commit 0bb2dff34771e4b2ed1da7bf630c15e00dc6342e Author: Blake Bourque Date: Thu Jun 18 22:15:24 2015 -0400 Initial commit I wish I could figure out how to have PlexVie be out of the LibOMV tree but its just not working die to a DLL not found exception about libopenjpeg. (Yes the dll is in the bin folder) This will do for now diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..78b5428 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +compile.bat +*.csproj +*.user +*.userprefs +*.sln +*.suo +*.cache + +[Oo]bj/ +[Bb]in/ + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..89d19ca --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,24 @@ + + Copyright (c) 2006-2014, openmetaverse.org + All rights reserved. + + - Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + - Neither the name of the openmetaverse.org nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/OpenMetaverse.StructuredData/JSON/IJsonWrapper.cs b/OpenMetaverse.StructuredData/JSON/IJsonWrapper.cs new file mode 100644 index 0000000..c56d42a --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/IJsonWrapper.cs @@ -0,0 +1,60 @@ +#region Header +/* + * IJsonWrapper.cs + * Interface that represents a type capable of handling all kinds of JSON + * data. This is mainly used when mapping objects through JsonMapper, and + * it's implemented by JsonData. + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +using System.Collections; +using System.Collections.Specialized; + + +namespace LitJson +{ + public enum JsonType + { + None, + + Object, + Array, + String, + Int, + Long, + Double, + Boolean + } + + public interface IJsonWrapper : IList, IOrderedDictionary + { + bool IsArray { get; } + bool IsBoolean { get; } + bool IsDouble { get; } + bool IsInt { get; } + bool IsLong { get; } + bool IsObject { get; } + bool IsString { get; } + + bool GetBoolean (); + double GetDouble (); + int GetInt (); + JsonType GetJsonType (); + long GetLong (); + string GetString (); + + void SetBoolean (bool val); + void SetDouble (double val); + void SetInt (int val); + void SetJsonType (JsonType type); + void SetLong (long val); + void SetString (string val); + + string ToJson (); + void ToJson (JsonWriter writer); + } +} diff --git a/OpenMetaverse.StructuredData/JSON/JsonData.cs b/OpenMetaverse.StructuredData/JSON/JsonData.cs new file mode 100644 index 0000000..694d625 --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/JsonData.cs @@ -0,0 +1,993 @@ +#region Header +/* + * JsonData.cs + * Generic type to hold JSON data (objects, arrays, and so on). This is + * the default type returned by JsonMapper.ToObject(). + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; + + +namespace LitJson +{ + public class JsonData : IJsonWrapper, IEquatable + { + #region Fields + private IList inst_array; + private bool inst_boolean; + private double inst_double; + private int inst_int; + private long inst_long; + private IDictionary inst_object; + private string inst_string; + private string json; + private JsonType type; + + // Used to implement the IOrderedDictionary interface + private IList> object_list; + #endregion + + + #region Properties + public int Count { + get { return EnsureCollection ().Count; } + } + + public bool IsArray { + get { return type == JsonType.Array; } + } + + public bool IsBoolean { + get { return type == JsonType.Boolean; } + } + + public bool IsDouble { + get { return type == JsonType.Double; } + } + + public bool IsInt { + get { return type == JsonType.Int; } + } + + public bool IsLong { + get { return type == JsonType.Long; } + } + + public bool IsObject { + get { return type == JsonType.Object; } + } + + public bool IsString { + get { return type == JsonType.String; } + } + #endregion + + + #region ICollection Properties + int ICollection.Count { + get { + return Count; + } + } + + bool ICollection.IsSynchronized { + get { + return EnsureCollection ().IsSynchronized; + } + } + + object ICollection.SyncRoot { + get { + return EnsureCollection ().SyncRoot; + } + } + #endregion + + + #region IDictionary Properties + bool IDictionary.IsFixedSize { + get { + return EnsureDictionary ().IsFixedSize; + } + } + + bool IDictionary.IsReadOnly { + get { + return EnsureDictionary ().IsReadOnly; + } + } + + ICollection IDictionary.Keys { + get { + EnsureDictionary (); + IList keys = new List (); + + foreach (KeyValuePair entry in + object_list) { + keys.Add (entry.Key); + } + + return (ICollection) keys; + } + } + + ICollection IDictionary.Values { + get { + EnsureDictionary (); + IList values = new List (); + + foreach (KeyValuePair entry in + object_list) { + values.Add (entry.Value); + } + + return (ICollection) values; + } + } + #endregion + + + + #region IJsonWrapper Properties + bool IJsonWrapper.IsArray { + get { return IsArray; } + } + + bool IJsonWrapper.IsBoolean { + get { return IsBoolean; } + } + + bool IJsonWrapper.IsDouble { + get { return IsDouble; } + } + + bool IJsonWrapper.IsInt { + get { return IsInt; } + } + + bool IJsonWrapper.IsLong { + get { return IsLong; } + } + + bool IJsonWrapper.IsObject { + get { return IsObject; } + } + + bool IJsonWrapper.IsString { + get { return IsString; } + } + #endregion + + + #region IList Properties + bool IList.IsFixedSize { + get { + return EnsureList ().IsFixedSize; + } + } + + bool IList.IsReadOnly { + get { + return EnsureList ().IsReadOnly; + } + } + #endregion + + + #region IDictionary Indexer + object IDictionary.this[object key] { + get { + return EnsureDictionary ()[key]; + } + + set { + if (! (key is String)) + throw new ArgumentException ( + "The key has to be a string"); + + JsonData data = ToJsonData (value); + + this[(string) key] = data; + } + } + #endregion + + + #region IOrderedDictionary Indexer + object IOrderedDictionary.this[int idx] { + get { + EnsureDictionary (); + return object_list[idx].Value; + } + + set { + EnsureDictionary (); + JsonData data = ToJsonData (value); + + KeyValuePair old_entry = object_list[idx]; + + inst_object[old_entry.Key] = data; + + KeyValuePair entry = + new KeyValuePair (old_entry.Key, data); + + object_list[idx] = entry; + } + } + #endregion + + + #region IList Indexer + object IList.this[int index] { + get { + return EnsureList ()[index]; + } + + set { + EnsureList (); + JsonData data = ToJsonData (value); + + this[index] = data; + } + } + #endregion + + + #region Public Indexers + public JsonData this[string prop_name] { + get { + EnsureDictionary (); + return inst_object[prop_name]; + } + + set { + EnsureDictionary (); + + KeyValuePair entry = + new KeyValuePair (prop_name, value); + + if (inst_object.ContainsKey (prop_name)) { + for (int i = 0; i < object_list.Count; i++) { + if (object_list[i].Key == prop_name) { + object_list[i] = entry; + break; + } + } + } else + object_list.Add (entry); + + inst_object[prop_name] = value; + + json = null; + } + } + + public JsonData this[int index] { + get { + EnsureCollection (); + + if (type == JsonType.Array) + return inst_array[index]; + + return object_list[index].Value; + } + + set { + EnsureCollection (); + + if (type == JsonType.Array) + inst_array[index] = value; + else { + KeyValuePair entry = object_list[index]; + KeyValuePair new_entry = + new KeyValuePair (entry.Key, value); + + object_list[index] = new_entry; + inst_object[entry.Key] = value; + } + + json = null; + } + } + #endregion + + + #region Constructors + public JsonData () + { + } + + public JsonData (bool boolean) + { + type = JsonType.Boolean; + inst_boolean = boolean; + } + + public JsonData (double number) + { + type = JsonType.Double; + inst_double = number; + } + + public JsonData (int number) + { + type = JsonType.Int; + inst_int = number; + } + + public JsonData (long number) + { + type = JsonType.Long; + inst_long = number; + } + + public JsonData (object obj) + { + if (obj is Boolean) { + type = JsonType.Boolean; + inst_boolean = (bool) obj; + return; + } + + if (obj is Double) { + type = JsonType.Double; + inst_double = (double) obj; + return; + } + + if (obj is Int32) { + type = JsonType.Int; + inst_int = (int) obj; + return; + } + + if (obj is Int64) { + type = JsonType.Long; + inst_long = (long) obj; + return; + } + + if (obj is String) { + type = JsonType.String; + inst_string = (string) obj; + return; + } + + throw new ArgumentException ( + "Unable to wrap the given object with JsonData"); + } + + public JsonData (string str) + { + type = JsonType.String; + inst_string = str; + } + #endregion + + + #region Implicit Conversions + public static implicit operator JsonData (Boolean data) + { + return new JsonData (data); + } + + public static implicit operator JsonData (Double data) + { + return new JsonData (data); + } + + public static implicit operator JsonData (Int32 data) + { + return new JsonData (data); + } + + public static implicit operator JsonData (Int64 data) + { + return new JsonData (data); + } + + public static implicit operator JsonData (String data) + { + return new JsonData (data); + } + #endregion + + + #region Explicit Conversions + public static explicit operator Boolean (JsonData data) + { + if (data.type != JsonType.Boolean) + throw new InvalidCastException ( + "Instance of JsonData doesn't hold a double"); + + return data.inst_boolean; + } + + public static explicit operator Double (JsonData data) + { + if (data.type != JsonType.Double) + throw new InvalidCastException ( + "Instance of JsonData doesn't hold a double"); + + return data.inst_double; + } + + public static explicit operator Int32 (JsonData data) + { + if (data.type != JsonType.Int) + throw new InvalidCastException ( + "Instance of JsonData doesn't hold an int"); + + return data.inst_int; + } + + public static explicit operator Int64 (JsonData data) + { + if (data.type != JsonType.Long) + throw new InvalidCastException ( + "Instance of JsonData doesn't hold an int"); + + return data.inst_long; + } + + public static explicit operator String (JsonData data) + { + if (data.type != JsonType.String) + throw new InvalidCastException ( + "Instance of JsonData doesn't hold a string"); + + return data.inst_string; + } + #endregion + + + #region ICollection Methods + void ICollection.CopyTo (Array array, int index) + { + EnsureCollection ().CopyTo (array, index); + } + #endregion + + + #region IDictionary Methods + void IDictionary.Add (object key, object value) + { + JsonData data = ToJsonData (value); + + EnsureDictionary ().Add (key, data); + + KeyValuePair entry = + new KeyValuePair ((string) key, data); + object_list.Add (entry); + + json = null; + } + + void IDictionary.Clear () + { + EnsureDictionary ().Clear (); + object_list.Clear (); + json = null; + } + + bool IDictionary.Contains (object key) + { + return EnsureDictionary ().Contains (key); + } + + IDictionaryEnumerator IDictionary.GetEnumerator () + { + return ((IOrderedDictionary) this).GetEnumerator (); + } + + void IDictionary.Remove (object key) + { + EnsureDictionary ().Remove (key); + + for (int i = 0; i < object_list.Count; i++) { + if (object_list[i].Key == (string) key) { + object_list.RemoveAt (i); + break; + } + } + + json = null; + } + #endregion + + + #region IEnumerable Methods + IEnumerator IEnumerable.GetEnumerator () + { + return EnsureCollection ().GetEnumerator (); + } + #endregion + + + #region IJsonWrapper Methods + bool IJsonWrapper.GetBoolean () + { + if (type != JsonType.Boolean) + throw new InvalidOperationException ( + "JsonData instance doesn't hold a boolean"); + + return inst_boolean; + } + + double IJsonWrapper.GetDouble () + { + if (type != JsonType.Double) + throw new InvalidOperationException ( + "JsonData instance doesn't hold a double"); + + return inst_double; + } + + int IJsonWrapper.GetInt () + { + if (type != JsonType.Int) + throw new InvalidOperationException ( + "JsonData instance doesn't hold an int"); + + return inst_int; + } + + long IJsonWrapper.GetLong () + { + if (type != JsonType.Long) + throw new InvalidOperationException ( + "JsonData instance doesn't hold a long"); + + return inst_long; + } + + string IJsonWrapper.GetString () + { + if (type != JsonType.String) + throw new InvalidOperationException ( + "JsonData instance doesn't hold a string"); + + return inst_string; + } + + void IJsonWrapper.SetBoolean (bool val) + { + type = JsonType.Boolean; + inst_boolean = val; + json = null; + } + + void IJsonWrapper.SetDouble (double val) + { + type = JsonType.Double; + inst_double = val; + json = null; + } + + void IJsonWrapper.SetInt (int val) + { + type = JsonType.Int; + inst_int = val; + json = null; + } + + void IJsonWrapper.SetLong (long val) + { + type = JsonType.Long; + inst_long = val; + json = null; + } + + void IJsonWrapper.SetString (string val) + { + type = JsonType.String; + inst_string = val; + json = null; + } + + string IJsonWrapper.ToJson () + { + return ToJson (); + } + + void IJsonWrapper.ToJson (JsonWriter writer) + { + ToJson (writer); + } + #endregion + + + #region IList Methods + int IList.Add (object value) + { + return Add (value); + } + + void IList.Clear () + { + EnsureList ().Clear (); + json = null; + } + + bool IList.Contains (object value) + { + return EnsureList ().Contains (value); + } + + int IList.IndexOf (object value) + { + return EnsureList ().IndexOf (value); + } + + void IList.Insert (int index, object value) + { + EnsureList ().Insert (index, value); + json = null; + } + + void IList.Remove (object value) + { + EnsureList ().Remove (value); + json = null; + } + + void IList.RemoveAt (int index) + { + EnsureList ().RemoveAt (index); + json = null; + } + #endregion + + + #region IOrderedDictionary Methods + IDictionaryEnumerator IOrderedDictionary.GetEnumerator () + { + EnsureDictionary (); + + return new OrderedDictionaryEnumerator ( + object_list.GetEnumerator ()); + } + + void IOrderedDictionary.Insert (int idx, object key, object value) + { + string property = (string) key; + JsonData data = ToJsonData (value); + + this[property] = data; + + KeyValuePair entry = + new KeyValuePair (property, data); + + object_list.Insert (idx, entry); + } + + void IOrderedDictionary.RemoveAt (int idx) + { + EnsureDictionary (); + + inst_object.Remove (object_list[idx].Key); + object_list.RemoveAt (idx); + } + #endregion + + + #region Private Methods + private ICollection EnsureCollection () + { + if (type == JsonType.Array) + return (ICollection) inst_array; + + if (type == JsonType.Object) + return (ICollection) inst_object; + + throw new InvalidOperationException ( + "The JsonData instance has to be initialized first"); + } + + private IDictionary EnsureDictionary () + { + if (type == JsonType.Object) + return (IDictionary) inst_object; + + if (type != JsonType.None) + throw new InvalidOperationException ( + "Instance of JsonData is not a dictionary"); + + type = JsonType.Object; + inst_object = new Dictionary (); + object_list = new List> (); + + return (IDictionary) inst_object; + } + + private IList EnsureList () + { + if (type == JsonType.Array) + return (IList) inst_array; + + if (type != JsonType.None) + throw new InvalidOperationException ( + "Instance of JsonData is not a list"); + + type = JsonType.Array; + inst_array = new List (); + + return (IList) inst_array; + } + + private JsonData ToJsonData (object obj) + { + if (obj == null) + return null; + + if (obj is JsonData) + return (JsonData) obj; + + return new JsonData (obj); + } + + private static void WriteJson (IJsonWrapper obj, JsonWriter writer) + { + if (obj.IsString) { + writer.Write (obj.GetString ()); + return; + } + + if (obj.IsBoolean) { + writer.Write (obj.GetBoolean ()); + return; + } + + if (obj.IsDouble) { + writer.Write (obj.GetDouble ()); + return; + } + + if (obj.IsInt) { + writer.Write (obj.GetInt ()); + return; + } + + if (obj.IsLong) { + writer.Write (obj.GetLong ()); + return; + } + + if (obj.IsArray) { + writer.WriteArrayStart (); + foreach (object elem in (IList) obj) + WriteJson ((JsonData) elem, writer); + writer.WriteArrayEnd (); + + return; + } + + if (obj.IsObject) { + writer.WriteObjectStart (); + + foreach (DictionaryEntry entry in ((IDictionary) obj)) { + writer.WritePropertyName ((string) entry.Key); + WriteJson ((JsonData) entry.Value, writer); + } + writer.WriteObjectEnd (); + + return; + } + } + #endregion + + + public int Add (object value) + { + JsonData data = ToJsonData (value); + + json = null; + + return EnsureList ().Add (data); + } + + public void Clear () + { + if (IsObject) { + ((IDictionary) this).Clear (); + return; + } + + if (IsArray) { + ((IList) this).Clear (); + return; + } + } + + public bool Equals (JsonData x) + { + if (x == null) + return false; + + if (x.type != this.type) + return false; + + switch (this.type) { + case JsonType.None: + return true; + + case JsonType.Object: + return this.inst_object.Equals (x.inst_object); + + case JsonType.Array: + return this.inst_array.Equals (x.inst_array); + + case JsonType.String: + return this.inst_string.Equals (x.inst_string); + + case JsonType.Int: + return this.inst_int.Equals (x.inst_int); + + case JsonType.Long: + return this.inst_long.Equals (x.inst_long); + + case JsonType.Double: + return this.inst_double.Equals (x.inst_double); + + case JsonType.Boolean: + return this.inst_boolean.Equals (x.inst_boolean); + } + + return false; + } + + public JsonType GetJsonType () + { + return type; + } + + public void SetJsonType (JsonType type) + { + if (this.type == type) + return; + + switch (type) { + case JsonType.None: + break; + + case JsonType.Object: + inst_object = new Dictionary (); + object_list = new List> (); + break; + + case JsonType.Array: + inst_array = new List (); + break; + + case JsonType.String: + inst_string = default (String); + break; + + case JsonType.Int: + inst_int = default (Int32); + break; + + case JsonType.Long: + inst_long = default (Int64); + break; + + case JsonType.Double: + inst_double = default (Double); + break; + + case JsonType.Boolean: + inst_boolean = default (Boolean); + break; + } + + this.type = type; + } + + public string ToJson () + { + if (json != null) + return json; + + StringWriter sw = new StringWriter (); + JsonWriter writer = new JsonWriter (sw); + writer.Validate = false; + + WriteJson (this, writer); + json = sw.ToString (); + + return json; + } + + public void ToJson (JsonWriter writer) + { + bool old_validate = writer.Validate; + + writer.Validate = false; + + WriteJson (this, writer); + + writer.Validate = old_validate; + } + + public override string ToString () + { + switch (type) { + case JsonType.Array: + return "JsonData array"; + + case JsonType.Boolean: + return inst_boolean.ToString (); + + case JsonType.Double: + return inst_double.ToString (); + + case JsonType.Int: + return inst_int.ToString (); + + case JsonType.Long: + return inst_long.ToString (); + + case JsonType.Object: + return "JsonData object"; + + case JsonType.String: + return inst_string; + } + + return "Uninitialized JsonData"; + } + } + + + internal class OrderedDictionaryEnumerator : IDictionaryEnumerator + { + IEnumerator> list_enumerator; + + + public object Current { + get { return Entry; } + } + + public DictionaryEntry Entry { + get { + KeyValuePair curr = list_enumerator.Current; + return new DictionaryEntry (curr.Key, curr.Value); + } + } + + public object Key { + get { return list_enumerator.Current.Key; } + } + + public object Value { + get { return list_enumerator.Current.Value; } + } + + + public OrderedDictionaryEnumerator ( + IEnumerator> enumerator) + { + list_enumerator = enumerator; + } + + + public bool MoveNext () + { + return list_enumerator.MoveNext (); + } + + public void Reset () + { + list_enumerator.Reset (); + } + } +} diff --git a/OpenMetaverse.StructuredData/JSON/JsonException.cs b/OpenMetaverse.StructuredData/JSON/JsonException.cs new file mode 100644 index 0000000..a356fd6 --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/JsonException.cs @@ -0,0 +1,60 @@ +#region Header +/* + * JsonException.cs + * Base class throwed by LitJSON when a parsing error occurs. + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +using System; + + +namespace LitJson +{ + public class JsonException : ApplicationException + { + public JsonException () : base () + { + } + + internal JsonException (ParserToken token) : + base (String.Format ( + "Invalid token '{0}' in input string", token)) + { + } + + internal JsonException (ParserToken token, + Exception inner_exception) : + base (String.Format ( + "Invalid token '{0}' in input string", token), + inner_exception) + { + } + + internal JsonException (int c) : + base (String.Format ( + "Invalid character '{0}' in input string", (char) c)) + { + } + + internal JsonException (int c, Exception inner_exception) : + base (String.Format ( + "Invalid character '{0}' in input string", (char) c), + inner_exception) + { + } + + + public JsonException (string message) : base (message) + { + } + + public JsonException (string message, Exception inner_exception) : + base (message, inner_exception) + { + } + } +} diff --git a/OpenMetaverse.StructuredData/JSON/JsonMapper.cs b/OpenMetaverse.StructuredData/JSON/JsonMapper.cs new file mode 100644 index 0000000..4b6bd08 --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/JsonMapper.cs @@ -0,0 +1,901 @@ +#region Header +/* + * JsonMapper.cs + * JSON to .Net object and object to JSON conversions. + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Reflection; + + +namespace LitJson +{ + internal struct PropertyMetadata + { + public MemberInfo Info; + public bool IsField; + public Type Type; + } + + + internal struct ArrayMetadata + { + private Type element_type; + private bool is_array; + private bool is_list; + + + public Type ElementType { + get { + if (element_type == null) + return typeof (JsonData); + + return element_type; + } + + set { element_type = value; } + } + + public bool IsArray { + get { return is_array; } + set { is_array = value; } + } + + public bool IsList { + get { return is_list; } + set { is_list = value; } + } + } + + + internal struct ObjectMetadata + { + private Type element_type; + private bool is_dictionary; + + private IDictionary properties; + + + public Type ElementType { + get { + if (element_type == null) + return typeof (JsonData); + + return element_type; + } + + set { element_type = value; } + } + + public bool IsDictionary { + get { return is_dictionary; } + set { is_dictionary = value; } + } + + public IDictionary Properties { + get { return properties; } + set { properties = value; } + } + } + + + internal delegate void ExporterFunc (object obj, JsonWriter writer); + public delegate void ExporterFunc (T obj, JsonWriter writer); + + internal delegate object ImporterFunc (object input); + public delegate TValue ImporterFunc (TJson input); + + public delegate IJsonWrapper WrapperFactory (); + + + public class JsonMapper + { + #region Fields + private static int max_nesting_depth; + + private static IFormatProvider datetime_format; + + private static IDictionary base_exporters_table; + private static IDictionary custom_exporters_table; + + private static IDictionary> base_importers_table; + private static IDictionary> custom_importers_table; + + private static IDictionary array_metadata; + private static readonly object array_metadata_lock = new Object (); + + private static IDictionary> conv_ops; + private static readonly object conv_ops_lock = new Object (); + + private static IDictionary object_metadata; + private static readonly object object_metadata_lock = new Object (); + + private static IDictionary> type_properties; + private static readonly object type_properties_lock = new Object (); + + private static JsonWriter static_writer; + private static readonly object static_writer_lock = new Object (); + #endregion + + + #region Constructors + static JsonMapper () + { + max_nesting_depth = 100; + + array_metadata = new Dictionary (); + conv_ops = new Dictionary> (); + object_metadata = new Dictionary (); + type_properties = new Dictionary> (); + + static_writer = new JsonWriter (); + + datetime_format = DateTimeFormatInfo.InvariantInfo; + + base_exporters_table = new Dictionary (); + custom_exporters_table = new Dictionary (); + + base_importers_table = new Dictionary> (); + custom_importers_table = new Dictionary> (); + + RegisterBaseExporters (); + RegisterBaseImporters (); + } + #endregion + + + #region Private Methods + private static void AddArrayMetadata (Type type) + { + if (array_metadata.ContainsKey (type)) + return; + + ArrayMetadata data = new ArrayMetadata (); + + data.IsArray = type.IsArray; + + if (type.GetInterface ("System.Collections.IList") != null) + data.IsList = true; + + foreach (PropertyInfo p_info in type.GetProperties ()) { + if (p_info.Name != "Item") + continue; + + ParameterInfo[] parameters = p_info.GetIndexParameters (); + + if (parameters.Length != 1) + continue; + + if (parameters[0].ParameterType == typeof (int)) + data.ElementType = p_info.PropertyType; + } + + lock (array_metadata_lock) { + try { + array_metadata.Add (type, data); + } catch (ArgumentException) { + return; + } + } + } + + private static void AddObjectMetadata (Type type) + { + if (object_metadata.ContainsKey (type)) + return; + + ObjectMetadata data = new ObjectMetadata (); + + if (type.GetInterface ("System.Collections.IDictionary") != null) + data.IsDictionary = true; + + data.Properties = new Dictionary (); + + foreach (PropertyInfo p_info in type.GetProperties ()) { + if (p_info.Name == "Item") { + ParameterInfo[] parameters = p_info.GetIndexParameters (); + + if (parameters.Length != 1) + continue; + + if (parameters[0].ParameterType == typeof (string)) + data.ElementType = p_info.PropertyType; + + continue; + } + + PropertyMetadata p_data = new PropertyMetadata (); + p_data.Info = p_info; + p_data.Type = p_info.PropertyType; + + data.Properties.Add (p_info.Name, p_data); + } + + foreach (FieldInfo f_info in type.GetFields ()) { + PropertyMetadata p_data = new PropertyMetadata (); + p_data.Info = f_info; + p_data.IsField = true; + p_data.Type = f_info.FieldType; + + data.Properties.Add (f_info.Name, p_data); + } + + lock (object_metadata_lock) { + try { + object_metadata.Add (type, data); + } catch (ArgumentException) { + return; + } + } + } + + private static void AddTypeProperties (Type type) + { + if (type_properties.ContainsKey (type)) + return; + + IList props = new List (); + + foreach (PropertyInfo p_info in type.GetProperties ()) { + if (p_info.Name == "Item") + continue; + + PropertyMetadata p_data = new PropertyMetadata (); + p_data.Info = p_info; + p_data.IsField = false; + props.Add (p_data); + } + + foreach (FieldInfo f_info in type.GetFields ()) { + PropertyMetadata p_data = new PropertyMetadata (); + p_data.Info = f_info; + p_data.IsField = true; + + props.Add (p_data); + } + + lock (type_properties_lock) { + try { + type_properties.Add (type, props); + } catch (ArgumentException) { + return; + } + } + } + + private static MethodInfo GetConvOp (Type t1, Type t2) + { + lock (conv_ops_lock) { + if (! conv_ops.ContainsKey (t1)) + conv_ops.Add (t1, new Dictionary ()); + } + + if (conv_ops[t1].ContainsKey (t2)) + return conv_ops[t1][t2]; + + MethodInfo op = t1.GetMethod ( + "op_Implicit", new Type[] { t2 }); + + lock (conv_ops_lock) { + try { + conv_ops[t1].Add (t2, op); + } catch (ArgumentException) { + return conv_ops[t1][t2]; + } + } + + return op; + } + + private static object ReadValue (Type inst_type, JsonReader reader) + { + reader.Read (); + + if (reader.Token == JsonToken.ArrayEnd) + return null; + + if (reader.Token == JsonToken.Null) { + + if (! inst_type.IsClass) + throw new JsonException (String.Format ( + "Can't assign null to an instance of type {0}", + inst_type)); + + return null; + } + + if (reader.Token == JsonToken.Double || + reader.Token == JsonToken.Int || + reader.Token == JsonToken.Long || + reader.Token == JsonToken.String || + reader.Token == JsonToken.Boolean) { + + Type json_type = reader.Value.GetType (); + + if (inst_type.IsAssignableFrom (json_type)) + return reader.Value; + + // If there's a custom importer that fits, use it + if (custom_importers_table.ContainsKey (json_type) && + custom_importers_table[json_type].ContainsKey ( + inst_type)) { + + ImporterFunc importer = + custom_importers_table[json_type][inst_type]; + + return importer (reader.Value); + } + + // Maybe there's a base importer that works + if (base_importers_table.ContainsKey (json_type) && + base_importers_table[json_type].ContainsKey ( + inst_type)) { + + ImporterFunc importer = + base_importers_table[json_type][inst_type]; + + return importer (reader.Value); + } + + // Maybe it's an enum + if (inst_type.IsEnum) + return Enum.ToObject (inst_type, reader.Value); + + // Try using an implicit conversion operator + MethodInfo conv_op = GetConvOp (inst_type, json_type); + + if (conv_op != null) + return conv_op.Invoke (null, + new object[] { reader.Value }); + + // No luck + throw new JsonException (String.Format ( + "Can't assign value '{0}' (type {1}) to type {2}", + reader.Value, json_type, inst_type)); + } + + object instance = null; + + if (reader.Token == JsonToken.ArrayStart) { + + AddArrayMetadata (inst_type); + ArrayMetadata t_data = array_metadata[inst_type]; + + if (! t_data.IsArray && ! t_data.IsList) + throw new JsonException (String.Format ( + "Type {0} can't act as an array", + inst_type)); + + IList list; + Type elem_type; + + if (! t_data.IsArray) { + list = (IList) Activator.CreateInstance (inst_type); + elem_type = t_data.ElementType; + } else { + list = new ArrayList (); + elem_type = inst_type.GetElementType (); + } + + while (true) { + object item = ReadValue (elem_type, reader); + if (reader.Token == JsonToken.ArrayEnd) + break; + + list.Add (item); + } + + if (t_data.IsArray) { + int n = list.Count; + instance = Array.CreateInstance (elem_type, n); + + for (int i = 0; i < n; i++) + ((Array) instance).SetValue (list[i], i); + } else + instance = list; + + } else if (reader.Token == JsonToken.ObjectStart) { + + AddObjectMetadata (inst_type); + ObjectMetadata t_data = object_metadata[inst_type]; + + instance = Activator.CreateInstance (inst_type); + + while (true) { + reader.Read (); + + if (reader.Token == JsonToken.ObjectEnd) + break; + + string property = (string) reader.Value; + + if (t_data.Properties.ContainsKey (property)) { + PropertyMetadata prop_data = + t_data.Properties[property]; + + if (prop_data.IsField) { + ((FieldInfo) prop_data.Info).SetValue ( + instance, ReadValue (prop_data.Type, reader)); + } else { + PropertyInfo p_info = + (PropertyInfo) prop_data.Info; + + if (p_info.CanWrite) + p_info.SetValue ( + instance, + ReadValue (prop_data.Type, reader), + null); + else + ReadValue (prop_data.Type, reader); + } + + } else { + if (! t_data.IsDictionary) + throw new JsonException (String.Format ( + "The type {0} doesn't have the " + + "property '{1}'", inst_type, property)); + + ((IDictionary) instance).Add ( + property, ReadValue ( + t_data.ElementType, reader)); + } + + } + + } + + return instance; + } + + private static IJsonWrapper ReadValue (WrapperFactory factory, + JsonReader reader) + { + reader.Read (); + + if (reader.Token == JsonToken.ArrayEnd || + reader.Token == JsonToken.Null) + return null; + + IJsonWrapper instance = factory (); + + switch (reader.Token) + { + case JsonToken.String: + instance.SetString ((string) reader.Value); + break; + case JsonToken.Double: + instance.SetDouble ((double) reader.Value); + break; + case JsonToken.Int: + instance.SetInt ((int) reader.Value); + break; + case JsonToken.Long: + instance.SetLong ((long) reader.Value); + break; + case JsonToken.Boolean: + instance.SetBoolean ((bool) reader.Value); + break; + case JsonToken.ArrayStart: + instance.SetJsonType (JsonType.Array); + + while (true) { + IJsonWrapper item = ReadValue (factory, reader); + if (item == null && reader.Token == JsonToken.ArrayEnd) + break; + + ((IList) instance).Add (item); + } + break; + case JsonToken.ObjectStart: + instance.SetJsonType (JsonType.Object); + + while (true) { + reader.Read (); + if (reader.Token == JsonToken.ObjectEnd) + break; + + string property = (string) reader.Value; + ((IDictionary) instance)[property] = ReadValue ( + factory, reader); + } + break; + } + + return instance; + } + + private static void RegisterBaseExporters () + { + base_exporters_table[typeof (byte)] = + delegate (object obj, JsonWriter writer) { + writer.Write (Convert.ToInt32 ((byte) obj)); + }; + + base_exporters_table[typeof (char)] = + delegate (object obj, JsonWriter writer) { + writer.Write (Convert.ToString ((char) obj)); + }; + + base_exporters_table[typeof (DateTime)] = + delegate (object obj, JsonWriter writer) { + writer.Write (Convert.ToString ((DateTime) obj, + datetime_format)); + }; + + base_exporters_table[typeof (decimal)] = + delegate (object obj, JsonWriter writer) { + writer.Write ((decimal) obj); + }; + + base_exporters_table[typeof (sbyte)] = + delegate (object obj, JsonWriter writer) { + writer.Write (Convert.ToInt32 ((sbyte) obj)); + }; + + base_exporters_table[typeof (short)] = + delegate (object obj, JsonWriter writer) { + writer.Write (Convert.ToInt32 ((short) obj)); + }; + + base_exporters_table[typeof (ushort)] = + delegate (object obj, JsonWriter writer) { + writer.Write (Convert.ToInt32 ((ushort) obj)); + }; + + base_exporters_table[typeof (uint)] = + delegate (object obj, JsonWriter writer) { + writer.Write (Convert.ToUInt64 ((uint) obj)); + }; + + base_exporters_table[typeof (ulong)] = + delegate (object obj, JsonWriter writer) { + writer.Write ((ulong) obj); + }; + } + + private static void RegisterBaseImporters () + { + ImporterFunc importer; + + importer = delegate (object input) { + return Convert.ToByte ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (byte), importer); + + importer = delegate (object input) { + return Convert.ToUInt64 ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (ulong), importer); + + importer = delegate (object input) { + return Convert.ToSByte ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (sbyte), importer); + + importer = delegate (object input) { + return Convert.ToInt16 ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (short), importer); + + importer = delegate (object input) { + return Convert.ToUInt16 ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (ushort), importer); + + importer = delegate (object input) { + return Convert.ToUInt32 ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (uint), importer); + + importer = delegate (object input) { + return Convert.ToSingle ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (float), importer); + + importer = delegate (object input) { + return Convert.ToDouble ((int) input); + }; + RegisterImporter (base_importers_table, typeof (int), + typeof (double), importer); + + importer = delegate (object input) { + return Convert.ToDecimal ((double) input); + }; + RegisterImporter (base_importers_table, typeof (double), + typeof (decimal), importer); + + + importer = delegate (object input) { + return Convert.ToUInt32 ((long) input); + }; + RegisterImporter (base_importers_table, typeof (long), + typeof (uint), importer); + + importer = delegate (object input) { + return Convert.ToChar ((string) input); + }; + RegisterImporter (base_importers_table, typeof (string), + typeof (char), importer); + + importer = delegate (object input) { + return Convert.ToDateTime ((string) input, datetime_format); + }; + RegisterImporter (base_importers_table, typeof (string), + typeof (DateTime), importer); + } + + private static void RegisterImporter ( + IDictionary> table, + Type json_type, Type value_type, ImporterFunc importer) + { + if (! table.ContainsKey (json_type)) + table.Add (json_type, new Dictionary ()); + + table[json_type][value_type] = importer; + } + + private static void WriteValue (object obj, JsonWriter writer, + bool writer_is_private, + int depth) + { + if (depth > max_nesting_depth) + throw new JsonException ( + String.Format ("Max allowed object depth reached while " + + "trying to export from type {0}", + obj.GetType ())); + + if (obj == null) { + writer.Write (null); + return; + } + + if (obj is IJsonWrapper) { + if (writer_is_private) + writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ()); + else + ((IJsonWrapper) obj).ToJson (writer); + + return; + } + + if (obj is String) { + writer.Write ((string) obj); + return; + } + + if (obj is Double) { + writer.Write ((double) obj); + return; + } + + if (obj is Int32) { + writer.Write ((int) obj); + return; + } + + if (obj is Boolean) { + writer.Write ((bool) obj); + return; + } + + if (obj is Int64) { + writer.Write ((long) obj); + return; + } + + if (obj is Array) { + writer.WriteArrayStart (); + + foreach (object elem in (Array) obj) + WriteValue (elem, writer, writer_is_private, depth + 1); + + writer.WriteArrayEnd (); + + return; + } + + if (obj is IList) { + writer.WriteArrayStart (); + foreach (object elem in (IList) obj) + WriteValue (elem, writer, writer_is_private, depth + 1); + writer.WriteArrayEnd (); + + return; + } + + if (obj is IDictionary) { + writer.WriteObjectStart (); + foreach (DictionaryEntry entry in (IDictionary) obj) { + writer.WritePropertyName ((string) entry.Key); + WriteValue (entry.Value, writer, writer_is_private, + depth + 1); + } + writer.WriteObjectEnd (); + + return; + } + + Type obj_type = obj.GetType (); + + // See if there's a custom exporter for the object + if (custom_exporters_table.ContainsKey (obj_type)) { + ExporterFunc exporter = custom_exporters_table[obj_type]; + exporter (obj, writer); + + return; + } + + // If not, maybe there's a base exporter + if (base_exporters_table.ContainsKey (obj_type)) { + ExporterFunc exporter = base_exporters_table[obj_type]; + exporter (obj, writer); + + return; + } + + // Last option, let's see if it's an enum + if (obj is Enum) { + Type e_type = Enum.GetUnderlyingType (obj_type); + + if (e_type == typeof (long) + || e_type == typeof (uint) + || e_type == typeof (ulong)) + writer.Write ((ulong) obj); + else + writer.Write ((int) obj); + + return; + } + + // Okay, so it looks like the input should be exported as an + // object + AddTypeProperties (obj_type); + IList props = type_properties[obj_type]; + + writer.WriteObjectStart (); + foreach (PropertyMetadata p_data in props) { + if (p_data.IsField) { + writer.WritePropertyName (p_data.Info.Name); + WriteValue (((FieldInfo) p_data.Info).GetValue (obj), + writer, writer_is_private, depth + 1); + } + else { + PropertyInfo p_info = (PropertyInfo) p_data.Info; + + if (p_info.CanRead) { + writer.WritePropertyName (p_data.Info.Name); + WriteValue (p_info.GetValue (obj, null), + writer, writer_is_private, depth + 1); + } + } + } + writer.WriteObjectEnd (); + } + #endregion + + + public static string ToJson (object obj) + { + lock (static_writer_lock) { + static_writer.Reset (); + + WriteValue (obj, static_writer, true, 0); + + return static_writer.ToString (); + } + } + + public static void ToJson (object obj, JsonWriter writer) + { + WriteValue (obj, writer, false, 0); + } + + public static JsonData ToObject (JsonReader reader) + { + return (JsonData) ToWrapper ( + delegate { return new JsonData (); }, reader); + } + + public static JsonData ToObject (TextReader reader) + { + JsonReader json_reader = new JsonReader (reader); + + return (JsonData) ToWrapper ( + delegate { return new JsonData (); }, json_reader); + } + + public static JsonData ToObject (string json) + { + return (JsonData) ToWrapper ( + delegate { return new JsonData (); }, json); + } + + public static T ToObject (JsonReader reader) + { + return (T) ReadValue (typeof (T), reader); + } + + public static T ToObject (TextReader reader) + { + JsonReader json_reader = new JsonReader (reader); + + return (T) ReadValue (typeof (T), json_reader); + } + + public static T ToObject (string json) + { + JsonReader reader = new JsonReader (json); + + return (T) ReadValue (typeof (T), reader); + } + + public static IJsonWrapper ToWrapper (WrapperFactory factory, + JsonReader reader) + { + return ReadValue (factory, reader); + } + + public static IJsonWrapper ToWrapper (WrapperFactory factory, + string json) + { + JsonReader reader = new JsonReader (json); + + return ReadValue (factory, reader); + } + + public static void RegisterExporter (ExporterFunc exporter) + { + ExporterFunc exporter_wrapper = + delegate (object obj, JsonWriter writer) { + exporter ((T) obj, writer); + }; + + custom_exporters_table[typeof (T)] = exporter_wrapper; + } + + public static void RegisterImporter ( + ImporterFunc importer) + { + ImporterFunc importer_wrapper = + delegate (object input) { + return importer ((TJson) input); + }; + + RegisterImporter (custom_importers_table, typeof (TJson), + typeof (TValue), importer_wrapper); + } + + public static void UnregisterExporters () + { + custom_exporters_table.Clear (); + } + + public static void UnregisterImporters () + { + custom_importers_table.Clear (); + } + } +} diff --git a/OpenMetaverse.StructuredData/JSON/JsonReader.cs b/OpenMetaverse.StructuredData/JSON/JsonReader.cs new file mode 100644 index 0000000..a7c3d3a --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/JsonReader.cs @@ -0,0 +1,455 @@ +#region Header +/* + * JsonReader.cs + * Stream-like access to JSON text. + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + + +namespace LitJson +{ + public enum JsonToken + { + None, + + ObjectStart, + PropertyName, + ObjectEnd, + + ArrayStart, + ArrayEnd, + + Int, + Long, + Double, + + String, + + Boolean, + Null + } + + + public class JsonReader + { + #region Fields + private static IDictionary> parse_table; + + private Stack automaton_stack; + private int current_input; + private int current_symbol; + private bool end_of_json; + private bool end_of_input; + private Lexer lexer; + private bool parser_in_string; + private bool parser_return; + private bool read_started; + private TextReader reader; + private bool reader_is_owned; + private object token_value; + private JsonToken token; + #endregion + + + #region Public Properties + public bool AllowComments { + get { return lexer.AllowComments; } + set { lexer.AllowComments = value; } + } + + public bool AllowSingleQuotedStrings { + get { return lexer.AllowSingleQuotedStrings; } + set { lexer.AllowSingleQuotedStrings = value; } + } + + public bool EndOfInput { + get { return end_of_input; } + } + + public bool EndOfJson { + get { return end_of_json; } + } + + public JsonToken Token { + get { return token; } + } + + public object Value { + get { return token_value; } + } + #endregion + + + #region Constructors + static JsonReader () + { + PopulateParseTable (); + } + + public JsonReader (string json_text) : + this (new StringReader (json_text), true) + { + } + + public JsonReader (TextReader reader) : + this (reader, false) + { + } + + private JsonReader (TextReader reader, bool owned) + { + if (reader == null) + throw new ArgumentNullException ("reader"); + + parser_in_string = false; + parser_return = false; + + read_started = false; + automaton_stack = new Stack (); + automaton_stack.Push ((int) ParserToken.End); + automaton_stack.Push ((int) ParserToken.Text); + + lexer = new Lexer (reader); + + end_of_input = false; + end_of_json = false; + + this.reader = reader; + reader_is_owned = owned; + } + #endregion + + + #region Static Methods + private static void PopulateParseTable () + { + parse_table = new Dictionary> (); + + TableAddRow (ParserToken.Array); + TableAddCol (ParserToken.Array, '[', + '[', + (int) ParserToken.ArrayPrime); + + TableAddRow (ParserToken.ArrayPrime); + TableAddCol (ParserToken.ArrayPrime, '"', + (int) ParserToken.Value, + + (int) ParserToken.ValueRest, + ']'); + TableAddCol (ParserToken.ArrayPrime, '[', + (int) ParserToken.Value, + (int) ParserToken.ValueRest, + ']'); + TableAddCol (ParserToken.ArrayPrime, ']', + ']'); + TableAddCol (ParserToken.ArrayPrime, '{', + (int) ParserToken.Value, + (int) ParserToken.ValueRest, + ']'); + TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number, + (int) ParserToken.Value, + (int) ParserToken.ValueRest, + ']'); + TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True, + (int) ParserToken.Value, + (int) ParserToken.ValueRest, + ']'); + TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False, + (int) ParserToken.Value, + (int) ParserToken.ValueRest, + ']'); + TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null, + (int) ParserToken.Value, + (int) ParserToken.ValueRest, + ']'); + + TableAddRow (ParserToken.Object); + TableAddCol (ParserToken.Object, '{', + '{', + (int) ParserToken.ObjectPrime); + + TableAddRow (ParserToken.ObjectPrime); + TableAddCol (ParserToken.ObjectPrime, '"', + (int) ParserToken.Pair, + (int) ParserToken.PairRest, + '}'); + TableAddCol (ParserToken.ObjectPrime, '}', + '}'); + + TableAddRow (ParserToken.Pair); + TableAddCol (ParserToken.Pair, '"', + (int) ParserToken.String, + ':', + (int) ParserToken.Value); + + TableAddRow (ParserToken.PairRest); + TableAddCol (ParserToken.PairRest, ',', + ',', + (int) ParserToken.Pair, + (int) ParserToken.PairRest); + TableAddCol (ParserToken.PairRest, '}', + (int) ParserToken.Epsilon); + + TableAddRow (ParserToken.String); + TableAddCol (ParserToken.String, '"', + '"', + (int) ParserToken.CharSeq, + '"'); + + TableAddRow (ParserToken.Text); + TableAddCol (ParserToken.Text, '[', + (int) ParserToken.Array); + TableAddCol (ParserToken.Text, '{', + (int) ParserToken.Object); + + TableAddRow (ParserToken.Value); + TableAddCol (ParserToken.Value, '"', + (int) ParserToken.String); + TableAddCol (ParserToken.Value, '[', + (int) ParserToken.Array); + TableAddCol (ParserToken.Value, '{', + (int) ParserToken.Object); + TableAddCol (ParserToken.Value, (int) ParserToken.Number, + (int) ParserToken.Number); + TableAddCol (ParserToken.Value, (int) ParserToken.True, + (int) ParserToken.True); + TableAddCol (ParserToken.Value, (int) ParserToken.False, + (int) ParserToken.False); + TableAddCol (ParserToken.Value, (int) ParserToken.Null, + (int) ParserToken.Null); + + TableAddRow (ParserToken.ValueRest); + TableAddCol (ParserToken.ValueRest, ',', + ',', + (int) ParserToken.Value, + (int) ParserToken.ValueRest); + TableAddCol (ParserToken.ValueRest, ']', + (int) ParserToken.Epsilon); + } + + private static void TableAddCol (ParserToken row, int col, + params int[] symbols) + { + parse_table[(int) row].Add (col, symbols); + } + + private static void TableAddRow (ParserToken rule) + { + parse_table.Add ((int) rule, new Dictionary ()); + } + #endregion + + + #region Private Methods + private void ProcessNumber (string number) + { + if (number.IndexOf ('.') != -1 || + number.IndexOf ('e') != -1 || + number.IndexOf ('E') != -1) { + + double n_double; + if (Double.TryParse (number, out n_double)) { + token = JsonToken.Double; + token_value = n_double; + + return; + } + } + + int n_int32; + if (Int32.TryParse (number, out n_int32)) { + token = JsonToken.Int; + token_value = n_int32; + + return; + } + + long n_int64; + if (Int64.TryParse (number, out n_int64)) { + token = JsonToken.Long; + token_value = n_int64; + + return; + } + + // Shouldn't happen, but just in case, return something + token = JsonToken.Int; + token_value = 0; + } + + private void ProcessSymbol () + { + if (current_symbol == '[') { + token = JsonToken.ArrayStart; + parser_return = true; + + } else if (current_symbol == ']') { + token = JsonToken.ArrayEnd; + parser_return = true; + + } else if (current_symbol == '{') { + token = JsonToken.ObjectStart; + parser_return = true; + + } else if (current_symbol == '}') { + token = JsonToken.ObjectEnd; + parser_return = true; + + } else if (current_symbol == '"') { + if (parser_in_string) { + parser_in_string = false; + + parser_return = true; + + } else { + if (token == JsonToken.None) + token = JsonToken.String; + + parser_in_string = true; + } + + } else if (current_symbol == (int) ParserToken.CharSeq) { + token_value = lexer.StringValue; + + } else if (current_symbol == (int) ParserToken.False) { + token = JsonToken.Boolean; + token_value = false; + parser_return = true; + + } else if (current_symbol == (int) ParserToken.Null) { + token = JsonToken.Null; + parser_return = true; + + } else if (current_symbol == (int) ParserToken.Number) { + ProcessNumber (lexer.StringValue); + + parser_return = true; + + } else if (current_symbol == (int) ParserToken.Pair) { + token = JsonToken.PropertyName; + + } else if (current_symbol == (int) ParserToken.True) { + token = JsonToken.Boolean; + token_value = true; + parser_return = true; + + } + } + + private bool ReadToken () + { + if (end_of_input) + return false; + + lexer.NextToken (); + + if (lexer.EndOfInput) { + Close (); + + return false; + } + + current_input = lexer.Token; + + return true; + } + #endregion + + + public void Close () + { + if (end_of_input) + return; + + end_of_input = true; + end_of_json = true; + + if (reader_is_owned) + reader.Close (); + + reader = null; + } + + public bool Read () + { + if (end_of_input) + return false; + + if (end_of_json) { + end_of_json = false; + automaton_stack.Clear (); + automaton_stack.Push ((int) ParserToken.End); + automaton_stack.Push ((int) ParserToken.Text); + } + + parser_in_string = false; + parser_return = false; + + token = JsonToken.None; + token_value = null; + + if (! read_started) { + read_started = true; + + if (! ReadToken ()) + return false; + } + + + int[] entry_symbols; + + while (true) { + if (parser_return) { + if (automaton_stack.Peek () == (int) ParserToken.End) + end_of_json = true; + + return true; + } + + current_symbol = automaton_stack.Pop (); + + ProcessSymbol (); + + if (current_symbol == current_input) { + if (! ReadToken ()) { + if (automaton_stack.Peek () != (int) ParserToken.End) + throw new JsonException ( + "Input doesn't evaluate to proper JSON text"); + + if (parser_return) + return true; + + return false; + } + + continue; + } + + try { + + entry_symbols = + parse_table[current_symbol][current_input]; + + } catch (KeyNotFoundException e) { + throw new JsonException ((ParserToken) current_input, e); + } + + if (entry_symbols[0] == (int) ParserToken.Epsilon) + continue; + + for (int i = entry_symbols.Length - 1; i >= 0; i--) + automaton_stack.Push (entry_symbols[i]); + } + } + + } +} diff --git a/OpenMetaverse.StructuredData/JSON/JsonWriter.cs b/OpenMetaverse.StructuredData/JSON/JsonWriter.cs new file mode 100644 index 0000000..9dcc59d --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/JsonWriter.cs @@ -0,0 +1,466 @@ +#region Header +/* + * JsonWriter.cs + * Stream-like facility to output JSON text. + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + + +namespace LitJson +{ + internal enum Condition + { + InArray, + InObject, + NotAProperty, + Property, + Value + } + + internal class WriterContext + { + public int Count; + public bool InArray; + public bool InObject; + public bool ExpectingValue; + public int Padding; + } + + public class JsonWriter + { + #region Fields + private static NumberFormatInfo number_format; + + private WriterContext context; + private Stack ctx_stack; + private bool has_reached_end; + private char[] hex_seq; + private int indentation; + private int indent_value; + private StringBuilder inst_string_builder; + private bool pretty_print; + private bool validate; + private TextWriter writer; + #endregion + + + #region Properties + public int IndentValue { + get { return indent_value; } + set { + indentation = (indentation / indent_value) * value; + indent_value = value; + } + } + + public bool PrettyPrint { + get { return pretty_print; } + set { pretty_print = value; } + } + + public TextWriter TextWriter { + get { return writer; } + } + + public bool Validate { + get { return validate; } + set { validate = value; } + } + #endregion + + + #region Constructors + static JsonWriter () + { + number_format = NumberFormatInfo.InvariantInfo; + } + + public JsonWriter () + { + inst_string_builder = new StringBuilder (); + writer = new StringWriter (inst_string_builder); + + Init (); + } + + public JsonWriter (StringBuilder sb) : + this (new StringWriter (sb)) + { + } + + public JsonWriter (TextWriter writer) + { + if (writer == null) + throw new ArgumentNullException ("writer"); + + this.writer = writer; + + Init (); + } + #endregion + + + #region Private Methods + private void DoValidation (Condition cond) + { + if (! context.ExpectingValue) + context.Count++; + + if (! validate) + return; + + if (has_reached_end) + throw new JsonException ( + "A complete JSON symbol has already been written"); + + switch (cond) { + case Condition.InArray: + if (! context.InArray) + throw new JsonException ( + "Can't close an array here"); + break; + + case Condition.InObject: + if (! context.InObject || context.ExpectingValue) + throw new JsonException ( + "Can't close an object here"); + break; + + case Condition.NotAProperty: + if (context.InObject && ! context.ExpectingValue) + throw new JsonException ( + "Expected a property"); + break; + + case Condition.Property: + if (! context.InObject || context.ExpectingValue) + throw new JsonException ( + "Can't add a property here"); + break; + + case Condition.Value: + if (! context.InArray && + (! context.InObject || ! context.ExpectingValue)) + throw new JsonException ( + "Can't add a value here"); + + break; + } + } + + private void Init () + { + has_reached_end = false; + hex_seq = new char[4]; + indentation = 0; + indent_value = 4; + pretty_print = false; + validate = true; + + ctx_stack = new Stack (); + context = new WriterContext (); + ctx_stack.Push (context); + } + + private static void IntToHex (int n, char[] hex) + { + int num; + + for (int i = 0; i < 4; i++) { + num = n % 16; + + if (num < 10) + hex[3 - i] = (char) ('0' + num); + else + hex[3 - i] = (char) ('A' + (num - 10)); + + n >>= 4; + } + } + + private void Indent () + { + if (pretty_print) + indentation += indent_value; + } + + + private void Put (string str) + { + if (pretty_print && ! context.ExpectingValue) + for (int i = 0; i < indentation; i++) + writer.Write (' '); + + writer.Write (str); + } + + private void PutNewline () + { + PutNewline (true); + } + + private void PutNewline (bool add_comma) + { + if (add_comma && ! context.ExpectingValue && + context.Count > 1) + writer.Write (','); + + if (pretty_print && ! context.ExpectingValue) + writer.Write ('\n'); + } + + private void PutString (string str) + { + Put (String.Empty); + + writer.Write ('"'); + + int n = str.Length; + for (int i = 0; i < n; i++) { + switch (str[i]) { + case '\n': + writer.Write ("\\n"); + continue; + + case '\r': + writer.Write ("\\r"); + continue; + + case '\t': + writer.Write ("\\t"); + continue; + + case '"': + case '\\': + writer.Write ('\\'); + writer.Write (str[i]); + continue; + + case '\f': + writer.Write ("\\f"); + continue; + + case '\b': + writer.Write ("\\b"); + continue; + } + + if ((int) str[i] >= 32 && (int) str[i] <= 126) { + writer.Write (str[i]); + continue; + } + + // Default, turn into a \uXXXX sequence + IntToHex ((int) str[i], hex_seq); + writer.Write ("\\u"); + writer.Write (hex_seq); + } + + writer.Write ('"'); + } + + private void Unindent () + { + if (pretty_print) + indentation -= indent_value; + } + #endregion + + + public override string ToString () + { + if (inst_string_builder == null) + return String.Empty; + + return inst_string_builder.ToString (); + } + + public void Reset () + { + has_reached_end = false; + + ctx_stack.Clear (); + context = new WriterContext (); + ctx_stack.Push (context); + + if (inst_string_builder != null) + inst_string_builder.Remove (0, inst_string_builder.Length); + } + + public void Write (bool boolean) + { + DoValidation (Condition.Value); + PutNewline (); + + Put (boolean ? "true" : "false"); + + context.ExpectingValue = false; + } + + public void Write (decimal number) + { + DoValidation (Condition.Value); + PutNewline (); + + Put (Convert.ToString (number, number_format)); + + context.ExpectingValue = false; + } + + public void Write (double number) + { + DoValidation (Condition.Value); + PutNewline (); + + if (double.IsNaN(number) || double.IsInfinity(number)) + Put("null"); + else + { + string str = Convert.ToString(number, number_format); + Put(str); + + if (str.IndexOf('.') == -1 && str.IndexOf('E') == -1) + writer.Write(".0"); + } + + context.ExpectingValue = false; + } + + public void Write (int number) + { + DoValidation (Condition.Value); + PutNewline (); + + Put (Convert.ToString (number, number_format)); + + context.ExpectingValue = false; + } + + public void Write (long number) + { + DoValidation (Condition.Value); + PutNewline (); + + Put (Convert.ToString (number, number_format)); + + context.ExpectingValue = false; + } + + public void Write (string str) + { + DoValidation (Condition.Value); + PutNewline (); + + if (str == null) + Put ("null"); + else + PutString (str); + + context.ExpectingValue = false; + } + + public void Write (ulong number) + { + DoValidation (Condition.Value); + PutNewline (); + + Put (Convert.ToString (number, number_format)); + + context.ExpectingValue = false; + } + + public void WriteArrayEnd () + { + DoValidation (Condition.InArray); + PutNewline (false); + + ctx_stack.Pop (); + if (ctx_stack.Count == 1) + has_reached_end = true; + else { + context = ctx_stack.Peek (); + context.ExpectingValue = false; + } + + Unindent (); + Put ("]"); + } + + public void WriteArrayStart () + { + DoValidation (Condition.NotAProperty); + PutNewline (); + + Put ("["); + + context = new WriterContext (); + context.InArray = true; + ctx_stack.Push (context); + + Indent (); + } + + public void WriteObjectEnd () + { + DoValidation (Condition.InObject); + PutNewline (false); + + ctx_stack.Pop (); + if (ctx_stack.Count == 1) + has_reached_end = true; + else { + context = ctx_stack.Peek (); + context.ExpectingValue = false; + } + + Unindent (); + Put ("}"); + } + + public void WriteObjectStart () + { + DoValidation (Condition.NotAProperty); + PutNewline (); + + Put ("{"); + + context = new WriterContext (); + context.InObject = true; + ctx_stack.Push (context); + + Indent (); + } + + public void WritePropertyName (string property_name) + { + DoValidation (Condition.Property); + PutNewline (); + + PutString (property_name); + + if (pretty_print) { + if (property_name.Length > context.Padding) + context.Padding = property_name.Length; + + for (int i = context.Padding - property_name.Length; + i >= 0; i--) + writer.Write (' '); + + writer.Write (": "); + } else + writer.Write (':'); + + context.ExpectingValue = true; + } + } +} diff --git a/OpenMetaverse.StructuredData/JSON/Lexer.cs b/OpenMetaverse.StructuredData/JSON/Lexer.cs new file mode 100644 index 0000000..66f0be0 --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/Lexer.cs @@ -0,0 +1,910 @@ +#region Header +/* + * Lexer.cs + * JSON lexer implementation based on a finite state machine. + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + + +namespace LitJson +{ + internal class FsmContext + { + public bool Return; + public int NextState; + public Lexer L; + public int StateStack; + } + + + internal class Lexer + { + #region Fields + private delegate bool StateHandler (FsmContext ctx); + + private static int[] fsm_return_table; + private static StateHandler[] fsm_handler_table; + + private bool allow_comments; + private bool allow_single_quoted_strings; + private bool end_of_input; + private FsmContext fsm_context; + private int input_buffer; + private int input_char; + private TextReader reader; + private int state; + private StringBuilder string_buffer; + private string string_value; + private int token; + private int unichar; + #endregion + + + #region Properties + public bool AllowComments { + get { return allow_comments; } + set { allow_comments = value; } + } + + public bool AllowSingleQuotedStrings { + get { return allow_single_quoted_strings; } + set { allow_single_quoted_strings = value; } + } + + public bool EndOfInput { + get { return end_of_input; } + } + + public int Token { + get { return token; } + } + + public string StringValue { + get { return string_value; } + } + #endregion + + + #region Constructors + static Lexer () + { + PopulateFsmTables (); + } + + public Lexer (TextReader reader) + { + allow_comments = true; + allow_single_quoted_strings = true; + + input_buffer = 0; + string_buffer = new StringBuilder (128); + state = 1; + end_of_input = false; + this.reader = reader; + + fsm_context = new FsmContext (); + fsm_context.L = this; + } + #endregion + + + #region Static Methods + private static int HexValue (int digit) + { + switch (digit) { + case 'a': + case 'A': + return 10; + + case 'b': + case 'B': + return 11; + + case 'c': + case 'C': + return 12; + + case 'd': + case 'D': + return 13; + + case 'e': + case 'E': + return 14; + + case 'f': + case 'F': + return 15; + + default: + return digit - '0'; + } + } + + private static void PopulateFsmTables () + { + fsm_handler_table = new StateHandler[28] { + State1, + State2, + State3, + State4, + State5, + State6, + State7, + State8, + State9, + State10, + State11, + State12, + State13, + State14, + State15, + State16, + State17, + State18, + State19, + State20, + State21, + State22, + State23, + State24, + State25, + State26, + State27, + State28 + }; + + fsm_return_table = new int[28] { + (int) ParserToken.Char, + 0, + (int) ParserToken.Number, + (int) ParserToken.Number, + 0, + (int) ParserToken.Number, + 0, + (int) ParserToken.Number, + 0, + 0, + (int) ParserToken.True, + 0, + 0, + 0, + (int) ParserToken.False, + 0, + 0, + (int) ParserToken.Null, + (int) ParserToken.CharSeq, + (int) ParserToken.Char, + 0, + 0, + (int) ParserToken.CharSeq, + (int) ParserToken.Char, + 0, + 0, + 0, + 0 + }; + } + + private static char ProcessEscChar (int esc_char) + { + switch (esc_char) { + case '"': + case '\'': + case '\\': + case '/': + return Convert.ToChar (esc_char); + + case 'n': + return '\n'; + + case 't': + return '\t'; + + case 'r': + return '\r'; + + case 'b': + return '\b'; + + case 'f': + return '\f'; + + default: + // Unreachable + return '?'; + } + } + + private static bool State1 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') + continue; + + if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') { + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 3; + return true; + } + + switch (ctx.L.input_char) { + case '"': + ctx.NextState = 19; + ctx.Return = true; + return true; + + case ',': + case ':': + case '[': + case ']': + case '{': + case '}': + ctx.NextState = 1; + ctx.Return = true; + return true; + + case '-': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 2; + return true; + + case '0': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 4; + return true; + + case 'f': + ctx.NextState = 12; + return true; + + case 'n': + ctx.NextState = 16; + return true; + + case 't': + ctx.NextState = 9; + return true; + + case '\'': + if (! ctx.L.allow_single_quoted_strings) + return false; + + ctx.L.input_char = '"'; + ctx.NextState = 23; + ctx.Return = true; + return true; + + case '/': + if (! ctx.L.allow_comments) + return false; + + ctx.NextState = 25; + return true; + + default: + return false; + } + } + + return true; + } + + private static bool State2 (FsmContext ctx) + { + ctx.L.GetChar (); + + if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') { + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 3; + return true; + } + + switch (ctx.L.input_char) { + case '0': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 4; + return true; + + default: + return false; + } + } + + private static bool State3 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') { + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + continue; + } + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) { + case ',': + case ']': + case '}': + ctx.L.UngetChar (); + ctx.Return = true; + ctx.NextState = 1; + return true; + + case '.': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 5; + return true; + + case 'e': + case 'E': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 7; + return true; + + default: + return false; + } + } + return true; + } + + private static bool State4 (FsmContext ctx) + { + ctx.L.GetChar (); + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) { + case ',': + case ']': + case '}': + ctx.L.UngetChar (); + ctx.Return = true; + ctx.NextState = 1; + return true; + + case '.': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 5; + return true; + + case 'e': + case 'E': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 7; + return true; + + default: + return false; + } + } + + private static bool State5 (FsmContext ctx) + { + ctx.L.GetChar (); + + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') { + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 6; + return true; + } + + return false; + } + + private static bool State6 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') { + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + continue; + } + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) { + case ',': + case ']': + case '}': + ctx.L.UngetChar (); + ctx.Return = true; + ctx.NextState = 1; + return true; + + case 'e': + case 'E': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 7; + return true; + + default: + return false; + } + } + + return true; + } + + private static bool State7 (FsmContext ctx) + { + ctx.L.GetChar (); + + if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') { + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 8; + return true; + } + + switch (ctx.L.input_char) { + case '+': + case '-': + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + ctx.NextState = 8; + return true; + + default: + return false; + } + } + + private static bool State8 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') { + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + continue; + } + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) { + case ',': + case ']': + case '}': + ctx.L.UngetChar (); + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + return true; + } + + private static bool State9 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'r': + ctx.NextState = 10; + return true; + + default: + return false; + } + } + + private static bool State10 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'u': + ctx.NextState = 11; + return true; + + default: + return false; + } + } + + private static bool State11 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'e': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State12 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'a': + ctx.NextState = 13; + return true; + + default: + return false; + } + } + + private static bool State13 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'l': + ctx.NextState = 14; + return true; + + default: + return false; + } + } + + private static bool State14 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 's': + ctx.NextState = 15; + return true; + + default: + return false; + } + } + + private static bool State15 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'e': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State16 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'u': + ctx.NextState = 17; + return true; + + default: + return false; + } + } + + private static bool State17 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'l': + ctx.NextState = 18; + return true; + + default: + return false; + } + } + + private static bool State18 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'l': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State19 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + switch (ctx.L.input_char) { + case '"': + ctx.L.UngetChar (); + ctx.Return = true; + ctx.NextState = 20; + return true; + + case '\\': + ctx.StateStack = 19; + ctx.NextState = 21; + return true; + + default: + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + continue; + } + } + + return true; + } + + private static bool State20 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case '"': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State21 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case 'u': + ctx.NextState = 22; + return true; + + case '"': + case '\'': + case '/': + case '\\': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + ctx.L.string_buffer.Append ( + ProcessEscChar (ctx.L.input_char)); + ctx.NextState = ctx.StateStack; + return true; + + default: + return false; + } + } + + private static bool State22 (FsmContext ctx) + { + int counter = 0; + int mult = 4096; + + ctx.L.unichar = 0; + + while (ctx.L.GetChar ()) { + + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' || + ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' || + ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') { + + ctx.L.unichar += HexValue (ctx.L.input_char) * mult; + + counter++; + mult /= 16; + + if (counter == 4) { + ctx.L.string_buffer.Append ( + Convert.ToChar (ctx.L.unichar)); + ctx.NextState = ctx.StateStack; + return true; + } + + continue; + } + + return false; + } + + return true; + } + + private static bool State23 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + switch (ctx.L.input_char) { + case '\'': + ctx.L.UngetChar (); + ctx.Return = true; + ctx.NextState = 24; + return true; + + case '\\': + ctx.StateStack = 23; + ctx.NextState = 21; + return true; + + default: + ctx.L.string_buffer.Append ((char) ctx.L.input_char); + continue; + } + } + + return true; + } + + private static bool State24 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case '\'': + ctx.L.input_char = '"'; + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State25 (FsmContext ctx) + { + ctx.L.GetChar (); + + switch (ctx.L.input_char) { + case '*': + ctx.NextState = 27; + return true; + + case '/': + ctx.NextState = 26; + return true; + + default: + return false; + } + } + + private static bool State26 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + if (ctx.L.input_char == '\n') { + ctx.NextState = 1; + return true; + } + } + + return true; + } + + private static bool State27 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + if (ctx.L.input_char == '*') { + ctx.NextState = 28; + return true; + } + } + + return true; + } + + private static bool State28 (FsmContext ctx) + { + while (ctx.L.GetChar ()) { + if (ctx.L.input_char == '*') + continue; + + if (ctx.L.input_char == '/') { + ctx.NextState = 1; + return true; + } + + ctx.NextState = 27; + return true; + } + + return true; + } + #endregion + + + private bool GetChar () + { + if ((input_char = NextChar ()) != -1) + return true; + + end_of_input = true; + return false; + } + + private int NextChar () + { + if (input_buffer != 0) { + int tmp = input_buffer; + input_buffer = 0; + + return tmp; + } + + return reader.Read (); + } + + public bool NextToken () + { + StateHandler handler; + fsm_context.Return = false; + + while (true) { + handler = fsm_handler_table[state - 1]; + + if (! handler (fsm_context)) + throw new JsonException (input_char); + + if (end_of_input) + return false; + + if (fsm_context.Return) { + string_value = string_buffer.ToString (); + string_buffer.Remove (0, string_buffer.Length); + token = fsm_return_table[state - 1]; + + if (token == (int) ParserToken.Char) + token = input_char; + + state = fsm_context.NextState; + + return true; + } + + state = fsm_context.NextState; + } + } + + private void UngetChar () + { + input_buffer = input_char; + } + } +} diff --git a/OpenMetaverse.StructuredData/JSON/OSDJson.cs b/OpenMetaverse.StructuredData/JSON/OSDJson.cs new file mode 100644 index 0000000..463a86d --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/OSDJson.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using LitJson; + +namespace OpenMetaverse.StructuredData +{ + public static partial class OSDParser + { + public static OSD DeserializeJson(Stream json) + { + using (StreamReader streamReader = new StreamReader(json)) + { + JsonReader reader = new JsonReader(streamReader); + return DeserializeJson(JsonMapper.ToObject(reader)); + } + } + + public static OSD DeserializeJson(string json) + { + return DeserializeJson(JsonMapper.ToObject(json)); + } + + public static OSD DeserializeJson(JsonData json) + { + if (json == null) return new OSD(); + + switch (json.GetJsonType()) + { + case JsonType.Boolean: + return OSD.FromBoolean((bool)json); + case JsonType.Int: + return OSD.FromInteger((int)json); + case JsonType.Long: + return OSD.FromLong((long)json); + case JsonType.Double: + return OSD.FromReal((double)json); + case JsonType.String: + string str = (string)json; + if (String.IsNullOrEmpty(str)) + return new OSD(); + else + return OSD.FromString(str); + case JsonType.Array: + OSDArray array = new OSDArray(json.Count); + for (int i = 0; i < json.Count; i++) + array.Add(DeserializeJson(json[i])); + return array; + case JsonType.Object: + OSDMap map = new OSDMap(json.Count); + IDictionaryEnumerator e = ((IOrderedDictionary)json).GetEnumerator(); + while (e.MoveNext()) + map.Add((string)e.Key, DeserializeJson((JsonData)e.Value)); + return map; + case JsonType.None: + default: + return new OSD(); + } + } + + public static string SerializeJsonString(OSD osd) + { + return SerializeJson(osd, false).ToJson(); + } + + public static string SerializeJsonString(OSD osd, bool preserveDefaults) + { + return SerializeJson(osd, preserveDefaults).ToJson(); + } + + public static void SerializeJsonString(OSD osd, bool preserveDefaults, ref JsonWriter writer) + { + SerializeJson(osd, preserveDefaults).ToJson(writer); + } + + public static JsonData SerializeJson(OSD osd, bool preserveDefaults) + { + switch (osd.Type) + { + case OSDType.Boolean: + return new JsonData(osd.AsBoolean()); + case OSDType.Integer: + return new JsonData(osd.AsInteger()); + case OSDType.Real: + return new JsonData(osd.AsReal()); + case OSDType.String: + case OSDType.Date: + case OSDType.URI: + case OSDType.UUID: + return new JsonData(osd.AsString()); + case OSDType.Binary: + byte[] binary = osd.AsBinary(); + JsonData jsonbinarray = new JsonData(); + jsonbinarray.SetJsonType(JsonType.Array); + for (int i = 0; i < binary.Length; i++) + jsonbinarray.Add(new JsonData(binary[i])); + return jsonbinarray; + case OSDType.Array: + JsonData jsonarray = new JsonData(); + jsonarray.SetJsonType(JsonType.Array); + OSDArray array = (OSDArray)osd; + for (int i = 0; i < array.Count; i++) + jsonarray.Add(SerializeJson(array[i], preserveDefaults)); + return jsonarray; + case OSDType.Map: + JsonData jsonmap = new JsonData(); + jsonmap.SetJsonType(JsonType.Object); + OSDMap map = (OSDMap)osd; + foreach (KeyValuePair kvp in map) + { + JsonData data; + + if (preserveDefaults) + data = SerializeJson(kvp.Value, preserveDefaults); + else + data = SerializeJsonNoDefaults(kvp.Value); + + if (data != null) + jsonmap[kvp.Key] = data; + } + return jsonmap; + case OSDType.Unknown: + default: + return new JsonData(null); + } + } + + private static JsonData SerializeJsonNoDefaults(OSD osd) + { + switch (osd.Type) + { + case OSDType.Boolean: + bool b = osd.AsBoolean(); + if (!b) + return null; + + return new JsonData(b); + case OSDType.Integer: + int v = osd.AsInteger(); + if (v == 0) + return null; + + return new JsonData(v); + case OSDType.Real: + double d = osd.AsReal(); + if (d == 0.0d) + return null; + + return new JsonData(d); + case OSDType.String: + case OSDType.Date: + case OSDType.URI: + string str = osd.AsString(); + if (String.IsNullOrEmpty(str)) + return null; + + return new JsonData(str); + case OSDType.UUID: + UUID uuid = osd.AsUUID(); + if (uuid == UUID.Zero) + return null; + + return new JsonData(uuid.ToString()); + case OSDType.Binary: + byte[] binary = osd.AsBinary(); + if (binary == Utils.EmptyBytes) + return null; + + JsonData jsonbinarray = new JsonData(); + jsonbinarray.SetJsonType(JsonType.Array); + for (int i = 0; i < binary.Length; i++) + jsonbinarray.Add(new JsonData(binary[i])); + return jsonbinarray; + case OSDType.Array: + JsonData jsonarray = new JsonData(); + jsonarray.SetJsonType(JsonType.Array); + OSDArray array = (OSDArray)osd; + for (int i = 0; i < array.Count; i++) + jsonarray.Add(SerializeJson(array[i], false)); + return jsonarray; + case OSDType.Map: + JsonData jsonmap = new JsonData(); + jsonmap.SetJsonType(JsonType.Object); + OSDMap map = (OSDMap)osd; + foreach (KeyValuePair kvp in map) + { + JsonData data = SerializeJsonNoDefaults(kvp.Value); + if (data != null) + jsonmap[kvp.Key] = data; + } + return jsonmap; + case OSDType.Unknown: + default: + return null; + } + } + } +} diff --git a/OpenMetaverse.StructuredData/JSON/ParserToken.cs b/OpenMetaverse.StructuredData/JSON/ParserToken.cs new file mode 100644 index 0000000..e19dcd7 --- /dev/null +++ b/OpenMetaverse.StructuredData/JSON/ParserToken.cs @@ -0,0 +1,44 @@ +#region Header +/* + * ParserToken.cs + * Internal representation of the tokens used by the lexer and the parser. + * + * The authors disclaim copyright to this source code. For more details, see + * the COPYING file included with this distribution. + */ +#endregion + + +namespace LitJson +{ + internal enum ParserToken + { + // Lexer tokens + None = System.Char.MaxValue + 1, + Number, + True, + False, + Null, + CharSeq, + // Single char + Char, + + // Parser Rules + Text, + Object, + ObjectPrime, + Pair, + PairRest, + Array, + ArrayPrime, + Value, + ValueRest, + String, + + // End of input + End, + + // The empty rule + Epsilon + } +} diff --git a/OpenMetaverse.StructuredData/LLSD/BinaryLLSD.cs b/OpenMetaverse.StructuredData/LLSD/BinaryLLSD.cs new file mode 100644 index 0000000..119f6f5 --- /dev/null +++ b/OpenMetaverse.StructuredData/LLSD/BinaryLLSD.cs @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * + * This implementation is based upon the description at + * + * http://wiki.secondlife.com/wiki/LLSD + * + * and (partially) tested against the (supposed) reference implementation at + * + * http://svn.secondlife.com/svn/linden/release/indra/lib/python/indra/base/osd.py + * + */ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.StructuredData +{ + /// + /// + /// + public static partial class OSDParser + { + private const int initialBufferSize = 128; + private const int int32Length = 4; + private const int doubleLength = 8; + + private const string llsdBinaryHead = ""; + private const string llsdBinaryHead2 = ""; + private const byte undefBinaryValue = (byte)'!'; + private const byte trueBinaryValue = (byte)'1'; + private const byte falseBinaryValue = (byte)'0'; + private const byte integerBinaryMarker = (byte)'i'; + private const byte realBinaryMarker = (byte)'r'; + private const byte uuidBinaryMarker = (byte)'u'; + private const byte binaryBinaryMarker = (byte)'b'; + private const byte stringBinaryMarker = (byte)'s'; + private const byte uriBinaryMarker = (byte)'l'; + private const byte dateBinaryMarker = (byte)'d'; + private const byte arrayBeginBinaryMarker = (byte)'['; + private const byte arrayEndBinaryMarker = (byte)']'; + private const byte mapBeginBinaryMarker = (byte)'{'; + private const byte mapEndBinaryMarker = (byte)'}'; + private const byte keyBinaryMarker = (byte)'k'; + + private static readonly byte[] llsdBinaryHeadBytes = Encoding.ASCII.GetBytes(llsdBinaryHead2); + + /// + /// Deserializes binary LLSD + /// + /// Serialized data + /// OSD containting deserialized data + public static OSD DeserializeLLSDBinary(byte[] binaryData) + { + + MemoryStream stream = new MemoryStream(binaryData); + OSD osd = DeserializeLLSDBinary(stream); + stream.Close(); + return osd; + } + + /// + /// Deserializes binary LLSD + /// + /// Stream to read the data from + /// OSD containting deserialized data + public static OSD DeserializeLLSDBinary(Stream stream) + { + if (!stream.CanSeek) + throw new OSDException("Cannot deserialize binary LLSD from unseekable streams"); + + SkipWhiteSpace(stream); + + if (!FindString(stream, llsdBinaryHead) && !FindString(stream, llsdBinaryHead2)) + { + //throw new OSDException("Failed to decode binary LLSD"); + } + + SkipWhiteSpace(stream); + + return ParseLLSDBinaryElement(stream); + } + + /// + /// Serializes OSD to binary format. It does no prepend header + /// + /// OSD to serialize + /// Serialized data + public static byte[] SerializeLLSDBinary(OSD osd) + { + return SerializeLLSDBinary(osd, true); + } + + /// + /// Serializes OSD to binary format + /// + /// OSD to serialize + /// + /// Serialized data + public static byte[] SerializeLLSDBinary(OSD osd, bool prependHeader) + { + MemoryStream stream = SerializeLLSDBinaryStream(osd, prependHeader); + byte[] binaryData = stream.ToArray(); + + stream.Close(); + + return binaryData; + } + + /// + /// Serializes OSD to binary format. It does no prepend header + /// + /// OSD to serialize + /// Serialized data + public static MemoryStream SerializeLLSDBinaryStream(OSD data) + { + return SerializeLLSDBinaryStream(data, true); + } + /// + /// Serializes OSD to binary format + /// + /// OSD to serialize + /// + /// Serialized data + public static MemoryStream SerializeLLSDBinaryStream(OSD data, bool prependHeader) + { + MemoryStream stream = new MemoryStream(initialBufferSize); + + if (prependHeader) + { + stream.Write(llsdBinaryHeadBytes, 0, llsdBinaryHeadBytes.Length); + stream.WriteByte((byte)'\n'); + } + SerializeLLSDBinaryElement(stream, data); + return stream; + } + + private static void SerializeLLSDBinaryElement(MemoryStream stream, OSD osd) + { + switch (osd.Type) + { + case OSDType.Unknown: + stream.WriteByte(undefBinaryValue); + break; + case OSDType.Boolean: + stream.Write(osd.AsBinary(), 0, 1); + break; + case OSDType.Integer: + stream.WriteByte(integerBinaryMarker); + stream.Write(osd.AsBinary(), 0, int32Length); + break; + case OSDType.Real: + stream.WriteByte(realBinaryMarker); + stream.Write(osd.AsBinary(), 0, doubleLength); + break; + case OSDType.UUID: + stream.WriteByte(uuidBinaryMarker); + stream.Write(osd.AsBinary(), 0, 16); + break; + case OSDType.String: + stream.WriteByte(stringBinaryMarker); + byte[] rawString = osd.AsBinary(); + byte[] stringLengthNetEnd = HostToNetworkIntBytes(rawString.Length); + stream.Write(stringLengthNetEnd, 0, int32Length); + stream.Write(rawString, 0, rawString.Length); + break; + case OSDType.Binary: + stream.WriteByte(binaryBinaryMarker); + byte[] rawBinary = osd.AsBinary(); + byte[] binaryLengthNetEnd = HostToNetworkIntBytes(rawBinary.Length); + stream.Write(binaryLengthNetEnd, 0, int32Length); + stream.Write(rawBinary, 0, rawBinary.Length); + break; + case OSDType.Date: + stream.WriteByte(dateBinaryMarker); + stream.Write(osd.AsBinary(), 0, doubleLength); + break; + case OSDType.URI: + stream.WriteByte(uriBinaryMarker); + byte[] rawURI = osd.AsBinary(); + byte[] uriLengthNetEnd = HostToNetworkIntBytes(rawURI.Length); + stream.Write(uriLengthNetEnd, 0, int32Length); + stream.Write(rawURI, 0, rawURI.Length); + break; + case OSDType.Array: + SerializeLLSDBinaryArray(stream, (OSDArray)osd); + break; + case OSDType.Map: + SerializeLLSDBinaryMap(stream, (OSDMap)osd); + break; + default: + throw new OSDException("Binary serialization: Not existing element discovered."); + + } + } + + private static void SerializeLLSDBinaryArray(MemoryStream stream, OSDArray osdArray) + { + stream.WriteByte(arrayBeginBinaryMarker); + byte[] binaryNumElementsHostEnd = HostToNetworkIntBytes(osdArray.Count); + stream.Write(binaryNumElementsHostEnd, 0, int32Length); + + foreach (OSD osd in osdArray) + { + SerializeLLSDBinaryElement(stream, osd); + } + stream.WriteByte(arrayEndBinaryMarker); + } + + private static void SerializeLLSDBinaryMap(MemoryStream stream, OSDMap osdMap) + { + stream.WriteByte(mapBeginBinaryMarker); + byte[] binaryNumElementsNetEnd = HostToNetworkIntBytes(osdMap.Count); + stream.Write(binaryNumElementsNetEnd, 0, int32Length); + + foreach (KeyValuePair kvp in osdMap) + { + stream.WriteByte(keyBinaryMarker); + byte[] binaryKey = Encoding.UTF8.GetBytes(kvp.Key); + byte[] binaryKeyLength = HostToNetworkIntBytes(binaryKey.Length); + stream.Write(binaryKeyLength, 0, int32Length); + stream.Write(binaryKey, 0, binaryKey.Length); + SerializeLLSDBinaryElement(stream, kvp.Value); + } + stream.WriteByte(mapEndBinaryMarker); + } + + private static OSD ParseLLSDBinaryElement(Stream stream) + { + SkipWhiteSpace(stream); + OSD osd; + + int marker = stream.ReadByte(); + if (marker < 0) + throw new OSDException("Binary LLSD parsing: Unexpected end of stream."); + + switch ((byte)marker) + { + case undefBinaryValue: + osd = new OSD(); + break; + case trueBinaryValue: + osd = OSD.FromBoolean(true); + break; + case falseBinaryValue: + osd = OSD.FromBoolean(false); + break; + case integerBinaryMarker: + int integer = NetworkToHostInt(ConsumeBytes(stream, int32Length)); + osd = OSD.FromInteger(integer); + break; + case realBinaryMarker: + double dbl = NetworkToHostDouble(ConsumeBytes(stream, doubleLength)); + osd = OSD.FromReal(dbl); + break; + case uuidBinaryMarker: + osd = OSD.FromUUID(new UUID(ConsumeBytes(stream, 16), 0)); + break; + case binaryBinaryMarker: + int binaryLength = NetworkToHostInt(ConsumeBytes(stream, int32Length)); + osd = OSD.FromBinary(ConsumeBytes(stream, binaryLength)); + break; + case stringBinaryMarker: + int stringLength = NetworkToHostInt(ConsumeBytes(stream, int32Length)); + string ss = Encoding.UTF8.GetString(ConsumeBytes(stream, stringLength)); + osd = OSD.FromString(ss); + break; + case uriBinaryMarker: + int uriLength = NetworkToHostInt(ConsumeBytes(stream, int32Length)); + string sUri = Encoding.UTF8.GetString(ConsumeBytes(stream, uriLength)); + Uri uri; + try + { + uri = new Uri(sUri, UriKind.RelativeOrAbsolute); + } + catch + { + throw new OSDException("Binary LLSD parsing: Invalid Uri format detected."); + } + osd = OSD.FromUri(uri); + break; + case dateBinaryMarker: + double timestamp = Utils.BytesToDouble(ConsumeBytes(stream, doubleLength), 0); + DateTime dateTime = DateTime.SpecifyKind(Utils.Epoch, DateTimeKind.Utc); + dateTime = dateTime.AddSeconds(timestamp); + osd = OSD.FromDate(dateTime.ToLocalTime()); + break; + case arrayBeginBinaryMarker: + osd = ParseLLSDBinaryArray(stream); + break; + case mapBeginBinaryMarker: + osd = ParseLLSDBinaryMap(stream); + break; + default: + throw new OSDException("Binary LLSD parsing: Unknown type marker."); + + } + return osd; + } + + private static OSD ParseLLSDBinaryArray(Stream stream) + { + int numElements = NetworkToHostInt(ConsumeBytes(stream, int32Length)); + int crrElement = 0; + OSDArray osdArray = new OSDArray(); + while (crrElement < numElements) + { + osdArray.Add(ParseLLSDBinaryElement(stream)); + crrElement++; + } + + if (!FindByte(stream, arrayEndBinaryMarker)) + throw new OSDException("Binary LLSD parsing: Missing end marker in array."); + + return (OSD)osdArray; + } + + private static OSD ParseLLSDBinaryMap(Stream stream) + { + int numElements = NetworkToHostInt(ConsumeBytes(stream, int32Length)); + int crrElement = 0; + OSDMap osdMap = new OSDMap(); + while (crrElement < numElements) + { + if (!FindByte(stream, keyBinaryMarker)) + throw new OSDException("Binary LLSD parsing: Missing key marker in map."); + int keyLength = NetworkToHostInt(ConsumeBytes(stream, int32Length)); + string key = Encoding.UTF8.GetString(ConsumeBytes(stream, keyLength)); + osdMap[key] = ParseLLSDBinaryElement(stream); + crrElement++; + } + + if (!FindByte(stream, mapEndBinaryMarker)) + throw new OSDException("Binary LLSD parsing: Missing end marker in map."); + + return (OSD)osdMap; + } + + /// + /// + /// + /// + public static void SkipWhiteSpace(Stream stream) + { + int bt; + + while (((bt = stream.ReadByte()) > 0) && + ((byte)bt == ' ' || (byte)bt == '\t' || + (byte)bt == '\n' || (byte)bt == '\r') + ) + { + } + stream.Seek(-1, SeekOrigin.Current); + } + + /// + /// + /// + /// + /// + /// + public static bool FindByte(Stream stream, byte toFind) + { + int bt = stream.ReadByte(); + if (bt < 0) + return false; + if ((byte)bt == toFind) + return true; + else + { + stream.Seek(-1L, SeekOrigin.Current); + return false; + } + } + + /// + /// + /// + /// + /// + /// + public static bool FindString(Stream stream, string toFind) + { + int lastIndexToFind = toFind.Length - 1; + int crrIndex = 0; + bool found = true; + int bt; + long lastPosition = stream.Position; + + while (found && + ((bt = stream.ReadByte()) > 0) && + (crrIndex <= lastIndexToFind) + ) + { + if (toFind[crrIndex].ToString().Equals(((char)bt).ToString(), StringComparison.InvariantCultureIgnoreCase)) + { + found = true; + crrIndex++; + } + else + found = false; + } + + if (found && crrIndex > lastIndexToFind) + { + stream.Seek(-1L, SeekOrigin.Current); + return true; + } + else + { + stream.Position = lastPosition; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public static byte[] ConsumeBytes(Stream stream, int consumeBytes) + { + byte[] bytes = new byte[consumeBytes]; + if (stream.Read(bytes, 0, consumeBytes) < consumeBytes) + throw new OSDException("Binary LLSD parsing: Unexpected end of stream."); + return bytes; + } + + /// + /// + /// + /// + /// + public static int NetworkToHostInt(byte[] binaryNetEnd) + { + if (binaryNetEnd == null) + return -1; + + int intNetEnd = BitConverter.ToInt32(binaryNetEnd, 0); + int intHostEnd = System.Net.IPAddress.NetworkToHostOrder(intNetEnd); + return intHostEnd; + } + + /// + /// + /// + /// + /// + public static double NetworkToHostDouble(byte[] binaryNetEnd) + { + if (binaryNetEnd == null) + return -1d; + long longNetEnd = BitConverter.ToInt64(binaryNetEnd, 0); + long longHostEnd = System.Net.IPAddress.NetworkToHostOrder(longNetEnd); + byte[] binaryHostEnd = BitConverter.GetBytes(longHostEnd); + double doubleHostEnd = BitConverter.ToDouble(binaryHostEnd, 0); + return doubleHostEnd; + + } + /// + /// + /// + /// + /// + public static byte[] HostToNetworkIntBytes(int intHostEnd) + { + int intNetEnd = System.Net.IPAddress.HostToNetworkOrder(intHostEnd); + byte[] bytesNetEnd = BitConverter.GetBytes(intNetEnd); + return bytesNetEnd; + + } + } +} \ No newline at end of file diff --git a/OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs b/OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs new file mode 100644 index 0000000..cb4a015 --- /dev/null +++ b/OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs @@ -0,0 +1,774 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace OpenMetaverse.StructuredData +{ + /// + /// + /// + public static partial class OSDParser + { + private const string baseIndent = " "; + + private const char undefNotationValue = '!'; + + private const char trueNotationValueOne = '1'; + private const char trueNotationValueTwo = 't'; + private static readonly char[] trueNotationValueTwoFull = { 't', 'r', 'u', 'e' }; + private const char trueNotationValueThree = 'T'; + private static readonly char[] trueNotationValueThreeFull = { 'T', 'R', 'U', 'E' }; + + private const char falseNotationValueOne = '0'; + private const char falseNotationValueTwo = 'f'; + private static readonly char[] falseNotationValueTwoFull = { 'f', 'a', 'l', 's', 'e' }; + private const char falseNotationValueThree = 'F'; + private static readonly char[] falseNotationValueThreeFull = { 'F', 'A', 'L', 'S', 'E' }; + + private const char integerNotationMarker = 'i'; + private const char realNotationMarker = 'r'; + private const char uuidNotationMarker = 'u'; + private const char binaryNotationMarker = 'b'; + private const char stringNotationMarker = 's'; + private const char uriNotationMarker = 'l'; + private const char dateNotationMarker = 'd'; + + private const char arrayBeginNotationMarker = '['; + private const char arrayEndNotationMarker = ']'; + + private const char mapBeginNotationMarker = '{'; + private const char mapEndNotationMarker = '}'; + private const char kommaNotationDelimiter = ','; + private const char keyNotationDelimiter = ':'; + + private const char sizeBeginNotationMarker = '('; + private const char sizeEndNotationMarker = ')'; + private const char doubleQuotesNotationMarker = '"'; + private const char singleQuotesNotationMarker = '\''; + + public static OSD DeserializeLLSDNotation(string notationData) + { + StringReader reader = new StringReader(notationData); + OSD osd = DeserializeLLSDNotation(reader); + reader.Close(); + return osd; + } + + public static OSD DeserializeLLSDNotation(StringReader reader) + { + OSD osd = DeserializeLLSDNotationElement(reader); + return osd; + } + + public static string SerializeLLSDNotation(OSD osd) + { + StringWriter writer = SerializeLLSDNotationStream(osd); + string s = writer.ToString(); + writer.Close(); + + return s; + } + + public static StringWriter SerializeLLSDNotationStream(OSD osd) + { + StringWriter writer = new StringWriter(); + + SerializeLLSDNotationElement(writer, osd); + return writer; + } + + public static string SerializeLLSDNotationFormatted(OSD osd) + { + StringWriter writer = SerializeLLSDNotationStreamFormatted(osd); + string s = writer.ToString(); + writer.Close(); + + return s; + } + + public static StringWriter SerializeLLSDNotationStreamFormatted(OSD osd) + { + StringWriter writer = new StringWriter(); + + string indent = String.Empty; + SerializeLLSDNotationElementFormatted(writer, indent, osd); + return writer; + } + + /// + /// + /// + /// + /// + private static OSD DeserializeLLSDNotationElement(StringReader reader) + { + int character = ReadAndSkipWhitespace(reader); + if (character < 0) + return new OSD(); // server returned an empty file, so we're going to pass along a null LLSD object + + OSD osd; + int matching; + switch ((char)character) + { + case undefNotationValue: + osd = new OSD(); + break; + case trueNotationValueOne: + osd = OSD.FromBoolean(true); + break; + case trueNotationValueTwo: + matching = BufferCharactersEqual(reader, trueNotationValueTwoFull, 1); + if (matching > 1 && matching < trueNotationValueTwoFull.Length) + throw new OSDException("Notation LLSD parsing: True value parsing error:"); + osd = OSD.FromBoolean(true); + break; + case trueNotationValueThree: + matching = BufferCharactersEqual(reader, trueNotationValueThreeFull, 1); + if (matching > 1 && matching < trueNotationValueThreeFull.Length) + throw new OSDException("Notation LLSD parsing: True value parsing error:"); + osd = OSD.FromBoolean(true); + break; + case falseNotationValueOne: + osd = OSD.FromBoolean(false); + break; + case falseNotationValueTwo: + matching = BufferCharactersEqual(reader, falseNotationValueTwoFull, 1); + if (matching > 1 && matching < falseNotationValueTwoFull.Length) + throw new OSDException("Notation LLSD parsing: True value parsing error:"); + osd = OSD.FromBoolean(false); + break; + case falseNotationValueThree: + matching = BufferCharactersEqual(reader, falseNotationValueThreeFull, 1); + if (matching > 1 && matching < falseNotationValueThreeFull.Length) + throw new OSDException("Notation LLSD parsing: True value parsing error:"); + osd = OSD.FromBoolean(false); + break; + case integerNotationMarker: + osd = DeserializeLLSDNotationInteger(reader); + break; + case realNotationMarker: + osd = DeserializeLLSDNotationReal(reader); + break; + case uuidNotationMarker: + char[] uuidBuf = new char[36]; + if (reader.Read(uuidBuf, 0, 36) < 36) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in UUID."); + UUID lluuid; + if (!UUID.TryParse(new String(uuidBuf), out lluuid)) + throw new OSDException("Notation LLSD parsing: Invalid UUID discovered."); + osd = OSD.FromUUID(lluuid); + break; + case binaryNotationMarker: + byte[] bytes = Utils.EmptyBytes; + int bChar = reader.Peek(); + if (bChar < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in binary."); + if ((char)bChar == sizeBeginNotationMarker) + { + throw new OSDException("Notation LLSD parsing: Raw binary encoding not supported."); + } + else if (Char.IsDigit((char)bChar)) + { + char[] charsBaseEncoding = new char[2]; + if (reader.Read(charsBaseEncoding, 0, 2) < 2) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in binary."); + int baseEncoding; + if (!Int32.TryParse(new String(charsBaseEncoding), out baseEncoding)) + throw new OSDException("Notation LLSD parsing: Invalid binary encoding base."); + if (baseEncoding == 64) + { + if (reader.Read() < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in binary."); + string bytes64 = GetStringDelimitedBy(reader, doubleQuotesNotationMarker); + bytes = Convert.FromBase64String(bytes64); + } + else + { + throw new OSDException("Notation LLSD parsing: Encoding base" + baseEncoding + " + not supported."); + } + } + osd = OSD.FromBinary(bytes); + break; + case stringNotationMarker: + int numChars = GetLengthInBrackets(reader); + if (reader.Read() < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string."); + char[] chars = new char[numChars]; + if (reader.Read(chars, 0, numChars) < numChars) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string."); + if (reader.Read() < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string."); + osd = OSD.FromString(new String(chars)); + break; + case singleQuotesNotationMarker: + string sOne = GetStringDelimitedBy(reader, singleQuotesNotationMarker); + osd = OSD.FromString(sOne); + break; + case doubleQuotesNotationMarker: + string sTwo = GetStringDelimitedBy(reader, doubleQuotesNotationMarker); + osd = OSD.FromString(sTwo); + break; + case uriNotationMarker: + if (reader.Read() < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in string."); + string sUri = GetStringDelimitedBy(reader, doubleQuotesNotationMarker); + + Uri uri; + try + { + uri = new Uri(sUri, UriKind.RelativeOrAbsolute); + } + catch + { + throw new OSDException("Notation LLSD parsing: Invalid Uri format detected."); + } + osd = OSD.FromUri(uri); + break; + case dateNotationMarker: + if (reader.Read() < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in date."); + string date = GetStringDelimitedBy(reader, doubleQuotesNotationMarker); + DateTime dt; + if (!DateTime.TryParse(date, out dt)) + throw new OSDException("Notation LLSD parsing: Invalid date discovered."); + osd = OSD.FromDate(dt); + break; + case arrayBeginNotationMarker: + osd = DeserializeLLSDNotationArray(reader); + break; + case mapBeginNotationMarker: + osd = DeserializeLLSDNotationMap(reader); + break; + default: + throw new OSDException("Notation LLSD parsing: Unknown type marker '" + (char)character + "'."); + } + return osd; + } + + private static OSD DeserializeLLSDNotationInteger(StringReader reader) + { + int character; + StringBuilder s = new StringBuilder(); + if (((character = reader.Peek()) > 0) && ((char)character == '-')) + { + s.Append((char)character); + reader.Read(); + } + + while ((character = reader.Peek()) > 0 && + Char.IsDigit((char)character)) + { + s.Append((char)character); + reader.Read(); + } + int integer; + if (!Int32.TryParse(s.ToString(), out integer)) + throw new OSDException("Notation LLSD parsing: Can't parse integer value." + s.ToString()); + + return OSD.FromInteger(integer); + } + + private static OSD DeserializeLLSDNotationReal(StringReader reader) + { + int character; + StringBuilder s = new StringBuilder(); + if (((character = reader.Peek()) > 0) && + ((char)character == '-' && (char)character == '+')) + { + s.Append((char)character); + reader.Read(); + } + while (((character = reader.Peek()) > 0) && + (Char.IsDigit((char)character) || (char)character == '.' || + (char)character == 'e' || (char)character == 'E' || + (char)character == '+' || (char)character == '-')) + { + s.Append((char)character); + reader.Read(); + } + double dbl; + if (!Utils.TryParseDouble(s.ToString(), out dbl)) + throw new OSDException("Notation LLSD parsing: Can't parse real value: " + s.ToString()); + + return OSD.FromReal(dbl); + } + + private static OSD DeserializeLLSDNotationArray(StringReader reader) + { + int character; + OSDArray osdArray = new OSDArray(); + while (((character = PeekAndSkipWhitespace(reader)) > 0) && + ((char)character != arrayEndNotationMarker)) + { + osdArray.Add(DeserializeLLSDNotationElement(reader)); + + character = ReadAndSkipWhitespace(reader); + if (character < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of array discovered."); + else if ((char)character == kommaNotationDelimiter) + continue; + else if ((char)character == arrayEndNotationMarker) + break; + } + if (character < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of array discovered."); + + return (OSD)osdArray; + } + + private static OSD DeserializeLLSDNotationMap(StringReader reader) + { + int character; + OSDMap osdMap = new OSDMap(); + while (((character = PeekAndSkipWhitespace(reader)) > 0) && + ((char)character != mapEndNotationMarker)) + { + OSD osdKey = DeserializeLLSDNotationElement(reader); + if (osdKey.Type != OSDType.String) + throw new OSDException("Notation LLSD parsing: Invalid key in map"); + string key = osdKey.AsString(); + + character = ReadAndSkipWhitespace(reader); + if ((char)character != keyNotationDelimiter) + throw new OSDException("Notation LLSD parsing: Unexpected end of stream in map."); + if ((char)character != keyNotationDelimiter) + throw new OSDException("Notation LLSD parsing: Invalid delimiter in map."); + + osdMap[key] = DeserializeLLSDNotationElement(reader); + character = ReadAndSkipWhitespace(reader); + if (character < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of map discovered."); + else if ((char)character == kommaNotationDelimiter) + continue; + else if ((char)character == mapEndNotationMarker) + break; + } + if (character < 0) + throw new OSDException("Notation LLSD parsing: Unexpected end of map discovered."); + + return (OSD)osdMap; + } + + private static void SerializeLLSDNotationElement(StringWriter writer, OSD osd) + { + + switch (osd.Type) + { + case OSDType.Unknown: + writer.Write(undefNotationValue); + break; + case OSDType.Boolean: + if (osd.AsBoolean()) + writer.Write(trueNotationValueTwo); + else + writer.Write(falseNotationValueTwo); + break; + case OSDType.Integer: + writer.Write(integerNotationMarker); + writer.Write(osd.AsString()); + break; + case OSDType.Real: + writer.Write(realNotationMarker); + writer.Write(osd.AsString()); + break; + case OSDType.UUID: + writer.Write(uuidNotationMarker); + writer.Write(osd.AsString()); + break; + case OSDType.String: + writer.Write(singleQuotesNotationMarker); + writer.Write(EscapeCharacter(osd.AsString(), singleQuotesNotationMarker)); + writer.Write(singleQuotesNotationMarker); + break; + case OSDType.Binary: + writer.Write(binaryNotationMarker); + writer.Write("64"); + writer.Write(doubleQuotesNotationMarker); + writer.Write(osd.AsString()); + writer.Write(doubleQuotesNotationMarker); + break; + case OSDType.Date: + writer.Write(dateNotationMarker); + writer.Write(doubleQuotesNotationMarker); + writer.Write(osd.AsString()); + writer.Write(doubleQuotesNotationMarker); + break; + case OSDType.URI: + writer.Write(uriNotationMarker); + writer.Write(doubleQuotesNotationMarker); + writer.Write(EscapeCharacter(osd.AsString(), doubleQuotesNotationMarker)); + writer.Write(doubleQuotesNotationMarker); + break; + case OSDType.Array: + SerializeLLSDNotationArray(writer, (OSDArray)osd); + break; + case OSDType.Map: + SerializeLLSDNotationMap(writer, (OSDMap)osd); + break; + default: + throw new OSDException("Notation serialization: Not existing element discovered."); + + } + } + + private static void SerializeLLSDNotationArray(StringWriter writer, OSDArray osdArray) + { + writer.Write(arrayBeginNotationMarker); + int lastIndex = osdArray.Count - 1; + + for (int idx = 0; idx <= lastIndex; idx++) + { + SerializeLLSDNotationElement(writer, osdArray[idx]); + if (idx < lastIndex) + writer.Write(kommaNotationDelimiter); + } + writer.Write(arrayEndNotationMarker); + } + + private static void SerializeLLSDNotationMap(StringWriter writer, OSDMap osdMap) + { + writer.Write(mapBeginNotationMarker); + int lastIndex = osdMap.Count - 1; + int idx = 0; + + foreach (KeyValuePair kvp in osdMap) + { + writer.Write(singleQuotesNotationMarker); + writer.Write(EscapeCharacter(kvp.Key, singleQuotesNotationMarker)); + writer.Write(singleQuotesNotationMarker); + writer.Write(keyNotationDelimiter); + SerializeLLSDNotationElement(writer, kvp.Value); + if (idx < lastIndex) + writer.Write(kommaNotationDelimiter); + + idx++; + } + writer.Write(mapEndNotationMarker); + } + + private static void SerializeLLSDNotationElementFormatted(StringWriter writer, string indent, OSD osd) + { + switch (osd.Type) + { + case OSDType.Unknown: + writer.Write(undefNotationValue); + break; + case OSDType.Boolean: + if (osd.AsBoolean()) + writer.Write(trueNotationValueTwo); + else + writer.Write(falseNotationValueTwo); + break; + case OSDType.Integer: + writer.Write(integerNotationMarker); + writer.Write(osd.AsString()); + break; + case OSDType.Real: + writer.Write(realNotationMarker); + writer.Write(osd.AsString()); + break; + case OSDType.UUID: + writer.Write(uuidNotationMarker); + writer.Write(osd.AsString()); + break; + case OSDType.String: + writer.Write(singleQuotesNotationMarker); + writer.Write(EscapeCharacter(osd.AsString(), singleQuotesNotationMarker)); + writer.Write(singleQuotesNotationMarker); + break; + case OSDType.Binary: + writer.Write(binaryNotationMarker); + writer.Write("64"); + writer.Write(doubleQuotesNotationMarker); + writer.Write(osd.AsString()); + writer.Write(doubleQuotesNotationMarker); + break; + case OSDType.Date: + writer.Write(dateNotationMarker); + writer.Write(doubleQuotesNotationMarker); + writer.Write(osd.AsString()); + writer.Write(doubleQuotesNotationMarker); + break; + case OSDType.URI: + writer.Write(uriNotationMarker); + writer.Write(doubleQuotesNotationMarker); + writer.Write(EscapeCharacter(osd.AsString(), doubleQuotesNotationMarker)); + writer.Write(doubleQuotesNotationMarker); + break; + case OSDType.Array: + SerializeLLSDNotationArrayFormatted(writer, indent + baseIndent, (OSDArray)osd); + break; + case OSDType.Map: + SerializeLLSDNotationMapFormatted(writer, indent + baseIndent, (OSDMap)osd); + break; + default: + throw new OSDException("Notation serialization: Not existing element discovered."); + + } + } + + private static void SerializeLLSDNotationArrayFormatted(StringWriter writer, string intend, OSDArray osdArray) + { + writer.WriteLine(); + writer.Write(intend); + writer.Write(arrayBeginNotationMarker); + int lastIndex = osdArray.Count - 1; + + for (int idx = 0; idx <= lastIndex; idx++) + { + if (osdArray[idx].Type != OSDType.Array && osdArray[idx].Type != OSDType.Map) + writer.WriteLine(); + writer.Write(intend + baseIndent); + SerializeLLSDNotationElementFormatted(writer, intend, osdArray[idx]); + if (idx < lastIndex) + { + writer.Write(kommaNotationDelimiter); + } + } + writer.WriteLine(); + writer.Write(intend); + writer.Write(arrayEndNotationMarker); + } + + private static void SerializeLLSDNotationMapFormatted(StringWriter writer, string intend, OSDMap osdMap) + { + writer.WriteLine(); + writer.Write(intend); + writer.WriteLine(mapBeginNotationMarker); + int lastIndex = osdMap.Count - 1; + int idx = 0; + + foreach (KeyValuePair kvp in osdMap) + { + writer.Write(intend + baseIndent); + writer.Write(singleQuotesNotationMarker); + writer.Write(EscapeCharacter(kvp.Key, singleQuotesNotationMarker)); + writer.Write(singleQuotesNotationMarker); + writer.Write(keyNotationDelimiter); + SerializeLLSDNotationElementFormatted(writer, intend, kvp.Value); + if (idx < lastIndex) + { + writer.WriteLine(); + writer.Write(intend + baseIndent); + writer.WriteLine(kommaNotationDelimiter); + } + + idx++; + } + writer.WriteLine(); + writer.Write(intend); + writer.Write(mapEndNotationMarker); + } + + /// + /// + /// + /// + /// + public static int PeekAndSkipWhitespace(StringReader reader) + { + int character; + while ((character = reader.Peek()) > 0) + { + char c = (char)character; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + { + reader.Read(); + continue; + } + else + break; + } + return character; + } + + /// + /// + /// + /// + /// + public static int ReadAndSkipWhitespace(StringReader reader) + { + int character = PeekAndSkipWhitespace(reader); + reader.Read(); + return character; + } + + /// + /// + /// + /// + /// + public static int GetLengthInBrackets(StringReader reader) + { + int character; + StringBuilder s = new StringBuilder(); + if (((character = PeekAndSkipWhitespace(reader)) > 0) && + ((char)character == sizeBeginNotationMarker)) + { + reader.Read(); + } + while (((character = reader.Read()) > 0) && + Char.IsDigit((char)character) && + ((char)character != sizeEndNotationMarker)) + { + s.Append((char)character); + } + if (character < 0) + throw new OSDException("Notation LLSD parsing: Can't parse length value cause unexpected end of stream."); + int length; + if (!Int32.TryParse(s.ToString(), out length)) + throw new OSDException("Notation LLSD parsing: Can't parse length value."); + + return length; + } + + /// + /// + /// + /// + /// + /// + public static string GetStringDelimitedBy(StringReader reader, char delimiter) + { + int character; + bool foundEscape = false; + StringBuilder s = new StringBuilder(); + while (((character = reader.Read()) > 0) && + (((char)character != delimiter) || + ((char)character == delimiter && foundEscape))) + { + + if (foundEscape) + { + foundEscape = false; + switch ((char)character) + { + case 'a': + s.Append('\a'); + break; + case 'b': + s.Append('\b'); + break; + case 'f': + s.Append('\f'); + break; + case 'n': + s.Append('\n'); + break; + case 'r': + s.Append('\r'); + break; + case 't': + s.Append('\t'); + break; + case 'v': + s.Append('\v'); + break; + default: + s.Append((char)character); + break; + } + } + else if ((char)character == '\\') + foundEscape = true; + else + s.Append((char)character); + + } + if (character < 0) + throw new OSDException("Notation LLSD parsing: Can't parse text because unexpected end of stream while expecting a '" + + delimiter + "' character."); + + return s.ToString(); + } + + /// + /// + /// + /// + /// + /// + /// + public static int BufferCharactersEqual(StringReader reader, char[] buffer, int offset) + { + + int character; + int lastIndex = buffer.Length - 1; + int crrIndex = offset; + bool charactersEqual = true; + + while ((character = reader.Peek()) > 0 && + crrIndex <= lastIndex && + charactersEqual) + { + if (((char)character) != buffer[crrIndex]) + { + charactersEqual = false; + break; + } + crrIndex++; + reader.Read(); + } + + return crrIndex; + } + + /// + /// + /// + /// + /// + /// + public static string UnescapeCharacter(String s, char c) + { + string oldOne = "\\" + c; + string newOne = new String(c, 1); + + String sOne = s.Replace("\\\\", "\\").Replace(oldOne, newOne); + return sOne; + } + + /// + /// + /// + /// + /// + /// + public static string EscapeCharacter(String s, char c) + { + string oldOne = new String(c, 1); + string newOne = "\\" + c; + + String sOne = s.Replace("\\", "\\\\").Replace(oldOne, newOne); + return sOne; + } + } +} diff --git a/OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs b/OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs new file mode 100644 index 0000000..8598c52 --- /dev/null +++ b/OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Xml.Schema; +using System.Text; + +namespace OpenMetaverse.StructuredData +{ + /// + /// + /// + public static partial class OSDParser + { + private static XmlSchema XmlSchema; + private static XmlTextReader XmlTextReader; + private static string LastXmlErrors = String.Empty; + private static object XmlValidationLock = new object(); + + /// + /// + /// + /// + /// + public static OSD DeserializeLLSDXml(byte[] xmlData) + { + return DeserializeLLSDXml(new XmlTextReader(new MemoryStream(xmlData, false))); + } + + public static OSD DeserializeLLSDXml(Stream xmlStream) + { + return DeserializeLLSDXml(new XmlTextReader(xmlStream)); + } + + /// + /// + /// + /// + /// + public static OSD DeserializeLLSDXml(string xmlData) + { + byte[] bytes = Utils.StringToBytes(xmlData); + return DeserializeLLSDXml(new XmlTextReader(new MemoryStream(bytes, false))); + } + + /// + /// + /// + /// + /// + public static OSD DeserializeLLSDXml(XmlTextReader xmlData) + { + try + { + xmlData.Read(); + SkipWhitespace(xmlData); + + xmlData.Read(); + OSD ret = ParseLLSDXmlElement(xmlData); + + return ret; + } + catch + { + return new OSD(); + } + } + + /// + /// + /// + /// + /// + public static byte[] SerializeLLSDXmlBytes(OSD data) + { + return Encoding.UTF8.GetBytes(SerializeLLSDXmlString(data)); + } + + /// + /// + /// + /// + /// + public static string SerializeLLSDXmlString(OSD data) + { + StringWriter sw = new StringWriter(); + XmlTextWriter writer = new XmlTextWriter(sw); + writer.Formatting = Formatting.None; + + writer.WriteStartElement(String.Empty, "llsd", String.Empty); + SerializeLLSDXmlElement(writer, data); + writer.WriteEndElement(); + + writer.Close(); + + return sw.ToString(); + } + + /// + /// + /// + /// + /// + public static void SerializeLLSDXmlElement(XmlTextWriter writer, OSD data) + { + switch (data.Type) + { + case OSDType.Unknown: + writer.WriteStartElement(String.Empty, "undef", String.Empty); + writer.WriteEndElement(); + break; + case OSDType.Boolean: + writer.WriteStartElement(String.Empty, "boolean", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.Integer: + writer.WriteStartElement(String.Empty, "integer", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.Real: + writer.WriteStartElement(String.Empty, "real", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.String: + writer.WriteStartElement(String.Empty, "string", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.UUID: + writer.WriteStartElement(String.Empty, "uuid", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.Date: + writer.WriteStartElement(String.Empty, "date", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.URI: + writer.WriteStartElement(String.Empty, "uri", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.Binary: + writer.WriteStartElement(String.Empty, "binary", String.Empty); + writer.WriteStartAttribute(String.Empty, "encoding", String.Empty); + writer.WriteString("base64"); + writer.WriteEndAttribute(); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case OSDType.Map: + OSDMap map = (OSDMap)data; + writer.WriteStartElement(String.Empty, "map", String.Empty); + foreach (KeyValuePair kvp in map) + { + writer.WriteStartElement(String.Empty, "key", String.Empty); + writer.WriteString(kvp.Key); + writer.WriteEndElement(); + + SerializeLLSDXmlElement(writer, kvp.Value); + } + writer.WriteEndElement(); + break; + case OSDType.Array: + OSDArray array = (OSDArray)data; + writer.WriteStartElement(String.Empty, "array", String.Empty); + for (int i = 0; i < array.Count; i++) + { + SerializeLLSDXmlElement(writer, array[i]); + } + writer.WriteEndElement(); + break; + } + } + + /// + /// + /// + /// + /// + /// + public static bool TryValidateLLSDXml(XmlTextReader xmlData, out string error) + { + lock (XmlValidationLock) + { + LastXmlErrors = String.Empty; + XmlTextReader = xmlData; + + CreateLLSDXmlSchema(); + + XmlReaderSettings readerSettings = new XmlReaderSettings(); + readerSettings.ValidationType = ValidationType.Schema; + readerSettings.Schemas.Add(XmlSchema); + readerSettings.ValidationEventHandler += new ValidationEventHandler(LLSDXmlSchemaValidationHandler); + + XmlReader reader = XmlReader.Create(xmlData, readerSettings); + + try + { + while (reader.Read()) { } + } + catch (XmlException) + { + error = LastXmlErrors; + return false; + } + + if (LastXmlErrors == String.Empty) + { + error = null; + return true; + } + else + { + error = LastXmlErrors; + return false; + } + } + } + + /// + /// + /// + /// + /// + private static OSD ParseLLSDXmlElement(XmlTextReader reader) + { + SkipWhitespace(reader); + + if (reader.NodeType != XmlNodeType.Element) + throw new OSDException("Expected an element"); + + string type = reader.LocalName; + OSD ret; + + switch (type) + { + case "undef": + if (reader.IsEmptyElement) + { + reader.Read(); + return new OSD(); + } + + reader.Read(); + SkipWhitespace(reader); + ret = new OSD(); + break; + case "boolean": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromBoolean(false); + } + + if (reader.Read()) + { + string s = reader.ReadString().Trim(); + + if (!String.IsNullOrEmpty(s) && (s == "true" || s == "1")) + { + ret = OSD.FromBoolean(true); + break; + } + } + + ret = OSD.FromBoolean(false); + break; + case "integer": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromInteger(0); + } + + if (reader.Read()) + { + int value = 0; + Int32.TryParse(reader.ReadString().Trim(), out value); + ret = OSD.FromInteger(value); + break; + } + + ret = OSD.FromInteger(0); + break; + case "real": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromReal(0d); + } + + if (reader.Read()) + { + double value = 0d; + string str = reader.ReadString().Trim().ToLower(); + + if (str == "nan") + value = Double.NaN; + else + Utils.TryParseDouble(str, out value); + + ret = OSD.FromReal(value); + break; + } + + ret = OSD.FromReal(0d); + break; + case "uuid": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromUUID(UUID.Zero); + } + + if (reader.Read()) + { + UUID value = UUID.Zero; + UUID.TryParse(reader.ReadString().Trim(), out value); + ret = OSD.FromUUID(value); + break; + } + + ret = OSD.FromUUID(UUID.Zero); + break; + case "date": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromDate(Utils.Epoch); + } + + if (reader.Read()) + { + DateTime value = Utils.Epoch; + DateTime.TryParse(reader.ReadString().Trim(), out value); + ret = OSD.FromDate(value); + break; + } + + ret = OSD.FromDate(Utils.Epoch); + break; + case "string": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromString(String.Empty); + } + + if (reader.Read()) + { + ret = OSD.FromString(reader.ReadString()); + break; + } + + ret = OSD.FromString(String.Empty); + break; + case "binary": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromBinary(Utils.EmptyBytes); + } + + if (reader.GetAttribute("encoding") != null && reader.GetAttribute("encoding") != "base64") + throw new OSDException("Unsupported binary encoding: " + reader.GetAttribute("encoding")); + + if (reader.Read()) + { + try + { + ret = OSD.FromBinary(Convert.FromBase64String(reader.ReadString().Trim())); + break; + } + catch (FormatException ex) + { + throw new OSDException("Binary decoding exception: " + ex.Message); + } + } + + ret = OSD.FromBinary(Utils.EmptyBytes); + break; + case "uri": + if (reader.IsEmptyElement) + { + reader.Read(); + return OSD.FromUri(new Uri(String.Empty, UriKind.RelativeOrAbsolute)); + } + + if (reader.Read()) + { + ret = OSD.FromUri(new Uri(reader.ReadString(), UriKind.RelativeOrAbsolute)); + break; + } + + ret = OSD.FromUri(new Uri(String.Empty, UriKind.RelativeOrAbsolute)); + break; + case "map": + return ParseLLSDXmlMap(reader); + case "array": + return ParseLLSDXmlArray(reader); + default: + reader.Read(); + ret = null; + break; + } + + if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != type) + { + throw new OSDException("Expected "); + } + else + { + reader.Read(); + return ret; + } + } + + private static OSDMap ParseLLSDXmlMap(XmlTextReader reader) + { + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "map") + throw new NotImplementedException("Expected "); + + OSDMap map = new OSDMap(); + + if (reader.IsEmptyElement) + { + reader.Read(); + return map; + } + + if (reader.Read()) + { + while (true) + { + SkipWhitespace(reader); + + if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "map") + { + reader.Read(); + break; + } + + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "key") + throw new OSDException("Expected "); + + string key = reader.ReadString(); + + if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "key") + throw new OSDException("Expected "); + + if (reader.Read()) + map[key] = ParseLLSDXmlElement(reader); + else + throw new OSDException("Failed to parse a value for key " + key); + } + } + + return map; + } + + private static OSDArray ParseLLSDXmlArray(XmlTextReader reader) + { + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "array") + throw new OSDException("Expected "); + + OSDArray array = new OSDArray(); + + if (reader.IsEmptyElement) + { + reader.Read(); + return array; + } + + if (reader.Read()) + { + while (true) + { + SkipWhitespace(reader); + + if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "array") + { + reader.Read(); + break; + } + + array.Add(ParseLLSDXmlElement(reader)); + } + } + + return array; + } + + private static void SkipWhitespace(XmlTextReader reader) + { + while ( + reader.NodeType == XmlNodeType.Comment || + reader.NodeType == XmlNodeType.Whitespace || + reader.NodeType == XmlNodeType.SignificantWhitespace || + reader.NodeType == XmlNodeType.XmlDeclaration) + { + reader.Read(); + } + } + + private static void CreateLLSDXmlSchema() + { + if (XmlSchema == null) + { + #region XSD + string schemaText = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + #endregion XSD + + MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(schemaText)); + + XmlSchema = new XmlSchema(); + XmlSchema = XmlSchema.Read(stream, new ValidationEventHandler(LLSDXmlSchemaValidationHandler)); + } + } + + private static void LLSDXmlSchemaValidationHandler(object sender, ValidationEventArgs args) + { + string error = String.Format("Line: {0} - Position: {1} - {2}", XmlTextReader.LineNumber, XmlTextReader.LinePosition, + args.Message); + + if (LastXmlErrors == String.Empty) + LastXmlErrors = error; + else + LastXmlErrors += Environment.NewLine + error; + } + } +} diff --git a/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.dll.build b/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.dll.build new file mode 100644 index 0000000..20e0c0e --- /dev/null +++ b/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.dll.build @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.mdp b/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.mdp new file mode 100644 index 0000000..3136b61 --- /dev/null +++ b/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.mdp @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverse.StructuredData/StructuredData.cs b/OpenMetaverse.StructuredData/StructuredData.cs new file mode 100644 index 0000000..4c8117b --- /dev/null +++ b/OpenMetaverse.StructuredData/StructuredData.cs @@ -0,0 +1,1283 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; + +namespace OpenMetaverse.StructuredData +{ + /// + /// + /// + public enum OSDType + { + /// + Unknown, + /// + Boolean, + /// + Integer, + /// + Real, + /// + String, + /// + UUID, + /// + Date, + /// + URI, + /// + Binary, + /// + Map, + /// + Array + } + + public enum OSDFormat + { + Xml = 0, + Json, + Binary + } + + /// + /// + /// + public class OSDException : Exception + { + public OSDException(string message) : base(message) { } + } + + /// + /// + /// + public partial class OSD + { + public virtual OSDType Type { get { return OSDType.Unknown; } } + + public virtual bool AsBoolean() { return false; } + public virtual int AsInteger() { return 0; } + public virtual uint AsUInteger() { return 0; } + public virtual long AsLong() { return 0; } + public virtual ulong AsULong() { return 0; } + public virtual double AsReal() { return 0d; } + public virtual string AsString() { return String.Empty; } + public virtual UUID AsUUID() { return UUID.Zero; } + public virtual DateTime AsDate() { return Utils.Epoch; } + public virtual Uri AsUri() { return null; } + public virtual byte[] AsBinary() { return Utils.EmptyBytes; } + public virtual Vector2 AsVector2() { return Vector2.Zero; } + public virtual Vector3 AsVector3() { return Vector3.Zero; } + public virtual Vector3d AsVector3d() { return Vector3d.Zero; } + public virtual Vector4 AsVector4() { return Vector4.Zero; } + public virtual Quaternion AsQuaternion() { return Quaternion.Identity; } + public virtual Color4 AsColor4() { return Color4.Black; } + public virtual OSD Copy() { return new OSD(); } + + public override string ToString() { return "undef"; } + + public static OSD FromBoolean(bool value) { return new OSDBoolean(value); } + public static OSD FromInteger(int value) { return new OSDInteger(value); } + public static OSD FromInteger(uint value) { return new OSDInteger((int)value); } + public static OSD FromInteger(short value) { return new OSDInteger((int)value); } + public static OSD FromInteger(ushort value) { return new OSDInteger((int)value); } + public static OSD FromInteger(sbyte value) { return new OSDInteger((int)value); } + public static OSD FromInteger(byte value) { return new OSDInteger((int)value); } + public static OSD FromUInteger(uint value) { return new OSDBinary(value); } + public static OSD FromLong(long value) { return new OSDBinary(value); } + public static OSD FromULong(ulong value) { return new OSDBinary(value); } + public static OSD FromReal(double value) { return new OSDReal(value); } + public static OSD FromReal(float value) { return new OSDReal((double)value); } + public static OSD FromString(string value) { return new OSDString(value); } + public static OSD FromUUID(UUID value) { return new OSDUUID(value); } + public static OSD FromDate(DateTime value) { return new OSDDate(value); } + public static OSD FromUri(Uri value) { return new OSDUri(value); } + public static OSD FromBinary(byte[] value) { return new OSDBinary(value); } + + public static OSD FromVector2(Vector2 value) + { + OSDArray array = new OSDArray(); + array.Add(OSD.FromReal(value.X)); + array.Add(OSD.FromReal(value.Y)); + return array; + } + + public static OSD FromVector3(Vector3 value) + { + OSDArray array = new OSDArray(); + array.Add(OSD.FromReal(value.X)); + array.Add(OSD.FromReal(value.Y)); + array.Add(OSD.FromReal(value.Z)); + return array; + } + + public static OSD FromVector3d(Vector3d value) + { + OSDArray array = new OSDArray(); + array.Add(OSD.FromReal(value.X)); + array.Add(OSD.FromReal(value.Y)); + array.Add(OSD.FromReal(value.Z)); + return array; + } + + public static OSD FromVector4(Vector4 value) + { + OSDArray array = new OSDArray(); + array.Add(OSD.FromReal(value.X)); + array.Add(OSD.FromReal(value.Y)); + array.Add(OSD.FromReal(value.Z)); + array.Add(OSD.FromReal(value.W)); + return array; + } + + public static OSD FromQuaternion(Quaternion value) + { + OSDArray array = new OSDArray(); + array.Add(OSD.FromReal(value.X)); + array.Add(OSD.FromReal(value.Y)); + array.Add(OSD.FromReal(value.Z)); + array.Add(OSD.FromReal(value.W)); + return array; + } + + public static OSD FromColor4(Color4 value) + { + OSDArray array = new OSDArray(); + array.Add(OSD.FromReal(value.R)); + array.Add(OSD.FromReal(value.G)); + array.Add(OSD.FromReal(value.B)); + array.Add(OSD.FromReal(value.A)); + return array; + } + + public static OSD FromObject(object value) + { + if (value == null) { return new OSD(); } + else if (value is bool) { return new OSDBoolean((bool)value); } + else if (value is int) { return new OSDInteger((int)value); } + else if (value is uint) { return new OSDBinary((uint)value); } + else if (value is short) { return new OSDInteger((int)(short)value); } + else if (value is ushort) { return new OSDInteger((int)(ushort)value); } + else if (value is sbyte) { return new OSDInteger((int)(sbyte)value); } + else if (value is byte) { return new OSDInteger((int)(byte)value); } + else if (value is double) { return new OSDReal((double)value); } + else if (value is float) { return new OSDReal((double)(float)value); } + else if (value is string) { return new OSDString((string)value); } + else if (value is UUID) { return new OSDUUID((UUID)value); } + else if (value is DateTime) { return new OSDDate((DateTime)value); } + else if (value is Uri) { return new OSDUri((Uri)value); } + else if (value is byte[]) { return new OSDBinary((byte[])value); } + else if (value is long) { return new OSDBinary((long)value); } + else if (value is ulong) { return new OSDBinary((ulong)value); } + else if (value is Vector2) { return FromVector2((Vector2)value); } + else if (value is Vector3) { return FromVector3((Vector3)value); } + else if (value is Vector3d) { return FromVector3d((Vector3d)value); } + else if (value is Vector4) { return FromVector4((Vector4)value); } + else if (value is Quaternion) { return FromQuaternion((Quaternion)value); } + else if (value is Color4) { return FromColor4((Color4)value); } + else return new OSD(); + } + + public static object ToObject(Type type, OSD value) + { + if (type == typeof(ulong)) + { + if (value.Type == OSDType.Binary) + { + byte[] bytes = value.AsBinary(); + return Utils.BytesToUInt64(bytes); + } + else + { + return (ulong)value.AsInteger(); + } + } + else if (type == typeof(uint)) + { + if (value.Type == OSDType.Binary) + { + byte[] bytes = value.AsBinary(); + return Utils.BytesToUInt(bytes); + } + else + { + return (uint)value.AsInteger(); + } + } + else if (type == typeof(ushort)) + { + return (ushort)value.AsInteger(); + } + else if (type == typeof(byte)) + { + return (byte)value.AsInteger(); + } + else if (type == typeof(short)) + { + return (short)value.AsInteger(); + } + else if (type == typeof(string)) + { + return value.AsString(); + } + else if (type == typeof(bool)) + { + return value.AsBoolean(); + } + else if (type == typeof(float)) + { + return (float)value.AsReal(); + } + else if (type == typeof(double)) + { + return value.AsReal(); + } + else if (type == typeof(int)) + { + return value.AsInteger(); + } + else if (type == typeof(UUID)) + { + return value.AsUUID(); + } + else if (type == typeof(Vector3)) + { + if (value.Type == OSDType.Array) + return ((OSDArray)value).AsVector3(); + else + return Vector3.Zero; + } + else if (type == typeof(Vector4)) + { + if (value.Type == OSDType.Array) + return ((OSDArray)value).AsVector4(); + else + return Vector4.Zero; + } + else if (type == typeof(Quaternion)) + { + if (value.Type == OSDType.Array) + return ((OSDArray)value).AsQuaternion(); + else + return Quaternion.Identity; + } + else if (type == typeof(OSDArray)) + { + OSDArray newArray = new OSDArray(); + foreach (OSD o in (OSDArray)value) + newArray.Add(o); + return newArray; + } + else if (type == typeof(OSDMap)) + { + OSDMap newMap = new OSDMap(); + foreach (KeyValuePair o in (OSDMap)value) + newMap.Add(o); + return newMap; + } + else + { + return null; + } + } + + #region Implicit Conversions + + public static implicit operator OSD(bool value) { return new OSDBoolean(value); } + public static implicit operator OSD(int value) { return new OSDInteger(value); } + public static implicit operator OSD(uint value) { return new OSDInteger((int)value); } + public static implicit operator OSD(short value) { return new OSDInteger((int)value); } + public static implicit operator OSD(ushort value) { return new OSDInteger((int)value); } + public static implicit operator OSD(sbyte value) { return new OSDInteger((int)value); } + public static implicit operator OSD(byte value) { return new OSDInteger((int)value); } + public static implicit operator OSD(long value) { return new OSDBinary(value); } + public static implicit operator OSD(ulong value) { return new OSDBinary(value); } + public static implicit operator OSD(double value) { return new OSDReal(value); } + public static implicit operator OSD(float value) { return new OSDReal(value); } + public static implicit operator OSD(string value) { return new OSDString(value); } + public static implicit operator OSD(UUID value) { return new OSDUUID(value); } + public static implicit operator OSD(DateTime value) { return new OSDDate(value); } + public static implicit operator OSD(Uri value) { return new OSDUri(value); } + public static implicit operator OSD(byte[] value) { return new OSDBinary(value); } + public static implicit operator OSD(Vector2 value) { return OSD.FromVector2(value); } + public static implicit operator OSD(Vector3 value) { return OSD.FromVector3(value); } + public static implicit operator OSD(Vector3d value) { return OSD.FromVector3d(value); } + public static implicit operator OSD(Vector4 value) { return OSD.FromVector4(value); } + public static implicit operator OSD(Quaternion value) { return OSD.FromQuaternion(value); } + public static implicit operator OSD(Color4 value) { return OSD.FromColor4(value); } + + public static implicit operator bool(OSD value) { return value.AsBoolean(); } + public static implicit operator int(OSD value) { return value.AsInteger(); } + public static implicit operator uint(OSD value) { return value.AsUInteger(); } + public static implicit operator long(OSD value) { return value.AsLong(); } + public static implicit operator ulong(OSD value) { return value.AsULong(); } + public static implicit operator double(OSD value) { return value.AsReal(); } + public static implicit operator float(OSD value) { return (float)value.AsReal(); } + public static implicit operator string(OSD value) { return value.AsString(); } + public static implicit operator UUID(OSD value) { return value.AsUUID(); } + public static implicit operator DateTime(OSD value) { return value.AsDate(); } + public static implicit operator Uri(OSD value) { return value.AsUri(); } + public static implicit operator byte[](OSD value) { return value.AsBinary(); } + public static implicit operator Vector2(OSD value) { return value.AsVector2(); } + public static implicit operator Vector3(OSD value) { return value.AsVector3(); } + public static implicit operator Vector3d(OSD value) { return value.AsVector3d(); } + public static implicit operator Vector4(OSD value) { return value.AsVector4(); } + public static implicit operator Quaternion(OSD value) { return value.AsQuaternion(); } + public static implicit operator Color4(OSD value) { return value.AsColor4(); } + + #endregion Implicit Conversions + + /// + /// Uses reflection to create an SDMap from all of the SD + /// serializable types in an object + /// + /// Class or struct containing serializable types + /// An SDMap holding the serialized values from the + /// container object + public static OSDMap SerializeMembers(object obj) + { + Type t = obj.GetType(); + FieldInfo[] fields = t.GetFields(); + + OSDMap map = new OSDMap(fields.Length); + + for (int i = 0; i < fields.Length; i++) + { + FieldInfo field = fields[i]; + if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute))) + { + OSD serializedField = OSD.FromObject(field.GetValue(obj)); + + if (serializedField.Type != OSDType.Unknown || field.FieldType == typeof(string) || field.FieldType == typeof(byte[])) + map.Add(field.Name, serializedField); + } + } + + return map; + } + + /// + /// Uses reflection to deserialize member variables in an object from + /// an SDMap + /// + /// Reference to an object to fill with deserialized + /// values + /// Serialized values to put in the target + /// object + public static void DeserializeMembers(ref object obj, OSDMap serialized) + { + Type t = obj.GetType(); + FieldInfo[] fields = t.GetFields(); + + for (int i = 0; i < fields.Length; i++) + { + FieldInfo field = fields[i]; + if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute))) + { + OSD serializedField; + if (serialized.TryGetValue(field.Name, out serializedField)) + field.SetValue(obj, ToObject(field.FieldType, serializedField)); + } + } + } + } + + /// + /// + /// + public sealed class OSDBoolean : OSD + { + private bool value; + + private static byte[] trueBinary = { 0x31 }; + private static byte[] falseBinary = { 0x30 }; + + public override OSDType Type { get { return OSDType.Boolean; } } + + public OSDBoolean(bool value) + { + this.value = value; + } + + public override bool AsBoolean() { return value; } + public override int AsInteger() { return value ? 1 : 0; } + public override double AsReal() { return value ? 1d : 0d; } + public override string AsString() { return value ? "1" : "0"; } + public override byte[] AsBinary() { return value ? trueBinary : falseBinary; } + public override OSD Copy() { return new OSDBoolean(value); } + + public override string ToString() { return AsString(); } + } + + /// + /// + /// + public sealed class OSDInteger : OSD + { + private int value; + + public override OSDType Type { get { return OSDType.Integer; } } + + public OSDInteger(int value) + { + this.value = value; + } + + public override bool AsBoolean() { return value != 0; } + public override int AsInteger() { return value; } + public override uint AsUInteger() { return (uint)value; } + public override long AsLong() { return value; } + public override ulong AsULong() { return (ulong)value; } + public override double AsReal() { return (double)value; } + public override string AsString() { return value.ToString(); } + public override byte[] AsBinary() { return Utils.IntToBytesBig(value); } + public override OSD Copy() { return new OSDInteger(value); } + + public override string ToString() { return AsString(); } + } + + /// + /// + /// + public sealed class OSDReal : OSD + { + private double value; + + public override OSDType Type { get { return OSDType.Real; } } + + public OSDReal(double value) + { + this.value = value; + } + + public override bool AsBoolean() { return (!Double.IsNaN(value) && value != 0d); } + public override OSD Copy() { return new OSDReal(value); } + + public override int AsInteger() + { + if (Double.IsNaN(value)) + return 0; + if (value > (double)Int32.MaxValue) + return Int32.MaxValue; + if (value < (double)Int32.MinValue) + return Int32.MinValue; + return (int)Math.Round(value); + } + + public override uint AsUInteger() + { + if (Double.IsNaN(value)) + return 0; + if (value > (double)UInt32.MaxValue) + return UInt32.MaxValue; + if (value < (double)UInt32.MinValue) + return UInt32.MinValue; + return (uint)Math.Round(value); + } + + public override long AsLong() + { + if (Double.IsNaN(value)) + return 0; + if (value > (double)Int64.MaxValue) + return Int64.MaxValue; + if (value < (double)Int64.MinValue) + return Int64.MinValue; + return (long)Math.Round(value); + } + + public override ulong AsULong() + { + if (Double.IsNaN(value)) + return 0; + if (value > (double)UInt64.MaxValue) + return Int32.MaxValue; + if (value < (double)UInt64.MinValue) + return UInt64.MinValue; + return (ulong)Math.Round(value); + } + + public override double AsReal() { return value; } + // "r" ensures the value will correctly round-trip back through Double.TryParse + public override string AsString() { return value.ToString("r", Utils.EnUsCulture); } + public override byte[] AsBinary() { return Utils.DoubleToBytesBig(value); } + public override string ToString() { return AsString(); } + } + + /// + /// + /// + public sealed class OSDString : OSD + { + private string value; + + public override OSDType Type { get { return OSDType.String; } } + + public override OSD Copy() { return new OSDString(value); } + + public OSDString(string value) + { + // Refuse to hold null pointers + if (value != null) + this.value = value; + else + this.value = String.Empty; + } + + public override bool AsBoolean() + { + if (String.IsNullOrEmpty(value)) + return false; + + if (value == "0" || value.ToLower() == "false") + return false; + + return true; + } + + public override int AsInteger() + { + double dbl; + if (Double.TryParse(value, out dbl)) + return (int)Math.Floor(dbl); + else + return 0; + } + + public override uint AsUInteger() + { + double dbl; + if (Double.TryParse(value, out dbl)) + return (uint)Math.Floor(dbl); + else + return 0; + } + + public override long AsLong() + { + double dbl; + if (Double.TryParse(value, out dbl)) + return (long)Math.Floor(dbl); + else + return 0; + } + + public override ulong AsULong() + { + double dbl; + if (Double.TryParse(value, out dbl)) + return (ulong)Math.Floor(dbl); + else + return 0; + } + + public override double AsReal() + { + double dbl; + if (Double.TryParse(value, out dbl)) + return dbl; + else + return 0d; + } + + public override string AsString() { return value; } + public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(value); } + public override UUID AsUUID() + { + UUID uuid; + if (UUID.TryParse(value, out uuid)) + return uuid; + else + return UUID.Zero; + } + public override DateTime AsDate() + { + DateTime dt; + if (DateTime.TryParse(value, out dt)) + return dt; + else + return Utils.Epoch; + } + public override Uri AsUri() + { + Uri uri; + if (Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out uri)) + return uri; + else + return null; + } + + public override string ToString() { return AsString(); } + } + + /// + /// + /// + public sealed class OSDUUID : OSD + { + private UUID value; + + public override OSDType Type { get { return OSDType.UUID; } } + + public OSDUUID(UUID value) + { + this.value = value; + } + + public override OSD Copy() { return new OSDUUID(value); } + public override bool AsBoolean() { return (value == UUID.Zero) ? false : true; } + public override string AsString() { return value.ToString(); } + public override UUID AsUUID() { return value; } + public override byte[] AsBinary() { return value.GetBytes(); } + public override string ToString() { return AsString(); } + } + + /// + /// + /// + public sealed class OSDDate : OSD + { + private DateTime value; + + public override OSDType Type { get { return OSDType.Date; } } + + public OSDDate(DateTime value) + { + this.value = value; + } + + public override string AsString() + { + string format; + if (value.Millisecond > 0) + format = "yyyy-MM-ddTHH:mm:ss.ffZ"; + else + format = "yyyy-MM-ddTHH:mm:ssZ"; + return value.ToUniversalTime().ToString(format); + } + + public override int AsInteger() + { + return (int)Utils.DateTimeToUnixTime(value); + } + + public override uint AsUInteger() + { + return Utils.DateTimeToUnixTime(value); + } + + public override long AsLong() + { + return (long)Utils.DateTimeToUnixTime(value); + } + + public override ulong AsULong() + { + return Utils.DateTimeToUnixTime(value); + } + + public override byte[] AsBinary() + { + TimeSpan ts = value.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + return Utils.DoubleToBytes(ts.TotalSeconds); + } + + public override OSD Copy() { return new OSDDate(value); } + public override DateTime AsDate() { return value; } + public override string ToString() { return AsString(); } + } + + /// + /// + /// + public sealed class OSDUri : OSD + { + private Uri value; + + public override OSDType Type { get { return OSDType.URI; } } + + public OSDUri(Uri value) + { + this.value = value; + } + + public override string AsString() + { + if (value != null) + { + if (value.IsAbsoluteUri) + return value.AbsoluteUri; + else + return value.ToString(); + } + return string.Empty; + } + + public override OSD Copy() { return new OSDUri(value); } + public override Uri AsUri() { return value; } + public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(AsString()); } + public override string ToString() { return AsString(); } + } + + /// + /// + /// + public sealed class OSDBinary : OSD + { + private byte[] value; + + public override OSDType Type { get { return OSDType.Binary; } } + + public OSDBinary(byte[] value) + { + if (value != null) + this.value = value; + else + this.value = Utils.EmptyBytes; + } + + public OSDBinary(uint value) + { + this.value = new byte[] + { + (byte)((value >> 24) % 256), + (byte)((value >> 16) % 256), + (byte)((value >> 8) % 256), + (byte)(value % 256) + }; + } + + public OSDBinary(long value) + { + this.value = new byte[] + { + (byte)((value >> 56) % 256), + (byte)((value >> 48) % 256), + (byte)((value >> 40) % 256), + (byte)((value >> 32) % 256), + (byte)((value >> 24) % 256), + (byte)((value >> 16) % 256), + (byte)((value >> 8) % 256), + (byte)(value % 256) + }; + } + + public OSDBinary(ulong value) + { + this.value = new byte[] + { + (byte)((value >> 56) % 256), + (byte)((value >> 48) % 256), + (byte)((value >> 40) % 256), + (byte)((value >> 32) % 256), + (byte)((value >> 24) % 256), + (byte)((value >> 16) % 256), + (byte)((value >> 8) % 256), + (byte)(value % 256) + }; + } + + public override OSD Copy() { return new OSDBinary(value); } + public override string AsString() { return Convert.ToBase64String(value); } + public override byte[] AsBinary() { return value; } + + public override uint AsUInteger() + { + return (uint)( + (value[0] << 24) + + (value[1] << 16) + + (value[2] << 8) + + (value[3] << 0)); + } + + public override long AsLong() + { + return (long)( + ((long)value[0] << 56) + + ((long)value[1] << 48) + + ((long)value[2] << 40) + + ((long)value[3] << 32) + + ((long)value[4] << 24) + + ((long)value[5] << 16) + + ((long)value[6] << 8) + + ((long)value[7] << 0)); + } + + public override ulong AsULong() + { + return (ulong)( + ((ulong)value[0] << 56) + + ((ulong)value[1] << 48) + + ((ulong)value[2] << 40) + + ((ulong)value[3] << 32) + + ((ulong)value[4] << 24) + + ((ulong)value[5] << 16) + + ((ulong)value[6] << 8) + + ((ulong)value[7] << 0)); + } + + public override string ToString() + { + return Utils.BytesToHexString(value, null); + } + } + + /// + /// + /// + public sealed class OSDMap : OSD, IDictionary + { + private Dictionary value; + + public override OSDType Type { get { return OSDType.Map; } } + + public OSDMap() + { + value = new Dictionary(); + } + + public OSDMap(int capacity) + { + value = new Dictionary(capacity); + } + + public OSDMap(Dictionary value) + { + if (value != null) + this.value = value; + else + this.value = new Dictionary(); + } + + public override bool AsBoolean() { return value.Count > 0; } + + public override string ToString() + { + return OSDParser.SerializeJsonString(this, true); + } + + public override OSD Copy() + { + return new OSDMap(new Dictionary(value)); + } + + #region IDictionary Implementation + + public int Count { get { return value.Count; } } + public bool IsReadOnly { get { return false; } } + public ICollection Keys { get { return value.Keys; } } + public ICollection Values { get { return value.Values; } } + public OSD this[string key] + { + get + { + OSD llsd; + if (this.value.TryGetValue(key, out llsd)) + return llsd; + else + return new OSD(); + } + set { this.value[key] = value; } + } + + public bool ContainsKey(string key) + { + return value.ContainsKey(key); + } + + public void Add(string key, OSD llsd) + { + value.Add(key, llsd); + } + + public void Add(KeyValuePair kvp) + { + value.Add(kvp.Key, kvp.Value); + } + + public bool Remove(string key) + { + return value.Remove(key); + } + + public bool TryGetValue(string key, out OSD llsd) + { + return value.TryGetValue(key, out llsd); + } + + public void Clear() + { + value.Clear(); + } + + public bool Contains(KeyValuePair kvp) + { + // This is a bizarre function... we don't really implement it + // properly, hopefully no one wants to use it + return value.ContainsKey(kvp.Key); + } + + public void CopyTo(KeyValuePair[] array, int index) + { + throw new NotImplementedException(); + } + + public bool Remove(KeyValuePair kvp) + { + return this.value.Remove(kvp.Key); + } + + public System.Collections.IDictionaryEnumerator GetEnumerator() + { + return value.GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return null; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return value.GetEnumerator(); + } + + #endregion IDictionary Implementation + } + + /// + /// + /// + public sealed class OSDArray : OSD, IList + { + private List value; + + public override OSDType Type { get { return OSDType.Array; } } + + public OSDArray() + { + value = new List(); + } + + public OSDArray(int capacity) + { + value = new List(capacity); + } + + public OSDArray(List value) + { + if (value != null) + this.value = value; + else + this.value = new List(); + } + + public override byte[] AsBinary() + { + byte[] binary = new byte[value.Count]; + + for (int i = 0; i < value.Count; i++) + binary[i] = (byte)value[i].AsInteger(); + + return binary; + } + + public override long AsLong() + { + OSDBinary binary = new OSDBinary(AsBinary()); + return binary.AsLong(); + } + + public override ulong AsULong() + { + OSDBinary binary = new OSDBinary(AsBinary()); + return binary.AsULong(); + } + + public override uint AsUInteger() + { + OSDBinary binary = new OSDBinary(AsBinary()); + return binary.AsUInteger(); + } + + public override Vector2 AsVector2() + { + Vector2 vector = Vector2.Zero; + + if (this.Count == 2) + { + vector.X = (float)this[0].AsReal(); + vector.Y = (float)this[1].AsReal(); + } + + return vector; + } + + public override Vector3 AsVector3() + { + Vector3 vector = Vector3.Zero; + + if (this.Count == 3) + { + vector.X = (float)this[0].AsReal(); + vector.Y = (float)this[1].AsReal(); + vector.Z = (float)this[2].AsReal(); + } + + return vector; + } + + public override Vector3d AsVector3d() + { + Vector3d vector = Vector3d.Zero; + + if (this.Count == 3) + { + vector.X = this[0].AsReal(); + vector.Y = this[1].AsReal(); + vector.Z = this[2].AsReal(); + } + + return vector; + } + + public override Vector4 AsVector4() + { + Vector4 vector = Vector4.Zero; + + if (this.Count == 4) + { + vector.X = (float)this[0].AsReal(); + vector.Y = (float)this[1].AsReal(); + vector.Z = (float)this[2].AsReal(); + vector.W = (float)this[3].AsReal(); + } + + return vector; + } + + public override Quaternion AsQuaternion() + { + Quaternion quaternion = Quaternion.Identity; + + if (this.Count == 4) + { + quaternion.X = (float)this[0].AsReal(); + quaternion.Y = (float)this[1].AsReal(); + quaternion.Z = (float)this[2].AsReal(); + quaternion.W = (float)this[3].AsReal(); + } + + return quaternion; + } + + public override Color4 AsColor4() + { + Color4 color = Color4.Black; + + if (this.Count == 4) + { + color.R = (float)this[0].AsReal(); + color.G = (float)this[1].AsReal(); + color.B = (float)this[2].AsReal(); + color.A = (float)this[3].AsReal(); + } + + return color; + } + + public override OSD Copy() + { + return new OSDArray(new List(value)); + } + + public override bool AsBoolean() { return value.Count > 0; } + + public override string ToString() + { + return OSDParser.SerializeJsonString(this, true); + } + + #region IList Implementation + + public int Count { get { return value.Count; } } + public bool IsReadOnly { get { return false; } } + public OSD this[int index] + { + get { return value[index]; } + set { this.value[index] = value; } + } + + public int IndexOf(OSD llsd) + { + return value.IndexOf(llsd); + } + + public void Insert(int index, OSD llsd) + { + value.Insert(index, llsd); + } + + public void RemoveAt(int index) + { + value.RemoveAt(index); + } + + public void Add(OSD llsd) + { + value.Add(llsd); + } + + public void Clear() + { + value.Clear(); + } + + public bool Contains(OSD llsd) + { + return value.Contains(llsd); + } + + public bool Contains(string element) + { + for (int i = 0; i < value.Count; i++) + { + if (value[i].Type == OSDType.String && value[i].AsString() == element) + return true; + } + + return false; + } + + public void CopyTo(OSD[] array, int index) + { + throw new NotImplementedException(); + } + + public bool Remove(OSD llsd) + { + return value.Remove(llsd); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return value.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return value.GetEnumerator(); + } + + #endregion IList Implementation + } + + public partial class OSDParser + { + const string LLSD_BINARY_HEADER = ""; + const string LLSD_XML_HEADER = ""; + const string LLSD_XML_ALT_HEADER = ""; + + public static OSD Deserialize(byte[] data) + { + string header = Encoding.ASCII.GetString(data, 0, data.Length >= 17 ? 17 : data.Length); + + try + { + string uHeader = Encoding.UTF8.GetString(data, 0, data.Length >= 17 ? 17 : data.Length).TrimStart(); + if (uHeader.StartsWith(LLSD_XML_HEADER, StringComparison.InvariantCultureIgnoreCase) || + uHeader.StartsWith(LLSD_XML_ALT_HEADER, StringComparison.InvariantCultureIgnoreCase) || + uHeader.StartsWith(LLSD_XML_ALT2_HEADER, StringComparison.InvariantCultureIgnoreCase)) + { + return DeserializeLLSDXml(data); + } + } + catch { } + + if (header.StartsWith(LLSD_BINARY_HEADER, StringComparison.InvariantCultureIgnoreCase)) + { + return DeserializeLLSDBinary(data); + } + else if (header.StartsWith(LLSD_XML_HEADER, StringComparison.InvariantCultureIgnoreCase) || + header.StartsWith(LLSD_XML_ALT_HEADER, StringComparison.InvariantCultureIgnoreCase) || + header.StartsWith(LLSD_XML_ALT2_HEADER, StringComparison.InvariantCultureIgnoreCase)) + { + return DeserializeLLSDXml(data); + } + else + { + return DeserializeJson(Encoding.UTF8.GetString(data)); + } + } + + public static OSD Deserialize(string data) + { + if (data.StartsWith(LLSD_BINARY_HEADER, StringComparison.InvariantCultureIgnoreCase)) + { + return DeserializeLLSDBinary(Encoding.UTF8.GetBytes(data)); + } + else if (data.StartsWith(LLSD_XML_HEADER, StringComparison.InvariantCultureIgnoreCase) || + data.StartsWith(LLSD_XML_ALT_HEADER, StringComparison.InvariantCultureIgnoreCase) || + data.StartsWith(LLSD_XML_ALT2_HEADER, StringComparison.InvariantCultureIgnoreCase)) + { + return DeserializeLLSDXml(data); + } + else + { + return DeserializeJson(data); + } + } + + public static OSD Deserialize(Stream stream) + { + if (stream.CanSeek) + { + byte[] headerData = new byte[14]; + stream.Read(headerData, 0, 14); + stream.Seek(0, SeekOrigin.Begin); + string header = Encoding.ASCII.GetString(headerData); + + if (header.StartsWith(LLSD_BINARY_HEADER)) + return DeserializeLLSDBinary(stream); + else if (header.StartsWith(LLSD_XML_HEADER) || header.StartsWith(LLSD_XML_ALT_HEADER) || header.StartsWith(LLSD_XML_ALT2_HEADER)) + return DeserializeLLSDXml(stream); + else + return DeserializeJson(stream); + } + else + { + throw new OSDException("Cannot deserialize structured data from unseekable streams"); + } + } + } +} diff --git a/OpenMetaverse.Utilities/OpenMetaverse.Utilities.dll.build b/OpenMetaverse.Utilities/OpenMetaverse.Utilities.dll.build new file mode 100644 index 0000000..66789af --- /dev/null +++ b/OpenMetaverse.Utilities/OpenMetaverse.Utilities.dll.build @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverse.Utilities/OpenMetaverse.Utilities.mdp b/OpenMetaverse.Utilities/OpenMetaverse.Utilities.mdp new file mode 100644 index 0000000..ecad893 --- /dev/null +++ b/OpenMetaverse.Utilities/OpenMetaverse.Utilities.mdp @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverse.Utilities/Properties/AssemblyInfo.cs b/OpenMetaverse.Utilities/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ed53187 --- /dev/null +++ b/OpenMetaverse.Utilities/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMetaverse.Utilities")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenMetaverse.Utilities")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b77aa07a-daa3-431f-b5aa-0c9c5e2151fd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenMetaverse.Utilities/RegistrationApi.cs b/OpenMetaverse.Utilities/RegistrationApi.cs new file mode 100644 index 0000000..9e67bd4 --- /dev/null +++ b/OpenMetaverse.Utilities/RegistrationApi.cs @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Text; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; + +namespace OpenMetaverse +{ + public class RegistrationApi + { + const int REQUEST_TIMEOUT = 1000 * 100; + + private struct UserInfo + { + public string FirstName; + public string LastName; + public string Password; + } + + private struct RegistrationCaps + { + public Uri CreateUser; + public Uri CheckName; + public Uri GetLastNames; + public Uri GetErrorCodes; + } + + public struct LastName + { + public int ID; + public string Name; + } + + /// + /// See https://secure-web6.secondlife.com/developers/third_party_reg/#service_create_user or + /// https://wiki.secondlife.com/wiki/RegAPIDoc for description + /// + public class CreateUserParam + { + public string FirstName; + public LastName LastName; + public string Email; + public string Password; + public DateTime Birthdate; + + // optional: + public Nullable LimitedToEstate; + public string StartRegionName; + public Nullable StartLocation; + public Nullable StartLookAt; + } + + private UserInfo _userInfo; + private RegistrationCaps _caps; + private int _initializing; + private List _lastNames = new List(); + private Dictionary _errors = new Dictionary(); + + public bool Initializing + { + get + { + System.Diagnostics.Debug.Assert(_initializing <= 0); + return (_initializing < 0); + } + } + + public List LastNames + { + get + { + lock (_lastNames) + { + if (_lastNames.Count <= 0) + GatherLastNames(); + } + + return _lastNames; + } + } + + public RegistrationApi(string firstName, string lastName, string password) + { + _initializing = -2; + + _userInfo = new UserInfo(); + + _userInfo.FirstName = firstName; + _userInfo.LastName = lastName; + _userInfo.Password = password; + + GatherCaps(); + } + + public void WaitForInitialization() + { + while (Initializing) + System.Threading.Thread.Sleep(10); + } + + public Uri RegistrationApiCaps + { + get { return new Uri("https://cap.secondlife.com/get_reg_capabilities"); } + } + + private void GatherCaps() + { + // build post data + byte[] postData = Encoding.ASCII.GetBytes( + String.Format("first_name={0}&last_name={1}&password={2}", _userInfo.FirstName, _userInfo.LastName, + _userInfo.Password)); + + CapsClient request = new CapsClient(RegistrationApiCaps); + request.OnComplete += new CapsClient.CompleteCallback(GatherCapsResponse); + request.BeginGetResponse(postData, "application/x-www-form-urlencoded", REQUEST_TIMEOUT); + } + + private void GatherCapsResponse(CapsClient client, OSD response, Exception error) + { + if (response is OSDMap) + { + OSDMap respTable = (OSDMap)response; + + // parse + _caps = new RegistrationCaps(); + + _caps.CreateUser = respTable["create_user"].AsUri(); + _caps.CheckName = respTable["check_name"].AsUri(); + _caps.GetLastNames = respTable["get_last_names"].AsUri(); + _caps.GetErrorCodes = respTable["get_error_codes"].AsUri(); + + // finalize + _initializing++; + + GatherErrorMessages(); + } + } + + private void GatherErrorMessages() + { + if (_caps.GetErrorCodes == null) + throw new InvalidOperationException("access denied"); // this should work even for not-approved users + + CapsClient request = new CapsClient(_caps.GetErrorCodes); + request.OnComplete += new CapsClient.CompleteCallback(GatherErrorMessagesResponse); + request.BeginGetResponse(REQUEST_TIMEOUT); + } + + private void GatherErrorMessagesResponse(CapsClient client, OSD response, Exception error) + { + if (response is OSDMap) + { + // parse + + //FIXME: wtf? + //foreach (KeyValuePair error in (Dictionary)response) + //{ + //StringBuilder sb = new StringBuilder(); + + //sb.Append(error[1]); + //sb.Append(" ("); + //sb.Append(error[0]); + //sb.Append("): "); + //sb.Append(error[2]); + + //_errors.Add((int)error[0], sb.ToString()); + //} + + // finalize + _initializing++; + } + } + + public void GatherLastNames() + { + if (Initializing) + throw new InvalidOperationException("still initializing"); + + if (_caps.GetLastNames == null) + throw new InvalidOperationException("access denied: only approved developers have access to the registration api"); + + CapsClient request = new CapsClient(_caps.GetLastNames); + request.OnComplete += new CapsClient.CompleteCallback(GatherLastNamesResponse); + request.BeginGetResponse(REQUEST_TIMEOUT); + + // FIXME: Block + } + + private void GatherLastNamesResponse(CapsClient client, OSD response, Exception error) + { + if (response is OSDMap) + { + //LLSDMap respTable = (LLSDMap)response; + + //FIXME: + //_lastNames = new List(respTable.Count); + + //for (Dictionary.Enumerator it = respTable.GetEnumerator(); it.MoveNext(); ) + //{ + // LastName ln = new LastName(); + + // ln.ID = int.Parse(it.Current.Key.ToString()); + // ln.Name = it.Current.Value.ToString(); + + // _lastNames.Add(ln); + //} + + //_lastNames.Sort(new Comparison(delegate(LastName a, LastName b) { return a.Name.CompareTo(b.Name); })); + } + } + + public bool CheckName(string firstName, LastName lastName) + { + if (Initializing) + throw new InvalidOperationException("still initializing"); + + if (_caps.CheckName == null) + throw new InvalidOperationException("access denied; only approved developers have access to the registration api"); + + // Create the POST data + OSDMap query = new OSDMap(); + query.Add("username", OSD.FromString(firstName)); + query.Add("last_name_id", OSD.FromInteger(lastName.ID)); + //byte[] postData = OSDParser.SerializeXmlBytes(query); + + CapsClient request = new CapsClient(_caps.CheckName); + request.OnComplete += new CapsClient.CompleteCallback(CheckNameResponse); + request.BeginGetResponse(REQUEST_TIMEOUT); + + // FIXME: + return false; + } + + private void CheckNameResponse(CapsClient client, OSD response, Exception error) + { + if (response.Type == OSDType.Boolean) + { + // FIXME: + //(bool)response; + } + else + { + // FIXME: + } + } + + /// + /// Returns the new user ID or throws an exception containing the error code + /// The error codes can be found here: https://wiki.secondlife.com/wiki/RegAPIError + /// + /// New user account to create + /// The UUID of the new user account + public UUID CreateUser(CreateUserParam user) + { + if (Initializing) + throw new InvalidOperationException("still initializing"); + + if (_caps.CreateUser == null) + throw new InvalidOperationException("access denied; only approved developers have access to the registration api"); + + // Create the POST data + OSDMap query = new OSDMap(); + query.Add("username", OSD.FromString(user.FirstName)); + query.Add("last_name_id", OSD.FromInteger(user.LastName.ID)); + query.Add("email", OSD.FromString(user.Email)); + query.Add("password", OSD.FromString(user.Password)); + query.Add("dob", OSD.FromString(user.Birthdate.ToString("yyyy-MM-dd"))); + + if (user.LimitedToEstate != null) + query.Add("limited_to_estate", OSD.FromInteger(user.LimitedToEstate.Value)); + + if (!string.IsNullOrEmpty(user.StartRegionName)) + query.Add("start_region_name", OSD.FromInteger(user.LimitedToEstate.Value)); + + if (user.StartLocation != null) + { + query.Add("start_local_x", OSD.FromReal(user.StartLocation.Value.X)); + query.Add("start_local_y", OSD.FromReal(user.StartLocation.Value.Y)); + query.Add("start_local_z", OSD.FromReal(user.StartLocation.Value.Z)); + } + + if (user.StartLookAt != null) + { + query.Add("start_look_at_x", OSD.FromReal(user.StartLookAt.Value.X)); + query.Add("start_look_at_y", OSD.FromReal(user.StartLookAt.Value.Y)); + query.Add("start_look_at_z", OSD.FromReal(user.StartLookAt.Value.Z)); + } + + //byte[] postData = OSDParser.SerializeXmlBytes(query); + + // Make the request + CapsClient request = new CapsClient(_caps.CreateUser); + request.OnComplete += new CapsClient.CompleteCallback(CreateUserResponse); + request.BeginGetResponse(REQUEST_TIMEOUT); + + // FIXME: Block + return UUID.Zero; + } + + private void CreateUserResponse(CapsClient client, OSD response, Exception error) + { + if (response is OSDMap) + { + // everything is okay + // FIXME: + //return new UUID(((Dictionary)response)["agent_id"].ToString()); + } + else + { + // an error happened + OSDArray al = (OSDArray)response; + + StringBuilder sb = new StringBuilder(); + + foreach (OSD ec in al) + { + if (sb.Length > 0) + sb.Append("; "); + + sb.Append(_errors[ec.AsInteger()]); + } + + // FIXME: + //throw new Exception("failed to create user: " + sb.ToString()); + } + } + } +} diff --git a/OpenMetaverse.Utilities/Utilities.cs b/OpenMetaverse.Utilities/Utilities.cs new file mode 100644 index 0000000..2ac5c49 --- /dev/null +++ b/OpenMetaverse.Utilities/Utilities.cs @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.Utilities +{ + /// + /// + /// + public enum WaterType + { + /// + Unknown, + /// + Dry, + /// + Waterfront, + /// + Underwater + } + + public static class Realism + { + /// + /// Aims at the specified position, enters mouselook, presses and + /// releases the left mouse button, and leaves mouselook + /// + /// + /// Target to shoot at + /// + public static bool Shoot(GridClient client, Vector3 target) + { + if (client.Self.Movement.TurnToward(target)) + return Shoot(client); + else + return false; + } + + /// + /// Enters mouselook, presses and releases the left mouse button, and leaves mouselook + /// + /// + public static bool Shoot(GridClient client) + { + if (client.Settings.SEND_AGENT_UPDATES) + { + client.Self.Movement.Mouselook = true; + client.Self.Movement.MLButtonDown = true; + client.Self.Movement.SendUpdate(); + + client.Self.Movement.MLButtonUp = true; + client.Self.Movement.MLButtonDown = false; + client.Self.Movement.FinishAnim = true; + client.Self.Movement.SendUpdate(); + + client.Self.Movement.Mouselook = false; + client.Self.Movement.MLButtonUp = false; + client.Self.Movement.FinishAnim = false; + client.Self.Movement.SendUpdate(); + + return true; + } + else + { + Logger.Log("Attempted Shoot but agent updates are disabled", Helpers.LogLevel.Warning, client); + return false; + } + } + + /// + /// A psuedo-realistic chat function that uses the typing sound and + /// animation, types at three characters per second, and randomly + /// pauses. This function will block until the message has been sent + /// + /// A reference to the client that will chat + /// The chat message to send + public static void Chat(GridClient client, string message) + { + Chat(client, message, ChatType.Normal, 3); + } + + /// + /// A psuedo-realistic chat function that uses the typing sound and + /// animation, types at a given rate, and randomly pauses. This + /// function will block until the message has been sent + /// + /// A reference to the client that will chat + /// The chat message to send + /// The chat type (usually Normal, Whisper or Shout) + /// Characters per second rate for chatting + public static void Chat(GridClient client, string message, ChatType type, int cps) + { + Random rand = new Random(); + int characters = 0; + bool typing = true; + + // Start typing + client.Self.Chat(String.Empty, 0, ChatType.StartTyping); + client.Self.AnimationStart(Animations.TYPE, false); + + while (characters < message.Length) + { + if (!typing) + { + // Start typing again + client.Self.Chat(String.Empty, 0, ChatType.StartTyping); + client.Self.AnimationStart(Animations.TYPE, false); + typing = true; + } + else + { + // Randomly pause typing + if (rand.Next(10) >= 9) + { + client.Self.Chat(String.Empty, 0, ChatType.StopTyping); + client.Self.AnimationStop(Animations.TYPE, false); + typing = false; + } + } + + // Sleep for a second and increase the amount of characters we've typed + System.Threading.Thread.Sleep(1000); + characters += cps; + } + + // Send the message + client.Self.Chat(message, 0, type); + + // Stop typing + client.Self.Chat(String.Empty, 0, ChatType.StopTyping); + client.Self.AnimationStop(Animations.TYPE, false); + } + } + + public class ConnectionManager + { + private GridClient Client; + private ulong SimHandle; + private Vector3 Position = Vector3.Zero; + private System.Timers.Timer CheckTimer; + + public ConnectionManager(GridClient client, int timerFrequency) + { + Client = client; + + CheckTimer = new System.Timers.Timer(timerFrequency); + CheckTimer.Elapsed += new System.Timers.ElapsedEventHandler(CheckTimer_Elapsed); + } + + public static bool PersistentLogin(GridClient client, string firstName, string lastName, string password, + string userAgent, string start, string author) + { + int unknownLogins = 0; + + Start: + + if (client.Network.Login(firstName, lastName, password, userAgent, start, author)) + { + Logger.Log("Logged in to " + client.Network.CurrentSim, Helpers.LogLevel.Info, client); + return true; + } + else + { + if (client.Network.LoginErrorKey == "god") + { + Logger.Log("Grid is down, waiting 10 minutes", Helpers.LogLevel.Warning, client); + LoginWait(10); + goto Start; + } + else if (client.Network.LoginErrorKey == "key") + { + Logger.Log("Bad username or password, giving up on login", Helpers.LogLevel.Error, client); + return false; + } + else if (client.Network.LoginErrorKey == "presence") + { + Logger.Log("Server is still logging us out, waiting 1 minute", Helpers.LogLevel.Warning, client); + LoginWait(1); + goto Start; + } + else if (client.Network.LoginErrorKey == "disabled") + { + Logger.Log("This account has been banned! Giving up on login", Helpers.LogLevel.Error, client); + return false; + } + else if (client.Network.LoginErrorKey == "timed out" ||client.Network.LoginErrorKey == "no connection" ) + { + Logger.Log("Login request timed out, waiting 1 minute", Helpers.LogLevel.Warning, client); + LoginWait(1); + goto Start; + } else if (client.Network.LoginErrorKey == "bad response") { + Logger.Log("Login server returned unparsable result", Helpers.LogLevel.Warning, client); + LoginWait(1); + goto Start; + } else + { + ++unknownLogins; + + if (unknownLogins < 5) + { + Logger.Log("Unknown login error, waiting 2 minutes: " + client.Network.LoginErrorKey, + Helpers.LogLevel.Warning, client); + LoginWait(2); + goto Start; + } + else + { + Logger.Log("Too many unknown login error codes, giving up", Helpers.LogLevel.Error, client); + return false; + } + } + } + } + + public void StayInSim(ulong handle, Vector3 desiredPosition) + { + SimHandle = handle; + Position = desiredPosition; + CheckTimer.Start(); + } + + private static void LoginWait(int minutes) + { + Thread.Sleep(1000 * 60 * minutes); + } + + private void CheckTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (SimHandle != 0) + { + if (Client.Network.CurrentSim.Handle != 0 && + Client.Network.CurrentSim.Handle != SimHandle) + { + // Attempt to move to our target sim + Client.Self.Teleport(SimHandle, Position); + } + } + } + } +} diff --git a/OpenMetaverse.Utilities/VoiceManager.cs b/OpenMetaverse.Utilities/VoiceManager.cs new file mode 100644 index 0000000..346791e --- /dev/null +++ b/OpenMetaverse.Utilities/VoiceManager.cs @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net.Sockets; +using System.Text; +using System.IO; +using System.Xml; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse.Utilities +{ + public enum VoiceStatus + { + StatusLoginRetry, + StatusLoggedIn, + StatusJoining, + StatusJoined, + StatusLeftChannel, + BeginErrorStatus, + ErrorChannelFull, + ErrorChannelLocked, + ErrorNotAvailable, + ErrorUnknown + } + + public enum VoiceServiceType + { + /// Unknown voice service level + Unknown, + /// Spatialized local chat + TypeA, + /// Remote multi-party chat + TypeB, + /// One-to-one and small group chat + TypeC + } + + public partial class VoiceManager + { + public const int VOICE_MAJOR_VERSION = 1; + public const string DAEMON_ARGS = " -p tcp -h -c -ll "; + public const int DAEMON_LOG_LEVEL = 1; + public const int DAEMON_PORT = 44124; + public const string VOICE_RELEASE_SERVER = "bhr.vivox.com"; + public const string VOICE_DEBUG_SERVER = "bhd.vivox.com"; + public const string REQUEST_TERMINATOR = "\n\n\n"; + + public delegate void LoginStateChangeCallback(int cookie, string accountHandle, int statusCode, string statusString, int state); + public delegate void NewSessionCallback(int cookie, string accountHandle, string eventSessionHandle, int state, string nameString, string uriString); + public delegate void SessionStateChangeCallback(int cookie, string uriString, int statusCode, string statusString, string eventSessionHandle, int state, bool isChannel, string nameString); + public delegate void ParticipantStateChangeCallback(int cookie, string uriString, int statusCode, string statusString, int state, string nameString, string displayNameString, int participantType); + public delegate void ParticipantPropertiesCallback(int cookie, string uriString, int statusCode, string statusString, bool isLocallyMuted, bool isModeratorMuted, bool isSpeaking, int volume, float energy); + public delegate void AuxAudioPropertiesCallback(int cookie, float energy); + public delegate void BasicActionCallback(int cookie, int statusCode, string statusString); + public delegate void ConnectorCreatedCallback(int cookie, int statusCode, string statusString, string connectorHandle); + public delegate void LoginCallback(int cookie, int statusCode, string statusString, string accountHandle); + public delegate void SessionCreatedCallback(int cookie, int statusCode, string statusString, string sessionHandle); + public delegate void DevicesCallback(int cookie, int statusCode, string statusString, string currentDevice); + public delegate void ProvisionAccountCallback(string username, string password); + public delegate void ParcelVoiceInfoCallback(string regionName, int localID, string channelURI); + + public event LoginStateChangeCallback OnLoginStateChange; + public event NewSessionCallback OnNewSession; + public event SessionStateChangeCallback OnSessionStateChange; + public event ParticipantStateChangeCallback OnParticipantStateChange; + public event ParticipantPropertiesCallback OnParticipantProperties; + public event AuxAudioPropertiesCallback OnAuxAudioProperties; + public event ConnectorCreatedCallback OnConnectorCreated; + public event LoginCallback OnLogin; + public event SessionCreatedCallback OnSessionCreated; + public event BasicActionCallback OnSessionConnected; + public event BasicActionCallback OnAccountLogout; + public event BasicActionCallback OnConnectorInitiateShutdown; + public event BasicActionCallback OnAccountChannelGetList; + public event BasicActionCallback OnSessionTerminated; + public event DevicesCallback OnCaptureDevices; + public event DevicesCallback OnRenderDevices; + public event ProvisionAccountCallback OnProvisionAccount; + public event ParcelVoiceInfoCallback OnParcelVoiceInfo; + + public GridClient Client; + public string VoiceServer = VOICE_RELEASE_SERVER; + public bool Enabled; + + protected Voice.TCPPipe _DaemonPipe; + protected VoiceStatus _Status; + protected int _CommandCookie = 0; + protected string _TuningSoundFile = String.Empty; + protected Dictionary _ChannelMap = new Dictionary(); + protected List _CaptureDevices = new List(); + protected List _RenderDevices = new List(); + + #region Response Processing Variables + + private bool isEvent = false; + private bool isChannel = false; + private bool isLocallyMuted = false; + private bool isModeratorMuted = false; + private bool isSpeaking = false; + private int cookie = 0; + //private int returnCode = 0; + private int statusCode = 0; + private int volume = 0; + private int state = 0; + private int participantType = 0; + private float energy = 0f; + private string statusString = String.Empty; + //private string uuidString = String.Empty; + private string actionString = String.Empty; + private string connectorHandle = String.Empty; + private string accountHandle = String.Empty; + private string sessionHandle = String.Empty; + private string eventSessionHandle = String.Empty; + private string eventTypeString = String.Empty; + private string uriString = String.Empty; + private string nameString = String.Empty; + //private string audioMediaString = String.Empty; + private string displayNameString = String.Empty; + + #endregion Response Processing Variables + + public VoiceManager(GridClient client) + { + Client = client; + Client.Network.RegisterEventCallback("RequiredVoiceVersion", new Caps.EventQueueCallback(RequiredVoiceVersionEventHandler)); + + // Register callback handlers for the blocking functions + RegisterCallbacks(); + + Enabled = true; + } + + public bool IsDaemonRunning() + { + throw new NotImplementedException(); + } + + public bool StartDaemon() + { + throw new NotImplementedException(); + } + + public void StopDaemon() + { + throw new NotImplementedException(); + } + + public bool ConnectToDaemon() + { + if (!Enabled) return false; + + return ConnectToDaemon("127.0.0.1", DAEMON_PORT); + } + + public bool ConnectToDaemon(string address, int port) + { + if (!Enabled) return false; + + _DaemonPipe = new Voice.TCPPipe(); + _DaemonPipe.OnDisconnected += new Voice.TCPPipe.OnDisconnectedCallback(_DaemonPipe_OnDisconnected); + _DaemonPipe.OnReceiveLine += new Voice.TCPPipe.OnReceiveLineCallback(_DaemonPipe_OnReceiveLine); + + SocketException se = _DaemonPipe.Connect(address, port); + + if (se == null) + { + return true; + } + else + { + Console.WriteLine("Connection failed: " + se.Message); + return false; + } + } + + public Dictionary GetChannelMap() + { + return new Dictionary(_ChannelMap); + } + + public List CurrentCaptureDevices() + { + return new List(_CaptureDevices); + } + + public List CurrentRenderDevices() + { + return new List(_RenderDevices); + } + + public string VoiceAccountFromUUID(UUID id) + { + string result = "x" + Convert.ToBase64String(id.GetBytes()); + return result.Replace('+', '-').Replace('/', '_'); + } + + public UUID UUIDFromVoiceAccount(string accountName) + { + if (accountName.Length == 25 && accountName[0] == 'x' && accountName[23] == '=' && accountName[24] == '=') + { + accountName = accountName.Replace('/', '_').Replace('+', '-'); + byte[] idBytes = Convert.FromBase64String(accountName); + + if (idBytes.Length == 16) + return new UUID(idBytes, 0); + else + return UUID.Zero; + } + else + { + return UUID.Zero; + } + } + + public string SIPURIFromVoiceAccount(string account) + { + return String.Format("sip:{0}@{1}", account, VoiceServer); + } + + public int RequestCaptureDevices() + { + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}", + _CommandCookie++, + REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestCaptureDevices() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + public int RequestRenderDevices() + { + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}", + _CommandCookie++, + REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestRenderDevices() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + public int RequestCreateConnector() + { + return RequestCreateConnector(VoiceServer); + } + + public int RequestCreateConnector(string voiceServer) + { + if (_DaemonPipe.Connected) + { + VoiceServer = voiceServer; + + string accountServer = String.Format("https://www.{0}/api2/", VoiceServer); + string logPath = "."; + + StringBuilder request = new StringBuilder(); + request.Append(String.Format("", _CommandCookie++)); + request.Append("V2 SDK"); + request.Append(String.Format("{0}", accountServer)); + request.Append(""); + request.Append("false"); + request.Append(String.Format("{0}", logPath)); + request.Append("vivox-gateway"); + request.Append(".log"); + request.Append("0"); + request.Append(""); + request.Append(""); + request.Append(REQUEST_TERMINATOR); + + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(request.ToString())); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.CreateConnector() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + private bool RequestVoiceInternal(string me, CapsClient.CompleteCallback callback, string capsName) + { + if (Enabled && Client.Network.Connected) + { + if (Client.Network.CurrentSim != null && Client.Network.CurrentSim.Caps != null) + { + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI(capsName); + + if (url != null) + { + CapsClient request = new CapsClient(url); + OSDMap body = new OSDMap(); + request.OnComplete += new CapsClient.CompleteCallback(callback); + request.BeginGetResponse(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + + return true; + } + else + { + Logger.Log("VoiceManager." + me + "(): " + capsName + " capability is missing", + Helpers.LogLevel.Info, Client); + return false; + } + } + } + + Logger.Log("VoiceManager.RequestVoiceInternal(): Voice system is currently disabled", + Helpers.LogLevel.Info, Client); + return false; + + } + + public bool RequestProvisionAccount() + { + return RequestVoiceInternal("RequestProvisionAccount", ProvisionCapsResponse, "ProvisionVoiceAccountRequest"); + } + + public bool RequestParcelVoiceInfo() + { + return RequestVoiceInternal("RequestParcelVoiceInfo", ParcelVoiceInfoResponse, "ParcelVoiceInfoRequest"); + } + + public int RequestLogin(string accountName, string password, string connectorHandle) + { + if (_DaemonPipe.Connected) + { + StringBuilder request = new StringBuilder(); + request.Append(String.Format("", _CommandCookie++)); + request.Append(String.Format("{0}", connectorHandle)); + request.Append(String.Format("{0}", accountName)); + request.Append(String.Format("{0}", password)); + request.Append("VerifyAnswer"); + request.Append(""); + request.Append("10"); + request.Append("false"); + request.Append(""); + request.Append(REQUEST_TERMINATOR); + + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(request.ToString())); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.Login() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + public int RequestSetRenderDevice(string deviceName) + { + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}{2}", + _CommandCookie, deviceName, REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestSetRenderDevice() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + public int RequestStartTuningMode(int duration) + { + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}{2}", + _CommandCookie, duration, REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestStartTuningMode() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + public int RequestStopTuningMode() + { + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}", + _CommandCookie, REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestStopTuningMode() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return _CommandCookie - 1; + } + } + + public int RequestSetSpeakerVolume(int volume) + { + if (volume < 0 || volume > 100) + throw new ArgumentException("volume must be between 0 and 100", "volume"); + + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}{2}", + _CommandCookie, volume, REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestSetSpeakerVolume() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + public int RequestSetCaptureVolume(int volume) + { + if (volume < 0 || volume > 100) + throw new ArgumentException("volume must be between 0 and 100", "volume"); + + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}{2}", + _CommandCookie, volume, REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestSetCaptureVolume() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + /// + /// Does not appear to be working + /// + /// + /// + public int RequestRenderAudioStart(string fileName, bool loop) + { + if (_DaemonPipe.Connected) + { + _TuningSoundFile = fileName; + + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}{2}{3}", + _CommandCookie++, _TuningSoundFile, (loop ? "1" : "0"), REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestRenderAudioStart() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + public int RequestRenderAudioStop() + { + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format( + "{1}{2}", + _CommandCookie++, _TuningSoundFile, REQUEST_TERMINATOR))); + + return _CommandCookie - 1; + } + else + { + Logger.Log("VoiceManager.RequestRenderAudioStop() called when the daemon pipe is disconnected", Helpers.LogLevel.Error, Client); + return -1; + } + } + + #region Callbacks + + private void RequiredVoiceVersionEventHandler(string capsKey, IMessage message, Simulator simulator) + { + RequiredVoiceVersionMessage msg = (RequiredVoiceVersionMessage)message; + + if (VOICE_MAJOR_VERSION != msg.MajorVersion) + { + Logger.Log(String.Format("Voice version mismatch! Got {0}, expecting {1}. Disabling the voice manager", + msg.MajorVersion, VOICE_MAJOR_VERSION), Helpers.LogLevel.Error, Client); + Enabled = false; + } + else + { + Logger.DebugLog("Voice version " + msg.MajorVersion + " verified", Client); + } + } + + private void ProvisionCapsResponse(CapsClient client, OSD response, Exception error) + { + if (response is OSDMap) + { + OSDMap respTable = (OSDMap)response; + + if (OnProvisionAccount != null) + { + try { OnProvisionAccount(respTable["username"].AsString(), respTable["password"].AsString()); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + } + + private void ParcelVoiceInfoResponse(CapsClient client, OSD response, Exception error) + { + if (response is OSDMap) + { + OSDMap respTable = (OSDMap)response; + + string regionName = respTable["region_name"].AsString(); + int localID = (int)respTable["parcel_local_id"].AsInteger(); + + string channelURI = null; + if (respTable["voice_credentials"] is OSDMap) + { + OSDMap creds = (OSDMap)respTable["voice_credentials"]; + channelURI = creds["channel_uri"].AsString(); + } + + if (OnParcelVoiceInfo != null) OnParcelVoiceInfo(regionName, localID, channelURI); + } + } + + private void _DaemonPipe_OnDisconnected(SocketException se) + { + if (se != null) Console.WriteLine("Disconnected! " + se.Message); + else Console.WriteLine("Disconnected!"); + } + + private void _DaemonPipe_OnReceiveLine(string line) + { + XmlTextReader reader = new XmlTextReader(new StringReader(line)); + + while (reader.Read()) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + { + if (reader.Depth == 0) + { + isEvent = (reader.Name == "Event"); + + if (isEvent || reader.Name == "Response") + { + for (int i = 0; i < reader.AttributeCount; i++) + { + reader.MoveToAttribute(i); + + switch (reader.Name) + { +// case "requestId": +// uuidString = reader.Value; +// break; + case "action": + actionString = reader.Value; + break; + case "type": + eventTypeString = reader.Value; + break; + } + } + } + } + else + { + switch (reader.Name) + { + case "InputXml": + cookie = -1; + + // Parse through here to get the cookie value + reader.Read(); + if (reader.Name == "Request") + { + for (int i = 0; i < reader.AttributeCount; i++) + { + reader.MoveToAttribute(i); + + if (reader.Name == "requestId") + { + Int32.TryParse(reader.Value, out cookie); + break; + } + } + } + + if (cookie == -1) + { + Logger.Log("VoiceManager._DaemonPipe_OnReceiveLine(): Failed to parse InputXml for the cookie", + Helpers.LogLevel.Warning, Client); + } + break; + case "CaptureDevices": + _CaptureDevices.Clear(); + break; + case "RenderDevices": + _RenderDevices.Clear(); + break; +// case "ReturnCode": +// returnCode = reader.ReadElementContentAsInt(); +// break; + case "StatusCode": + statusCode = reader.ReadElementContentAsInt(); + break; + case "StatusString": + statusString = reader.ReadElementContentAsString(); + break; + case "State": + state = reader.ReadElementContentAsInt(); + break; + case "ConnectorHandle": + connectorHandle = reader.ReadElementContentAsString(); + break; + case "AccountHandle": + accountHandle = reader.ReadElementContentAsString(); + break; + case "SessionHandle": + sessionHandle = reader.ReadElementContentAsString(); + break; + case "URI": + uriString = reader.ReadElementContentAsString(); + break; + case "IsChannel": + isChannel = reader.ReadElementContentAsBoolean(); + break; + case "Name": + nameString = reader.ReadElementContentAsString(); + break; +// case "AudioMedia": +// audioMediaString = reader.ReadElementContentAsString(); +// break; + case "ChannelName": + nameString = reader.ReadElementContentAsString(); + break; + case "ParticipantURI": + uriString = reader.ReadElementContentAsString(); + break; + case "DisplayName": + displayNameString = reader.ReadElementContentAsString(); + break; + case "AccountName": + nameString = reader.ReadElementContentAsString(); + break; + case "ParticipantType": + participantType = reader.ReadElementContentAsInt(); + break; + case "IsLocallyMuted": + isLocallyMuted = reader.ReadElementContentAsBoolean(); + break; + case "IsModeratorMuted": + isModeratorMuted = reader.ReadElementContentAsBoolean(); + break; + case "IsSpeaking": + isSpeaking = reader.ReadElementContentAsBoolean(); + break; + case "Volume": + volume = reader.ReadElementContentAsInt(); + break; + case "Energy": + energy = reader.ReadElementContentAsFloat(); + break; + case "MicEnergy": + energy = reader.ReadElementContentAsFloat(); + break; + case "ChannelURI": + uriString = reader.ReadElementContentAsString(); + break; + case "ChannelListResult": + _ChannelMap[nameString] = uriString; + break; + case "CaptureDevice": + reader.Read(); + _CaptureDevices.Add(reader.ReadElementContentAsString()); + break; + case "CurrentCaptureDevice": + reader.Read(); + nameString = reader.ReadElementContentAsString(); + break; + case "RenderDevice": + reader.Read(); + _RenderDevices.Add(reader.ReadElementContentAsString()); + break; + case "CurrentRenderDevice": + reader.Read(); + nameString = reader.ReadElementContentAsString(); + break; + } + } + + break; + } + case XmlNodeType.EndElement: + if (reader.Depth == 0) + ProcessEvent(); + break; + } + } + + if (isEvent) + { + } + + //Client.DebugLog("VOICE: " + line); + } + + private void ProcessEvent() + { + if (isEvent) + { + switch (eventTypeString) + { + case "LoginStateChangeEvent": + if (OnLoginStateChange != null) OnLoginStateChange(cookie, accountHandle, statusCode, statusString, state); + break; + case "SessionNewEvent": + if (OnNewSession != null) OnNewSession(cookie, accountHandle, eventSessionHandle, state, nameString, uriString); + break; + case "SessionStateChangeEvent": + if (OnSessionStateChange != null) OnSessionStateChange(cookie, uriString, statusCode, statusString, eventSessionHandle, state, isChannel, nameString); + break; + case "ParticipantStateChangeEvent": + if (OnParticipantStateChange != null) OnParticipantStateChange(cookie, uriString, statusCode, statusString, state, nameString, displayNameString, participantType); + break; + case "ParticipantPropertiesEvent": + if (OnParticipantProperties != null) OnParticipantProperties(cookie, uriString, statusCode, statusString, isLocallyMuted, isModeratorMuted, isSpeaking, volume, energy); + break; + case "AuxAudioPropertiesEvent": + if (OnAuxAudioProperties != null) OnAuxAudioProperties(cookie, energy); + break; + } + } + else + { + switch (actionString) + { + case "Connector.Create.1": + if (OnConnectorCreated != null) OnConnectorCreated(cookie, statusCode, statusString, connectorHandle); + break; + case "Account.Login.1": + if (OnLogin != null) OnLogin(cookie, statusCode, statusString, accountHandle); + break; + case "Session.Create.1": + if (OnSessionCreated != null) OnSessionCreated(cookie, statusCode, statusString, sessionHandle); + break; + case "Session.Connect.1": + if (OnSessionConnected != null) OnSessionConnected(cookie, statusCode, statusString); + break; + case "Session.Terminate.1": + if (OnSessionTerminated != null) OnSessionTerminated(cookie, statusCode, statusString); + break; + case "Account.Logout.1": + if (OnAccountLogout != null) OnAccountLogout(cookie, statusCode, statusString); + break; + case "Connector.InitiateShutdown.1": + if (OnConnectorInitiateShutdown != null) OnConnectorInitiateShutdown(cookie, statusCode, statusString); + break; + case "Account.ChannelGetList.1": + if (OnAccountChannelGetList != null) OnAccountChannelGetList(cookie, statusCode, statusString); + break; + case "Aux.GetCaptureDevices.1": + if (OnCaptureDevices != null) OnCaptureDevices(cookie, statusCode, statusString, nameString); + break; + case "Aux.GetRenderDevices.1": + if (OnRenderDevices != null) OnRenderDevices(cookie, statusCode, statusString, nameString); + break; + } + } + } + + #endregion Callbacks + } +} diff --git a/OpenMetaverse.Utilities/VoiceManagerBlocking.cs b/OpenMetaverse.Utilities/VoiceManagerBlocking.cs new file mode 100644 index 0000000..93723c9 --- /dev/null +++ b/OpenMetaverse.Utilities/VoiceManagerBlocking.cs @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.Utilities +{ + public partial class VoiceManager + { + /// Amount of time to wait for the voice daemon to respond. + /// The value needs to stay relatively high because some of the calls + /// require the voice daemon to make remote queries before replying + public int BlockingTimeout = 30 * 1000; + + protected Dictionary Events = new Dictionary(); + + public List CaptureDevices() + { + AutoResetEvent evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestCaptureDevices() == -1) + { + Events.Remove(_CommandCookie); + return new List(); + } + + if (evt.WaitOne(BlockingTimeout, false)) + return CurrentCaptureDevices(); + else + return new List(); + } + + public List RenderDevices() + { + AutoResetEvent evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestRenderDevices() == -1) + { + Events.Remove(_CommandCookie); + return new List(); + } + + if (evt.WaitOne(BlockingTimeout, false)) + return CurrentRenderDevices(); + else + return new List(); + } + + public string CreateConnector(out int status) + { + status = 0; + + AutoResetEvent evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestCreateConnector() == -1) + { + Events.Remove(_CommandCookie); + return String.Empty; + } + + bool success = evt.WaitOne(BlockingTimeout, false); + status = statusCode; + + if (success && statusCode == 0) + return connectorHandle; + else + return String.Empty; + } + + public string Login(string accountName, string password, string connectorHandle, out int status) + { + status = 0; + + AutoResetEvent evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestLogin(accountName, password, connectorHandle) == -1) + { + Events.Remove(_CommandCookie); + return String.Empty; + } + + bool success = evt.WaitOne(BlockingTimeout, false); + status = statusCode; + + if (success && statusCode == 0) + return accountHandle; + else + return String.Empty; + } + + protected void RegisterCallbacks() + { + OnCaptureDevices += new DevicesCallback(VoiceManager_OnCaptureDevices); + OnRenderDevices += new DevicesCallback(VoiceManager_OnRenderDevices); + OnConnectorCreated += new ConnectorCreatedCallback(VoiceManager_OnConnectorCreated); + OnLogin += new LoginCallback(VoiceManager_OnLogin); + } + + #region Callbacks + + private void VoiceManager_OnCaptureDevices(int cookie, int statusCode, string statusString, string currentDevice) + { + if (Events.ContainsKey(cookie)) + Events[cookie].Set(); + } + + private void VoiceManager_OnRenderDevices(int cookie, int statusCode, string statusString, string currentDevice) + { + if (Events.ContainsKey(cookie)) + Events[cookie].Set(); + } + + private void VoiceManager_OnConnectorCreated(int cookie, int statusCode, string statusString, string connectorHandle) + { + if (Events.ContainsKey(cookie)) + Events[cookie].Set(); + } + + private void VoiceManager_OnLogin(int cookie, int statusCode, string statusString, string accountHandle) + { + if (Events.ContainsKey(cookie)) + Events[cookie].Set(); + } + + #endregion Callbacks + } +} \ No newline at end of file diff --git a/OpenMetaverse/AgentManager.cs b/OpenMetaverse/AgentManager.cs new file mode 100644 index 0000000..960d223 --- /dev/null +++ b/OpenMetaverse/AgentManager.cs @@ -0,0 +1,5245 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Reflection; +using System.Collections.Generic; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; +using OpenMetaverse.Assets; +using OpenMetaverse.Packets; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// Permission request flags, asked when a script wants to control an Avatar + /// + [Flags] + public enum ScriptPermission : int + { + /// Placeholder for empty values, shouldn't ever see this + None = 0, + /// Script wants ability to take money from you + Debit = 1 << 1, + /// Script wants to take camera controls for you + TakeControls = 1 << 2, + /// Script wants to remap avatars controls + RemapControls = 1 << 3, + /// Script wants to trigger avatar animations + /// This function is not implemented on the grid + TriggerAnimation = 1 << 4, + /// Script wants to attach or detach the prim or primset to your avatar + Attach = 1 << 5, + /// Script wants permission to release ownership + /// This function is not implemented on the grid + /// The concept of "public" objects does not exist anymore. + ReleaseOwnership = 1 << 6, + /// Script wants ability to link/delink with other prims + ChangeLinks = 1 << 7, + /// Script wants permission to change joints + /// This function is not implemented on the grid + ChangeJoints = 1 << 8, + /// Script wants permissions to change permissions + /// This function is not implemented on the grid + ChangePermissions = 1 << 9, + /// Script wants to track avatars camera position and rotation + TrackCamera = 1 << 10, + /// Script wants to control your camera + ControlCamera = 1 << 11, + /// Script wants the ability to teleport you + Teleport = 1 << 12 + } + + /// + /// Special commands used in Instant Messages + /// + public enum InstantMessageDialog : byte + { + /// Indicates a regular IM from another agent + MessageFromAgent = 0, + /// Simple notification box with an OK button + MessageBox = 1, + // Used to show a countdown notification with an OK + // button, deprecated now + //[Obsolete] + //MessageBoxCountdown = 2, + /// You've been invited to join a group. + GroupInvitation = 3, + /// Inventory offer + InventoryOffered = 4, + /// Accepted inventory offer + InventoryAccepted = 5, + /// Declined inventory offer + InventoryDeclined = 6, + /// Group vote + GroupVote = 7, + // A message to everyone in the agent's group, no longer + // used + //[Obsolete] + //DeprecatedGroupMessage = 8, + /// An object is offering its inventory + TaskInventoryOffered = 9, + /// Accept an inventory offer from an object + TaskInventoryAccepted = 10, + /// Decline an inventory offer from an object + TaskInventoryDeclined = 11, + /// Unknown + NewUserDefault = 12, + /// Start a session, or add users to a session + SessionAdd = 13, + /// Start a session, but don't prune offline users + SessionOfflineAdd = 14, + /// Start a session with your group + SessionGroupStart = 15, + /// Start a session without a calling card (finder or objects) + SessionCardlessStart = 16, + /// Send a message to a session + SessionSend = 17, + /// Leave a session + SessionDrop = 18, + /// Indicates that the IM is from an object + MessageFromObject = 19, + /// Sent an IM to a busy user, this is the auto response + BusyAutoResponse = 20, + /// Shows the message in the console and chat history + ConsoleAndChatHistory = 21, + /// Send a teleport lure + RequestTeleport = 22, + /// Response sent to the agent which inititiated a teleport invitation + AcceptTeleport = 23, + /// Response sent to the agent which inititiated a teleport invitation + DenyTeleport = 24, + /// Only useful if you have Linden permissions + GodLikeRequestTeleport = 25, + /// Request a teleport lure + RequestLure = 26, + // Notification of a new group election, this is + // deprecated + //[Obsolete] + //DeprecatedGroupElection = 27, + /// IM to tell the user to go to an URL + GotoUrl = 28, + /// IM for help + Session911Start = 29, + /// IM sent automatically on call for help, sends a lure + /// to each Helper reached + Lure911 = 30, + /// Like an IM but won't go to email + FromTaskAsAlert = 31, + /// IM from a group officer to all group members + GroupNotice = 32, + /// Unknown + GroupNoticeInventoryAccepted = 33, + /// Unknown + GroupNoticeInventoryDeclined = 34, + /// Accept a group invitation + GroupInvitationAccept = 35, + /// Decline a group invitation + GroupInvitationDecline = 36, + /// Unknown + GroupNoticeRequested = 37, + /// An avatar is offering you friendship + FriendshipOffered = 38, + /// An avatar has accepted your friendship offer + FriendshipAccepted = 39, + /// An avatar has declined your friendship offer + FriendshipDeclined = 40, + /// Indicates that a user has started typing + StartTyping = 41, + /// Indicates that a user has stopped typing + StopTyping = 42 + } + + /// + /// Flag in Instant Messages, whether the IM should be delivered to + /// offline avatars as well + /// + public enum InstantMessageOnline + { + /// Only deliver to online avatars + Online = 0, + /// If the avatar is offline the message will be held until + /// they login next, and possibly forwarded to their e-mail account + Offline = 1 + } + + /// + /// Conversion type to denote Chat Packet types in an easier-to-understand format + /// + public enum ChatType : byte + { + /// Whisper (5m radius) + Whisper = 0, + /// Normal chat (10/20m radius), what the official viewer typically sends + Normal = 1, + /// Shouting! (100m radius) + Shout = 2, + // Say chat (10/20m radius) - The official viewer will + // print "[4:15] You say, hey" instead of "[4:15] You: hey" + //[Obsolete] + //Say = 3, + /// Event message when an Avatar has begun to type + StartTyping = 4, + /// Event message when an Avatar has stopped typing + StopTyping = 5, + /// Send the message to the debug channel + Debug = 6, + /// Event message when an object uses llOwnerSay + OwnerSay = 8, + /// Event message when an object uses llRegionSayTo + RegionSayTo = 9, + /// Special value to support llRegionSay, never sent to the client + RegionSay = Byte.MaxValue, + } + + /// + /// Identifies the source of a chat message + /// + public enum ChatSourceType : byte + { + /// Chat from the grid or simulator + System = 0, + /// Chat from another avatar + Agent = 1, + /// Chat from an object + Object = 2 + } + + /// + /// + /// + public enum ChatAudibleLevel : sbyte + { + /// + Not = -1, + /// + Barely = 0, + /// + Fully = 1 + } + + /// + /// Effect type used in ViewerEffect packets + /// + public enum EffectType : byte + { + /// + Text = 0, + /// + Icon, + /// + Connector, + /// + FlexibleObject, + /// + AnimalControls, + /// + AnimationObject, + /// + Cloth, + /// Project a beam from a source to a destination, such as + /// the one used when editing an object + Beam, + /// + Glow, + /// + Point, + /// + Trail, + /// Create a swirl of particles around an object + Sphere, + /// + Spiral, + /// + Edit, + /// Cause an avatar to look at an object + LookAt, + /// Cause an avatar to point at an object + PointAt + } + + /// + /// The action an avatar is doing when looking at something, used in + /// ViewerEffect packets for the LookAt effect + /// + public enum LookAtType : byte + { + /// + None, + /// + Idle, + /// + AutoListen, + /// + FreeLook, + /// + Respond, + /// + Hover, + /// Deprecated + [Obsolete] + Conversation, + /// + Select, + /// + Focus, + /// + Mouselook, + /// + Clear + } + + /// + /// The action an avatar is doing when pointing at something, used in + /// ViewerEffect packets for the PointAt effect + /// + public enum PointAtType : byte + { + /// + None, + /// + Select, + /// + Grab, + /// + Clear + } + + /// + /// Money transaction types + /// + public enum MoneyTransactionType : int + { + /// + None = 0, + /// + FailSimulatorTimeout = 1, + /// + FailDataserverTimeout = 2, + /// + ObjectClaim = 1000, + /// + LandClaim = 1001, + /// + GroupCreate = 1002, + /// + ObjectPublicClaim = 1003, + /// + GroupJoin = 1004, + /// + TeleportCharge = 1100, + /// + UploadCharge = 1101, + /// + LandAuction = 1102, + /// + ClassifiedCharge = 1103, + /// + ObjectTax = 2000, + /// + LandTax = 2001, + /// + LightTax = 2002, + /// + ParcelDirFee = 2003, + /// + GroupTax = 2004, + /// + ClassifiedRenew = 2005, + /// + GiveInventory = 3000, + /// + ObjectSale = 5000, + /// + Gift = 5001, + /// + LandSale = 5002, + /// + ReferBonus = 5003, + /// + InventorySale = 5004, + /// + RefundPurchase = 5005, + /// + LandPassSale = 5006, + /// + DwellBonus = 5007, + /// + PayObject = 5008, + /// + ObjectPays = 5009, + /// + GroupLandDeed = 6001, + /// + GroupObjectDeed = 6002, + /// + GroupLiability = 6003, + /// + GroupDividend = 6004, + /// + GroupMembershipDues = 6005, + /// + ObjectRelease = 8000, + /// + LandRelease = 8001, + /// + ObjectDelete = 8002, + /// + ObjectPublicDecay = 8003, + /// + ObjectPublicDelete = 8004, + /// + LindenAdjustment = 9000, + /// + LindenGrant = 9001, + /// + LindenPenalty = 9002, + /// + EventFee = 9003, + /// + EventPrize = 9004, + /// + StipendBasic = 10000, + /// + StipendDeveloper = 10001, + /// + StipendAlways = 10002, + /// + StipendDaily = 10003, + /// + StipendRating = 10004, + /// + StipendDelta = 10005 + } + /// + /// + /// + [Flags] + public enum TransactionFlags : byte + { + /// + None = 0, + /// + SourceGroup = 1, + /// + DestGroup = 2, + /// + OwnerGroup = 4, + /// + SimultaneousContribution = 8, + /// + ContributionRemoval = 16 + } + /// + /// + /// + public enum MeanCollisionType : byte + { + /// + None, + /// + Bump, + /// + LLPushObject, + /// + SelectedObjectCollide, + /// + ScriptedObjectCollide, + /// + PhysicalObjectCollide + } + + /// + /// Flags sent when a script takes or releases a control + /// + /// NOTE: (need to verify) These might be a subset of the ControlFlags enum in Movement, + [Flags] + public enum ScriptControlChange : uint + { + /// No Flags set + None = 0, + /// Forward (W or up Arrow) + Forward = 1, + /// Back (S or down arrow) + Back = 2, + /// Move left (shift+A or left arrow) + Left = 4, + /// Move right (shift+D or right arrow) + Right = 8, + /// Up (E or PgUp) + Up = 16, + /// Down (C or PgDown) + Down = 32, + /// Rotate left (A or left arrow) + RotateLeft = 256, + /// Rotate right (D or right arrow) + RotateRight = 512, + /// Left Mouse Button + LeftButton = 268435456, + /// Left Mouse button in MouseLook + MouseLookLeftButton = 1073741824 + } + + /// + /// Currently only used to hide your group title + /// + [Flags] + public enum AgentFlags : byte + { + /// No flags set + None = 0, + /// Hide your group title + HideTitle = 0x01, + } + + /// + /// Action state of the avatar, which can currently be typing and + /// editing + /// + [Flags] + public enum AgentState : byte + { + /// + None = 0x00, + /// + Typing = 0x04, + /// + Editing = 0x10 + } + + /// + /// Current teleport status + /// + public enum TeleportStatus + { + /// Unknown status + None, + /// Teleport initialized + Start, + /// Teleport in progress + Progress, + /// Teleport failed + Failed, + /// Teleport completed + Finished, + /// Teleport cancelled + Cancelled + } + + /// + /// + /// + [Flags] + public enum TeleportFlags : uint + { + /// No flags set, or teleport failed + Default = 0, + /// Set when newbie leaves help island for first time + SetHomeToTarget = 1 << 0, + /// + SetLastToTarget = 1 << 1, + /// Via Lure + ViaLure = 1 << 2, + /// Via Landmark + ViaLandmark = 1 << 3, + /// Via Location + ViaLocation = 1 << 4, + /// Via Home + ViaHome = 1 << 5, + /// Via Telehub + ViaTelehub = 1 << 6, + /// Via Login + ViaLogin = 1 << 7, + /// Linden Summoned + ViaGodlikeLure = 1 << 8, + /// Linden Forced me + Godlike = 1 << 9, + /// + NineOneOne = 1 << 10, + /// Agent Teleported Home via Script + DisableCancel = 1 << 11, + /// + ViaRegionID = 1 << 12, + /// + IsFlying = 1 << 13, + /// + ResetHome = 1 << 14, + /// forced to new location for example when avatar is banned or ejected + ForceRedirect = 1 << 15, + /// Teleport Finished via a Lure + FinishedViaLure = 1 << 26, + /// Finished, Sim Changed + FinishedViaNewSim = 1 << 28, + /// Finished, Same Sim + FinishedViaSameSim = 1 << 29 + } + + /// + /// + /// + [Flags] + public enum TeleportLureFlags + { + /// + NormalLure = 0, + /// + GodlikeLure = 1, + /// + GodlikePursuit = 2 + } + + /// + /// + /// + [Flags] + public enum ScriptSensorTypeFlags + { + /// + Agent = 1, + /// + Active = 2, + /// + Passive = 4, + /// + Scripted = 8, + } + + /// + /// Type of mute entry + /// + public enum MuteType + { + /// Object muted by name + ByName = 0, + /// Muted residet + Resident = 1, + /// Object muted by UUID + Object = 2, + /// Muted group + Group = 3, + /// Muted external entry + External = 4 + } + + /// + /// Flags of mute entry + /// + [Flags] + public enum MuteFlags : int + { + /// No exceptions + Default = 0x0, + /// Don't mute text chat + TextChat = 0x1, + /// Don't mute voice chat + VoiceChat = 0x2, + /// Don't mute particles + Particles = 0x4, + /// Don't mute sounds + ObjectSounds = 0x8, + /// Don't mute + All = 0xf + } + #endregion Enums + + #region Structs + + /// + /// Instant Message + /// + public struct InstantMessage + { + /// Key of sender + public UUID FromAgentID; + /// Name of sender + public string FromAgentName; + /// Key of destination avatar + public UUID ToAgentID; + /// ID of originating estate + public uint ParentEstateID; + /// Key of originating region + public UUID RegionID; + /// Coordinates in originating region + public Vector3 Position; + /// Instant message type + public InstantMessageDialog Dialog; + /// Group IM session toggle + public bool GroupIM; + /// Key of IM session, for Group Messages, the groups UUID + public UUID IMSessionID; + /// Timestamp of the instant message + public DateTime Timestamp; + /// Instant message text + public string Message; + /// Whether this message is held for offline avatars + public InstantMessageOnline Offline; + /// Context specific packed data + public byte[] BinaryBucket; + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// Represents muted object or resident + public class MuteEntry + { + /// Type of the mute entry + public MuteType Type; + /// UUID of the mute etnry + public UUID ID; + /// Mute entry name + public string Name; + /// Mute flags + public MuteFlags Flags; + } + + /// Transaction detail sent with MoneyBalanceReply message + public class TransactionInfo + { + /// Type of the transaction + public int TransactionType; // FIXME: this should be an enum + /// UUID of the transaction source + public UUID SourceID; + /// Is the transaction source a group + public bool IsSourceGroup; + /// UUID of the transaction destination + public UUID DestID; + /// Is transaction destination a group + public bool IsDestGroup; + /// Transaction amount + public int Amount; + /// Transaction description + public string ItemDescription; + } + #endregion Structs + + /// + /// Manager class for our own avatar + /// + public partial class AgentManager + { + #region Delegates + /// + /// Called once attachment resource usage information has been collected + /// + /// Indicates if operation was successfull + /// Attachment resource usage information + public delegate void AttachmentResourcesCallback(bool success, AttachmentResourcesMessage info); + #endregion Delegates + + #region Event Delegates + + /// The event subscribers. null if no subcribers + private EventHandler m_Chat; + + /// Raises the ChatFromSimulator event + /// A ChatEventArgs object containing the + /// data returned from the data server + protected virtual void OnChat(ChatEventArgs e) + { + EventHandler handler = m_Chat; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ChatLock = new object(); + + /// Raised when a scripted object or agent within range sends a public message + public event EventHandler ChatFromSimulator + { + add { lock (m_ChatLock) { m_Chat += value; } } + remove { lock (m_ChatLock) { m_Chat -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ScriptDialog; + + /// Raises the ScriptDialog event + /// A SctriptDialogEventArgs object containing the + /// data returned from the data server + protected virtual void OnScriptDialog(ScriptDialogEventArgs e) + { + EventHandler handler = m_ScriptDialog; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ScriptDialogLock = new object(); + /// Raised when a scripted object sends a dialog box containing possible + /// options an agent can respond to + public event EventHandler ScriptDialog + { + add { lock (m_ScriptDialogLock) { m_ScriptDialog += value; } } + remove { lock (m_ScriptDialogLock) { m_ScriptDialog -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ScriptQuestion; + + /// Raises the ScriptQuestion event + /// A ScriptQuestionEventArgs object containing the + /// data returned from the data server + protected virtual void OnScriptQuestion(ScriptQuestionEventArgs e) + { + EventHandler handler = m_ScriptQuestion; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ScriptQuestionLock = new object(); + /// Raised when an object requests a change in the permissions an agent has permitted + public event EventHandler ScriptQuestion + { + add { lock (m_ScriptQuestionLock) { m_ScriptQuestion += value; } } + remove { lock (m_ScriptQuestionLock) { m_ScriptQuestion -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_LoadURL; + + /// Raises the LoadURL event + /// A LoadUrlEventArgs object containing the + /// data returned from the data server + protected virtual void OnLoadURL(LoadUrlEventArgs e) + { + EventHandler handler = m_LoadURL; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_LoadUrlLock = new object(); + /// Raised when a script requests an agent open the specified URL + public event EventHandler LoadURL + { + add { lock (m_LoadUrlLock) { m_LoadURL += value; } } + remove { lock (m_LoadUrlLock) { m_LoadURL -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_Balance; + + /// Raises the MoneyBalance event + /// A BalanceEventArgs object containing the + /// data returned from the data server + protected virtual void OnBalance(BalanceEventArgs e) + { + EventHandler handler = m_Balance; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_BalanceLock = new object(); + + /// Raised when an agents currency balance is updated + public event EventHandler MoneyBalance + { + add { lock (m_BalanceLock) { m_Balance += value; } } + remove { lock (m_BalanceLock) { m_Balance -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_MoneyBalance; + + /// Raises the MoneyBalanceReply event + /// A MoneyBalanceReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnMoneyBalanceReply(MoneyBalanceReplyEventArgs e) + { + EventHandler handler = m_MoneyBalance; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_MoneyBalanceReplyLock = new object(); + + /// Raised when a transaction occurs involving currency such as a land purchase + public event EventHandler MoneyBalanceReply + { + add { lock (m_MoneyBalanceReplyLock) { m_MoneyBalance += value; } } + remove { lock (m_MoneyBalanceReplyLock) { m_MoneyBalance -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_InstantMessage; + + /// Raises the IM event + /// A InstantMessageEventArgs object containing the + /// data returned from the data server + protected virtual void OnInstantMessage(InstantMessageEventArgs e) + { + EventHandler handler = m_InstantMessage; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InstantMessageLock = new object(); + /// Raised when an ImprovedInstantMessage packet is recieved from the simulator, this is used for everything from + /// private messaging to friendship offers. The Dialog field defines what type of message has arrived + public event EventHandler IM + { + add { lock (m_InstantMessageLock) { m_InstantMessage += value; } } + remove { lock (m_InstantMessageLock) { m_InstantMessage -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_Teleport; + + /// Raises the TeleportProgress event + /// A TeleportEventArgs object containing the + /// data returned from the data server + protected virtual void OnTeleport(TeleportEventArgs e) + { + EventHandler handler = m_Teleport; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TeleportLock = new object(); + /// Raised when an agent has requested a teleport to another location, or when responding to a lure. Raised multiple times + /// for each teleport indicating the progress of the request + public event EventHandler TeleportProgress + { + add { lock (m_TeleportLock) { m_Teleport += value; } } + remove { lock (m_TeleportLock) { m_Teleport += value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_AgentData; + + /// Raises the AgentDataReply event + /// A AgentDataReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnAgentData(AgentDataReplyEventArgs e) + { + EventHandler handler = m_AgentData; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AgentDataLock = new object(); + + /// Raised when a simulator sends agent specific information for our avatar. + public event EventHandler AgentDataReply + { + add { lock (m_AgentDataLock) { m_AgentData += value; } } + remove { lock (m_AgentDataLock) { m_AgentData -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_AnimationsChanged; + + /// Raises the AnimationsChanged event + /// A AnimationsChangedEventArgs object containing the + /// data returned from the data server + protected virtual void OnAnimationsChanged(AnimationsChangedEventArgs e) + { + EventHandler handler = m_AnimationsChanged; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AnimationsChangedLock = new object(); + + /// Raised when our agents animation playlist changes + public event EventHandler AnimationsChanged + { + add { lock (m_AnimationsChangedLock) { m_AnimationsChanged += value; } } + remove { lock (m_AnimationsChangedLock) { m_AnimationsChanged -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_MeanCollision; + + /// Raises the MeanCollision event + /// A MeanCollisionEventArgs object containing the + /// data returned from the data server + protected virtual void OnMeanCollision(MeanCollisionEventArgs e) + { + EventHandler handler = m_MeanCollision; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_MeanCollisionLock = new object(); + + /// Raised when an object or avatar forcefully collides with our agent + public event EventHandler MeanCollision + { + add { lock (m_MeanCollisionLock) { m_MeanCollision += value; } } + remove { lock (m_MeanCollisionLock) { m_MeanCollision -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_RegionCrossed; + + /// Raises the RegionCrossed event + /// A RegionCrossedEventArgs object containing the + /// data returned from the data server + protected virtual void OnRegionCrossed(RegionCrossedEventArgs e) + { + EventHandler handler = m_RegionCrossed; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_RegionCrossedLock = new object(); + + /// Raised when our agent crosses a region border into another region + public event EventHandler RegionCrossed + { + add { lock (m_RegionCrossedLock) { m_RegionCrossed += value; } } + remove { lock (m_RegionCrossedLock) { m_RegionCrossed -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupChatJoined; + + /// Raises the GroupChatJoined event + /// A GroupChatJoinedEventArgs object containing the + /// data returned from the data server + protected virtual void OnGroupChatJoined(GroupChatJoinedEventArgs e) + { + EventHandler handler = m_GroupChatJoined; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupChatJoinedLock = new object(); + + /// Raised when our agent succeeds or fails to join a group chat session + public event EventHandler GroupChatJoined + { + add { lock (m_GroupChatJoinedLock) { m_GroupChatJoined += value; } } + remove { lock (m_GroupChatJoinedLock) { m_GroupChatJoined -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_AlertMessage; + + /// Raises the AlertMessage event + /// A AlertMessageEventArgs object containing the + /// data returned from the data server + protected virtual void OnAlertMessage(AlertMessageEventArgs e) + { + EventHandler handler = m_AlertMessage; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AlertMessageLock = new object(); + + /// Raised when a simulator sends an urgent message usually indication the recent failure of + /// another action we have attempted to take such as an attempt to enter a parcel where we are denied access + public event EventHandler AlertMessage + { + add { lock (m_AlertMessageLock) { m_AlertMessage += value; } } + remove { lock (m_AlertMessageLock) { m_AlertMessage -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ScriptControl; + + /// Raises the ScriptControlChange event + /// A ScriptControlEventArgs object containing the + /// data returned from the data server + protected virtual void OnScriptControlChange(ScriptControlEventArgs e) + { + EventHandler handler = m_ScriptControl; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ScriptControlLock = new object(); + + /// Raised when a script attempts to take or release specified controls for our agent + public event EventHandler ScriptControlChange + { + add { lock (m_ScriptControlLock) { m_ScriptControl += value; } } + remove { lock (m_ScriptControlLock) { m_ScriptControl -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_CameraConstraint; + + /// Raises the CameraConstraint event + /// A CameraConstraintEventArgs object containing the + /// data returned from the data server + protected virtual void OnCameraConstraint(CameraConstraintEventArgs e) + { + EventHandler handler = m_CameraConstraint; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_CameraConstraintLock = new object(); + + /// Raised when the simulator detects our agent is trying to view something + /// beyond its limits + public event EventHandler CameraConstraint + { + add { lock (m_CameraConstraintLock) { m_CameraConstraint += value; } } + remove { lock (m_CameraConstraintLock) { m_CameraConstraint -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ScriptSensorReply; + + /// Raises the ScriptSensorReply event + /// A ScriptSensorReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnScriptSensorReply(ScriptSensorReplyEventArgs e) + { + EventHandler handler = m_ScriptSensorReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ScriptSensorReplyLock = new object(); + + /// Raised when a script sensor reply is received from a simulator + public event EventHandler ScriptSensorReply + { + add { lock (m_ScriptSensorReplyLock) { m_ScriptSensorReply += value; } } + remove { lock (m_ScriptSensorReplyLock) { m_ScriptSensorReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_AvatarSitResponse; + + /// Raises the AvatarSitResponse event + /// A AvatarSitResponseEventArgs object containing the + /// data returned from the data server + protected virtual void OnAvatarSitResponse(AvatarSitResponseEventArgs e) + { + EventHandler handler = m_AvatarSitResponse; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarSitResponseLock = new object(); + + /// Raised in response to a request + public event EventHandler AvatarSitResponse + { + add { lock (m_AvatarSitResponseLock) { m_AvatarSitResponse += value; } } + remove { lock (m_AvatarSitResponseLock) { m_AvatarSitResponse -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ChatSessionMemberAdded; + + /// Raises the ChatSessionMemberAdded event + /// A ChatSessionMemberAddedEventArgs object containing the + /// data returned from the data server + protected virtual void OnChatSessionMemberAdded(ChatSessionMemberAddedEventArgs e) + { + EventHandler handler = m_ChatSessionMemberAdded; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ChatSessionMemberAddedLock = new object(); + + /// Raised when an avatar enters a group chat session we are participating in + public event EventHandler ChatSessionMemberAdded + { + add { lock (m_ChatSessionMemberAddedLock) { m_ChatSessionMemberAdded += value; } } + remove { lock (m_ChatSessionMemberAddedLock) { m_ChatSessionMemberAdded -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ChatSessionMemberLeft; + + /// Raises the ChatSessionMemberLeft event + /// A ChatSessionMemberLeftEventArgs object containing the + /// data returned from the data server + protected virtual void OnChatSessionMemberLeft(ChatSessionMemberLeftEventArgs e) + { + EventHandler handler = m_ChatSessionMemberLeft; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ChatSessionMemberLeftLock = new object(); + + /// Raised when an agent exits a group chat session we are participating in + public event EventHandler ChatSessionMemberLeft + { + add { lock (m_ChatSessionMemberLeftLock) { m_ChatSessionMemberLeft += value; } } + remove { lock (m_ChatSessionMemberLeftLock) { m_ChatSessionMemberLeft -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_SetDisplayNameReply; + + ///Raises the SetDisplayNameReply Event + /// A SetDisplayNameReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSetDisplayNameReply(SetDisplayNameReplyEventArgs e) + { + EventHandler handler = m_SetDisplayNameReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SetDisplayNameReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the details of display name change + public event EventHandler SetDisplayNameReply + { + add { lock (m_SetDisplayNameReplyLock) { m_SetDisplayNameReply += value; } } + remove { lock (m_SetDisplayNameReplyLock) { m_SetDisplayNameReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_MuteListUpdated; + + /// Raises the MuteListUpdated event + /// A EventArgs object containing the + /// data returned from the data server + protected virtual void OnMuteListUpdated(EventArgs e) + { + EventHandler handler = m_MuteListUpdated; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_MuteListUpdatedLock = new object(); + + /// Raised when a scripted object or agent within range sends a public message + public event EventHandler MuteListUpdated + { + add { lock (m_MuteListUpdatedLock) { m_MuteListUpdated += value; } } + remove { lock (m_MuteListUpdatedLock) { m_MuteListUpdated -= value; } } + } + #endregion Callbacks + + /// Reference to the GridClient instance + private readonly GridClient Client; + /// Used for movement and camera tracking + public readonly AgentMovement Movement; + /// Currently playing animations for the agent. Can be used to + /// check the current movement status such as walking, hovering, aiming, + /// etc. by checking against system animations found in the Animations class + public InternalDictionary SignaledAnimations = new InternalDictionary(); + /// Dictionary containing current Group Chat sessions and members + public InternalDictionary> GroupChatSessions = new InternalDictionary>(); + /// Dictionary containing mute list keyead on mute name and key + public InternalDictionary MuteList = new InternalDictionary(); + + #region Properties + + /// Your (client) avatars + /// "client", "agent", and "avatar" all represent the same thing + public UUID AgentID { get { return id; } } + /// Temporary assigned to this session, used for + /// verifying our identity in packets + public UUID SessionID { get { return sessionID; } } + /// Shared secret that is never sent over the wire + public UUID SecureSessionID { get { return secureSessionID; } } + /// Your (client) avatar ID, local to the current region/sim + public uint LocalID { get { return localID; } } + /// Where the avatar started at login. Can be "last", "home" + /// or a login + public string StartLocation { get { return startLocation; } } + /// The access level of this agent, usually M, PG or A + public string AgentAccess { get { return agentAccess; } } + /// The CollisionPlane of Agent + public Vector4 CollisionPlane { get { return collisionPlane; } } + /// An representing the velocity of our agent + public Vector3 Velocity { get { return velocity; } } + /// An representing the acceleration of our agent + public Vector3 Acceleration { get { return acceleration; } } + /// A which specifies the angular speed, and axis about which an Avatar is rotating. + public Vector3 AngularVelocity { get { return angularVelocity; } } + /// Position avatar client will goto when login to 'home' or during + /// teleport request to 'home' region. + public Vector3 HomePosition { get { return homePosition; } } + /// LookAt point saved/restored with HomePosition + public Vector3 HomeLookAt { get { return homeLookAt; } } + /// Avatar First Name (i.e. Philip) + public string FirstName { get { return firstName; } } + /// Avatar Last Name (i.e. Linden) + public string LastName { get { return lastName; } } + /// LookAt point received with the login response message + public Vector3 LookAt { get { return lookAt; } } + /// Avatar Full Name (i.e. Philip Linden) + public string Name + { + get + { + // This is a fairly common request, so assume the name doesn't + // change mid-session and cache the result + if (fullName == null || fullName.Length < 2) + fullName = String.Format("{0} {1}", firstName, lastName); + return fullName; + } + } + /// Gets the health of the agent + public float Health { get { return health; } } + /// Gets the current balance of the agent + public int Balance { get { return balance; } } + /// Gets the local ID of the prim the agent is sitting on, + /// zero if the avatar is not currently sitting + public uint SittingOn { get { return sittingOn; } } + /// Gets the of the agents active group. + public UUID ActiveGroup { get { return activeGroup; } } + /// Gets the Agents powers in the currently active group + public GroupPowers ActiveGroupPowers { get { return activeGroupPowers; } } + /// Current status message for teleporting + public string TeleportMessage { get { return teleportMessage; } } + /// Current position of the agent as a relative offset from + /// the simulator, or the parent object if we are sitting on something + public Vector3 RelativePosition { get { return relativePosition; } set { relativePosition = value; } } + /// Current rotation of the agent as a relative rotation from + /// the simulator, or the parent object if we are sitting on something + public Quaternion RelativeRotation { get { return relativeRotation; } set { relativeRotation = value; } } + /// Current position of the agent in the simulator + public Vector3 SimPosition + { + get + { + // simple case, agent not seated + if (sittingOn == 0) + { + return relativePosition; + } + + // a bit more complicatated, agent sitting on a prim + Primitive p = null; + Vector3 fullPosition = relativePosition; + + if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(sittingOn, out p)) + { + fullPosition = p.Position + relativePosition * p.Rotation; + } + + // go up the hiearchy trying to find the root prim + while (p != null && p.ParentID != 0) + { + Avatar av; + if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(p.ParentID, out av)) + { + p = av; + fullPosition += p.Position; + } + else + { + if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(p.ParentID, out p)) + { + fullPosition += p.Position; + } + } + } + + if (p != null) // we found the root prim + { + return fullPosition; + } + + // Didn't find the seat's root prim, try returning coarse loaction + if (Client.Network.CurrentSim.avatarPositions.TryGetValue(AgentID, out fullPosition)) + { + return fullPosition; + } + + Logger.Log("Failed to determine agents sim position", Helpers.LogLevel.Warning, Client); + return relativePosition; + } + } + /// + /// A representing the agents current rotation + /// + public Quaternion SimRotation + { + get + { + if (sittingOn != 0) + { + Primitive parent; + if (Client.Network.CurrentSim != null && Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(sittingOn, out parent)) + { + return relativeRotation * parent.Rotation; + } + else + { + Logger.Log("Currently sitting on object " + sittingOn + " which is not tracked, SimRotation will be inaccurate", + Helpers.LogLevel.Warning, Client); + return relativeRotation; + } + } + else + { + return relativeRotation; + } + } + } + /// Returns the global grid position of the avatar + public Vector3d GlobalPosition + { + get + { + if (Client.Network.CurrentSim != null) + { + uint globalX, globalY; + Utils.LongToUInts(Client.Network.CurrentSim.Handle, out globalX, out globalY); + Vector3 pos = SimPosition; + + return new Vector3d( + (double)globalX + (double)pos.X, + (double)globalY + (double)pos.Y, + (double)pos.Z); + } + else + return Vector3d.Zero; + } + } + + /// Various abilities and preferences sent by the grid + public AgentStateUpdateMessage AgentStateStatus; + + #endregion Properties + + internal uint localID; + internal Vector3 relativePosition; + internal Quaternion relativeRotation = Quaternion.Identity; + internal Vector4 collisionPlane; + internal Vector3 velocity; + internal Vector3 acceleration; + internal Vector3 angularVelocity; + internal uint sittingOn; + internal int lastInterpolation; + + #region Private Members + + private UUID id; + private UUID sessionID; + private UUID secureSessionID; + private string startLocation = String.Empty; + private string agentAccess = String.Empty; + private Vector3 homePosition; + private Vector3 homeLookAt; + private Vector3 lookAt; + private string firstName = String.Empty; + private string lastName = String.Empty; + private string fullName; + private string teleportMessage = String.Empty; + private TeleportStatus teleportStat = TeleportStatus.None; + private ManualResetEvent teleportEvent = new ManualResetEvent(false); + private uint heightWidthGenCounter; + private float health; + private int balance; + private UUID activeGroup; + private GroupPowers activeGroupPowers; + private Dictionary gestureCache = new Dictionary(); + #endregion Private Members + + /// + /// Constructor, setup callbacks for packets related to our avatar + /// + /// A reference to the Class + public AgentManager(GridClient client) + { + Client = client; + + Movement = new AgentMovement(Client); + + Client.Network.Disconnected += Network_OnDisconnected; + + // Teleport callbacks + Client.Network.RegisterCallback(PacketType.TeleportStart, TeleportHandler); + Client.Network.RegisterCallback(PacketType.TeleportProgress, TeleportHandler); + Client.Network.RegisterCallback(PacketType.TeleportFailed, TeleportHandler); + Client.Network.RegisterCallback(PacketType.TeleportCancel, TeleportHandler); + Client.Network.RegisterCallback(PacketType.TeleportLocal, TeleportHandler); + // these come in via the EventQueue + Client.Network.RegisterEventCallback("TeleportFailed", new Caps.EventQueueCallback(TeleportFailedEventHandler)); + Client.Network.RegisterEventCallback("TeleportFinish", new Caps.EventQueueCallback(TeleportFinishEventHandler)); + + // Instant message callback + Client.Network.RegisterCallback(PacketType.ImprovedInstantMessage, InstantMessageHandler); + // Chat callback + Client.Network.RegisterCallback(PacketType.ChatFromSimulator, ChatHandler); + // Script dialog callback + Client.Network.RegisterCallback(PacketType.ScriptDialog, ScriptDialogHandler); + // Script question callback + Client.Network.RegisterCallback(PacketType.ScriptQuestion, ScriptQuestionHandler); + // Script URL callback + Client.Network.RegisterCallback(PacketType.LoadURL, LoadURLHandler); + // Movement complete callback + Client.Network.RegisterCallback(PacketType.AgentMovementComplete, MovementCompleteHandler); + // Health callback + Client.Network.RegisterCallback(PacketType.HealthMessage, HealthHandler); + // Money callback + Client.Network.RegisterCallback(PacketType.MoneyBalanceReply, MoneyBalanceReplyHandler); + //Agent update callback + Client.Network.RegisterCallback(PacketType.AgentDataUpdate, AgentDataUpdateHandler); + // Animation callback + Client.Network.RegisterCallback(PacketType.AvatarAnimation, AvatarAnimationHandler, false); + // Object colliding into our agent callback + Client.Network.RegisterCallback(PacketType.MeanCollisionAlert, MeanCollisionAlertHandler); + // Region Crossing + Client.Network.RegisterCallback(PacketType.CrossedRegion, CrossedRegionHandler); + Client.Network.RegisterEventCallback("CrossedRegion", new Caps.EventQueueCallback(CrossedRegionEventHandler)); + // CAPS callbacks + Client.Network.RegisterEventCallback("EstablishAgentCommunication", new Caps.EventQueueCallback(EstablishAgentCommunicationEventHandler)); + Client.Network.RegisterEventCallback("SetDisplayNameReply", new Caps.EventQueueCallback(SetDisplayNameReplyEventHandler)); + Client.Network.RegisterEventCallback("AgentStateUpdate", new Caps.EventQueueCallback(AgentStateUpdateEventHandler)); + // Incoming Group Chat + Client.Network.RegisterEventCallback("ChatterBoxInvitation", new Caps.EventQueueCallback(ChatterBoxInvitationEventHandler)); + // Outgoing Group Chat Reply + Client.Network.RegisterEventCallback("ChatterBoxSessionEventReply", new Caps.EventQueueCallback(ChatterBoxSessionEventReplyEventHandler)); + Client.Network.RegisterEventCallback("ChatterBoxSessionStartReply", new Caps.EventQueueCallback(ChatterBoxSessionStartReplyEventHandler)); + Client.Network.RegisterEventCallback("ChatterBoxSessionAgentListUpdates", new Caps.EventQueueCallback(ChatterBoxSessionAgentListUpdatesEventHandler)); + // Login + Client.Network.RegisterLoginResponseCallback(new NetworkManager.LoginResponseCallback(Network_OnLoginResponse)); + // Alert Messages + Client.Network.RegisterCallback(PacketType.AlertMessage, AlertMessageHandler); + // script control change messages, ie: when an in-world LSL script wants to take control of your agent. + Client.Network.RegisterCallback(PacketType.ScriptControlChange, ScriptControlChangeHandler); + // Camera Constraint (probably needs to move to AgentManagerCamera TODO: + Client.Network.RegisterCallback(PacketType.CameraConstraint, CameraConstraintHandler); + Client.Network.RegisterCallback(PacketType.ScriptSensorReply, ScriptSensorReplyHandler); + Client.Network.RegisterCallback(PacketType.AvatarSitResponse, AvatarSitResponseHandler); + // Process mute list update message + Client.Network.RegisterCallback(PacketType.MuteListUpdate, MuteListUpdateHander); + } + + #region Chat and instant messages + + /// + /// Send a text message from the Agent to the Simulator + /// + /// A containing the message + /// The channel to send the message on, 0 is the public channel. Channels above 0 + /// can be used however only scripts listening on the specified channel will see the message + /// Denotes the type of message being sent, shout, whisper, etc. + public void Chat(string message, int channel, ChatType type) + { + ChatFromViewerPacket chat = new ChatFromViewerPacket(); + chat.AgentData.AgentID = this.id; + chat.AgentData.SessionID = Client.Self.SessionID; + chat.ChatData.Channel = channel; + chat.ChatData.Message = Utils.StringToBytes(message); + chat.ChatData.Type = (byte)type; + + Client.Network.SendPacket(chat); + } + + /// + /// Request any instant messages sent while the client was offline to be resent. + /// + public void RetrieveInstantMessages() + { + RetrieveInstantMessagesPacket p = new RetrieveInstantMessagesPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + Client.Network.SendPacket(p); + } + + /// + /// Send an Instant Message to another Avatar + /// + /// The recipients + /// A containing the message to send + public void InstantMessage(UUID target, string message) + { + InstantMessage(Name, target, message, AgentID.Equals(target) ? AgentID : target ^ AgentID, + InstantMessageDialog.MessageFromAgent, InstantMessageOnline.Offline, this.SimPosition, + UUID.Zero, Utils.EmptyBytes); + } + + /// + /// Send an Instant Message to an existing group chat or conference chat + /// + /// The recipients + /// A containing the message to send + /// IM session ID (to differentiate between IM windows) + public void InstantMessage(UUID target, string message, UUID imSessionID) + { + InstantMessage(Name, target, message, imSessionID, + InstantMessageDialog.MessageFromAgent, InstantMessageOnline.Offline, this.SimPosition, + UUID.Zero, Utils.EmptyBytes); + } + + /// + /// Send an Instant Message + /// + /// The name this IM will show up as being from + /// Key of Avatar + /// Text message being sent + /// IM session ID (to differentiate between IM windows) + /// IDs of sessions for a conference + public void InstantMessage(string fromName, UUID target, string message, UUID imSessionID, + UUID[] conferenceIDs) + { + byte[] binaryBucket; + + if (conferenceIDs != null && conferenceIDs.Length > 0) + { + binaryBucket = new byte[16 * conferenceIDs.Length]; + for (int i = 0; i < conferenceIDs.Length; ++i) + Buffer.BlockCopy(conferenceIDs[i].GetBytes(), 0, binaryBucket, i * 16, 16); + } + else + { + binaryBucket = Utils.EmptyBytes; + } + + InstantMessage(fromName, target, message, imSessionID, InstantMessageDialog.MessageFromAgent, + InstantMessageOnline.Offline, Vector3.Zero, UUID.Zero, binaryBucket); + } + + /// + /// Send an Instant Message + /// + /// The name this IM will show up as being from + /// Key of Avatar + /// Text message being sent + /// IM session ID (to differentiate between IM windows) + /// Type of instant message to send + /// Whether to IM offline avatars as well + /// Senders Position + /// RegionID Sender is In + /// Packed binary data that is specific to + /// the dialog type + public void InstantMessage(string fromName, UUID target, string message, UUID imSessionID, + InstantMessageDialog dialog, InstantMessageOnline offline, Vector3 position, UUID regionID, + byte[] binaryBucket) + { + if (target != UUID.Zero) + { + ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket(); + + if (imSessionID.Equals(UUID.Zero) || imSessionID.Equals(AgentID)) + imSessionID = AgentID.Equals(target) ? AgentID : target ^ AgentID; + + im.AgentData.AgentID = Client.Self.AgentID; + im.AgentData.SessionID = Client.Self.SessionID; + + im.MessageBlock.Dialog = (byte)dialog; + im.MessageBlock.FromAgentName = Utils.StringToBytes(fromName); + im.MessageBlock.FromGroup = false; + im.MessageBlock.ID = imSessionID; + im.MessageBlock.Message = Utils.StringToBytes(message); + im.MessageBlock.Offline = (byte)offline; + im.MessageBlock.ToAgentID = target; + + if (binaryBucket != null) + im.MessageBlock.BinaryBucket = binaryBucket; + else + im.MessageBlock.BinaryBucket = Utils.EmptyBytes; + + // These fields are mandatory, even if we don't have valid values for them + im.MessageBlock.Position = Vector3.Zero; + //TODO: Allow region id to be correctly set by caller or fetched from Client.* + im.MessageBlock.RegionID = regionID; + + // Send the message + Client.Network.SendPacket(im); + } + else + { + Logger.Log(String.Format("Suppressing instant message \"{0}\" to UUID.Zero", message), + Helpers.LogLevel.Error, Client); + } + } + + /// + /// Send an Instant Message to a group + /// + /// of the group to send message to + /// Text Message being sent. + public void InstantMessageGroup(UUID groupID, string message) + { + InstantMessageGroup(Name, groupID, message); + } + + /// + /// Send an Instant Message to a group the agent is a member of + /// + /// The name this IM will show up as being from + /// of the group to send message to + /// Text message being sent + public void InstantMessageGroup(string fromName, UUID groupID, string message) + { + lock (GroupChatSessions.Dictionary) + if (GroupChatSessions.ContainsKey(groupID)) + { + ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket(); + + im.AgentData.AgentID = Client.Self.AgentID; + im.AgentData.SessionID = Client.Self.SessionID; + im.MessageBlock.Dialog = (byte)InstantMessageDialog.SessionSend; + im.MessageBlock.FromAgentName = Utils.StringToBytes(fromName); + im.MessageBlock.FromGroup = false; + im.MessageBlock.Message = Utils.StringToBytes(message); + im.MessageBlock.Offline = 0; + im.MessageBlock.ID = groupID; + im.MessageBlock.ToAgentID = groupID; + im.MessageBlock.Position = Vector3.Zero; + im.MessageBlock.RegionID = UUID.Zero; + im.MessageBlock.BinaryBucket = Utils.StringToBytes("\0"); + + Client.Network.SendPacket(im); + } + else + { + Logger.Log("No Active group chat session appears to exist, use RequestJoinGroupChat() to join one", + Helpers.LogLevel.Error, Client); + } + } + + /// + /// Send a request to join a group chat session + /// + /// of Group to leave + public void RequestJoinGroupChat(UUID groupID) + { + ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket(); + + im.AgentData.AgentID = Client.Self.AgentID; + im.AgentData.SessionID = Client.Self.SessionID; + im.MessageBlock.Dialog = (byte)InstantMessageDialog.SessionGroupStart; + im.MessageBlock.FromAgentName = Utils.StringToBytes(Client.Self.Name); + im.MessageBlock.FromGroup = false; + im.MessageBlock.Message = Utils.EmptyBytes; + im.MessageBlock.ParentEstateID = 0; + im.MessageBlock.Offline = 0; + im.MessageBlock.ID = groupID; + im.MessageBlock.ToAgentID = groupID; + im.MessageBlock.BinaryBucket = Utils.EmptyBytes; + im.MessageBlock.Position = Client.Self.SimPosition; + im.MessageBlock.RegionID = UUID.Zero; + + Client.Network.SendPacket(im); + } + + /// + /// Exit a group chat session. This will stop further Group chat messages + /// from being sent until session is rejoined. + /// + /// of Group chat session to leave + public void RequestLeaveGroupChat(UUID groupID) + { + ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket(); + + im.AgentData.AgentID = Client.Self.AgentID; + im.AgentData.SessionID = Client.Self.SessionID; + im.MessageBlock.Dialog = (byte)InstantMessageDialog.SessionDrop; + im.MessageBlock.FromAgentName = Utils.StringToBytes(Client.Self.Name); + im.MessageBlock.FromGroup = false; + im.MessageBlock.Message = Utils.EmptyBytes; + im.MessageBlock.Offline = 0; + im.MessageBlock.ID = groupID; + im.MessageBlock.ToAgentID = groupID; + im.MessageBlock.BinaryBucket = Utils.EmptyBytes; + im.MessageBlock.Position = Vector3.Zero; + im.MessageBlock.RegionID = UUID.Zero; + + Client.Network.SendPacket(im); + + lock (GroupChatSessions.Dictionary) + if (GroupChatSessions.ContainsKey(groupID)) + GroupChatSessions.Remove(groupID); + } + + /// + /// Reply to script dialog questions. + /// + /// Channel initial request came on + /// Index of button you're "clicking" + /// Label of button you're "clicking" + /// of Object that sent the dialog request + /// + public void ReplyToScriptDialog(int channel, int buttonIndex, string buttonlabel, UUID objectID) + { + ScriptDialogReplyPacket reply = new ScriptDialogReplyPacket(); + + reply.AgentData.AgentID = Client.Self.AgentID; + reply.AgentData.SessionID = Client.Self.SessionID; + + reply.Data.ButtonIndex = buttonIndex; + reply.Data.ButtonLabel = Utils.StringToBytes(buttonlabel); + reply.Data.ChatChannel = channel; + reply.Data.ObjectID = objectID; + + Client.Network.SendPacket(reply); + } + + /// + /// Accept invite for to a chatterbox session + /// + /// of session to accept invite to + public void ChatterBoxAcceptInvite(UUID session_id) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + throw new Exception("ChatSessionRequest capability is not currently available"); + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("ChatSessionRequest"); + + if (url != null) + { + ChatSessionAcceptInvitation acceptInvite = new ChatSessionAcceptInvitation(); + acceptInvite.SessionID = session_id; + + CapsClient request = new CapsClient(url); + request.BeginGetResponse(acceptInvite.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + + lock (GroupChatSessions.Dictionary) + if (!GroupChatSessions.ContainsKey(session_id)) + GroupChatSessions.Add(session_id, new List()); + } + else + { + throw new Exception("ChatSessionRequest capability is not currently available"); + } + + } + + /// + /// Start a friends conference + /// + /// List of UUIDs to start a conference with + /// the temportary session ID returned in the callback> + public void StartIMConference(List participants, UUID tmp_session_id) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + throw new Exception("ChatSessionRequest capability is not currently available"); + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("ChatSessionRequest"); + + if (url != null) + { + ChatSessionRequestStartConference startConference = new ChatSessionRequestStartConference(); + + startConference.AgentsBlock = new UUID[participants.Count]; + for (int i = 0; i < participants.Count; i++) + startConference.AgentsBlock[i] = participants[i]; + + startConference.SessionID = tmp_session_id; + + CapsClient request = new CapsClient(url); + request.BeginGetResponse(startConference.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("ChatSessionRequest capability is not currently available"); + } + } + + #endregion Chat and instant messages + + #region Viewer Effects + + /// + /// Start a particle stream between an agent and an object + /// + /// Key of the source agent + /// Key of the target object + /// + /// The type from the enum + /// A unique for this effect + public void PointAtEffect(UUID sourceAvatar, UUID targetObject, Vector3d globalOffset, PointAtType type, + UUID effectID) + { + ViewerEffectPacket effect = new ViewerEffectPacket(); + + effect.AgentData.AgentID = Client.Self.AgentID; + effect.AgentData.SessionID = Client.Self.SessionID; + + effect.Effect = new ViewerEffectPacket.EffectBlock[1]; + effect.Effect[0] = new ViewerEffectPacket.EffectBlock(); + effect.Effect[0].AgentID = Client.Self.AgentID; + effect.Effect[0].Color = new byte[4]; + effect.Effect[0].Duration = (type == PointAtType.Clear) ? 0.0f : Single.MaxValue / 4.0f; + effect.Effect[0].ID = effectID; + effect.Effect[0].Type = (byte)EffectType.PointAt; + + byte[] typeData = new byte[57]; + if (sourceAvatar != UUID.Zero) + Buffer.BlockCopy(sourceAvatar.GetBytes(), 0, typeData, 0, 16); + if (targetObject != UUID.Zero) + Buffer.BlockCopy(targetObject.GetBytes(), 0, typeData, 16, 16); + Buffer.BlockCopy(globalOffset.GetBytes(), 0, typeData, 32, 24); + typeData[56] = (byte)type; + + effect.Effect[0].TypeData = typeData; + + Client.Network.SendPacket(effect); + } + + /// + /// Start a particle stream between an agent and an object + /// + /// Key of the source agent + /// Key of the target object + /// A representing the beams offset from the source + /// A which sets the avatars lookat animation + /// of the Effect + public void LookAtEffect(UUID sourceAvatar, UUID targetObject, Vector3d globalOffset, LookAtType type, + UUID effectID) + { + ViewerEffectPacket effect = new ViewerEffectPacket(); + + effect.AgentData.AgentID = Client.Self.AgentID; + effect.AgentData.SessionID = Client.Self.SessionID; + + float duration; + + switch (type) + { + case LookAtType.Clear: + duration = 2.0f; + break; + case LookAtType.Hover: + duration = 1.0f; + break; + case LookAtType.FreeLook: + duration = 2.0f; + break; + case LookAtType.Idle: + duration = 3.0f; + break; + case LookAtType.AutoListen: + case LookAtType.Respond: + duration = 4.0f; + break; + case LookAtType.None: + case LookAtType.Select: + case LookAtType.Focus: + case LookAtType.Mouselook: + duration = Single.MaxValue / 2.0f; + break; + default: + duration = 0.0f; + break; + } + + effect.Effect = new ViewerEffectPacket.EffectBlock[1]; + effect.Effect[0] = new ViewerEffectPacket.EffectBlock(); + effect.Effect[0].AgentID = Client.Self.AgentID; + effect.Effect[0].Color = new byte[4]; + effect.Effect[0].Duration = duration; + effect.Effect[0].ID = effectID; + effect.Effect[0].Type = (byte)EffectType.LookAt; + + byte[] typeData = new byte[57]; + Buffer.BlockCopy(sourceAvatar.GetBytes(), 0, typeData, 0, 16); + Buffer.BlockCopy(targetObject.GetBytes(), 0, typeData, 16, 16); + Buffer.BlockCopy(globalOffset.GetBytes(), 0, typeData, 32, 24); + typeData[56] = (byte)type; + + effect.Effect[0].TypeData = typeData; + + Client.Network.SendPacket(effect); + } + + /// + /// Create a particle beam between an avatar and an primitive + /// + /// The ID of source avatar + /// The ID of the target primitive + /// global offset + /// A object containing the combined red, green, blue and alpha + /// color values of particle beam + /// a float representing the duration the parcicle beam will last + /// A Unique ID for the beam + /// + public void BeamEffect(UUID sourceAvatar, UUID targetObject, Vector3d globalOffset, Color4 color, + float duration, UUID effectID) + { + ViewerEffectPacket effect = new ViewerEffectPacket(); + + effect.AgentData.AgentID = Client.Self.AgentID; + effect.AgentData.SessionID = Client.Self.SessionID; + + effect.Effect = new ViewerEffectPacket.EffectBlock[1]; + effect.Effect[0] = new ViewerEffectPacket.EffectBlock(); + effect.Effect[0].AgentID = Client.Self.AgentID; + effect.Effect[0].Color = color.GetBytes(); + effect.Effect[0].Duration = duration; + effect.Effect[0].ID = effectID; + effect.Effect[0].Type = (byte)EffectType.Beam; + + byte[] typeData = new byte[56]; + Buffer.BlockCopy(sourceAvatar.GetBytes(), 0, typeData, 0, 16); + Buffer.BlockCopy(targetObject.GetBytes(), 0, typeData, 16, 16); + Buffer.BlockCopy(globalOffset.GetBytes(), 0, typeData, 32, 24); + + effect.Effect[0].TypeData = typeData; + + Client.Network.SendPacket(effect); + } + + /// + /// Create a particle swirl around a target position using a packet + /// + /// global offset + /// A object containing the combined red, green, blue and alpha + /// color values of particle beam + /// a float representing the duration the parcicle beam will last + /// A Unique ID for the beam + public void SphereEffect(Vector3d globalOffset, Color4 color, float duration, UUID effectID) + { + ViewerEffectPacket effect = new ViewerEffectPacket(); + + effect.AgentData.AgentID = Client.Self.AgentID; + effect.AgentData.SessionID = Client.Self.SessionID; + + effect.Effect = new ViewerEffectPacket.EffectBlock[1]; + effect.Effect[0] = new ViewerEffectPacket.EffectBlock(); + effect.Effect[0].AgentID = Client.Self.AgentID; + effect.Effect[0].Color = color.GetBytes(); + effect.Effect[0].Duration = duration; + effect.Effect[0].ID = effectID; + effect.Effect[0].Type = (byte)EffectType.Sphere; + + byte[] typeData = new byte[56]; + Buffer.BlockCopy(UUID.Zero.GetBytes(), 0, typeData, 0, 16); + Buffer.BlockCopy(UUID.Zero.GetBytes(), 0, typeData, 16, 16); + Buffer.BlockCopy(globalOffset.GetBytes(), 0, typeData, 32, 24); + + effect.Effect[0].TypeData = typeData; + + Client.Network.SendPacket(effect); + } + + + #endregion Viewer Effects + + #region Movement Actions + + /// + /// Sends a request to sit on the specified object + /// + /// of the object to sit on + /// Sit at offset + public void RequestSit(UUID targetID, Vector3 offset) + { + AgentRequestSitPacket requestSit = new AgentRequestSitPacket(); + requestSit.AgentData.AgentID = Client.Self.AgentID; + requestSit.AgentData.SessionID = Client.Self.SessionID; + requestSit.TargetObject.TargetID = targetID; + requestSit.TargetObject.Offset = offset; + Client.Network.SendPacket(requestSit); + } + + /// + /// Follows a call to to actually sit on the object + /// + public void Sit() + { + AgentSitPacket sit = new AgentSitPacket(); + sit.AgentData.AgentID = Client.Self.AgentID; + sit.AgentData.SessionID = Client.Self.SessionID; + Client.Network.SendPacket(sit); + } + + /// Stands up from sitting on a prim or the ground + /// true of AgentUpdate was sent + public bool Stand() + { + if (Client.Settings.SEND_AGENT_UPDATES) + { + Movement.SitOnGround = false; + Movement.StandUp = true; + Movement.SendUpdate(); + Movement.StandUp = false; + Movement.SendUpdate(); + return true; + } + else + { + Logger.Log("Attempted to Stand() but agent updates are disabled", Helpers.LogLevel.Warning, Client); + return false; + } + } + + /// + /// Does a "ground sit" at the avatar's current position + /// + public void SitOnGround() + { + Movement.SitOnGround = true; + Movement.SendUpdate(true); + } + + /// + /// Starts or stops flying + /// + /// True to start flying, false to stop flying + public void Fly(bool start) + { + if (start) + Movement.Fly = true; + else + Movement.Fly = false; + + Movement.SendUpdate(true); + } + + /// + /// Starts or stops crouching + /// + /// True to start crouching, false to stop crouching + public void Crouch(bool crouching) + { + Movement.UpNeg = crouching; + Movement.SendUpdate(true); + } + + /// + /// Starts a jump (begin holding the jump key) + /// + public void Jump(bool jumping) + { + Movement.UpPos = jumping; + Movement.FastUp = jumping; + Movement.SendUpdate(true); + } + + /// + /// Use the autopilot sim function to move the avatar to a new + /// position. Uses double precision to get precise movements + /// + /// The z value is currently not handled properly by the simulator + /// Global X coordinate to move to + /// Global Y coordinate to move to + /// Z coordinate to move to + public void AutoPilot(double globalX, double globalY, double z) + { + GenericMessagePacket autopilot = new GenericMessagePacket(); + + autopilot.AgentData.AgentID = Client.Self.AgentID; + autopilot.AgentData.SessionID = Client.Self.SessionID; + autopilot.AgentData.TransactionID = UUID.Zero; + autopilot.MethodData.Invoice = UUID.Zero; + autopilot.MethodData.Method = Utils.StringToBytes("autopilot"); + autopilot.ParamList = new GenericMessagePacket.ParamListBlock[3]; + autopilot.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + autopilot.ParamList[0].Parameter = Utils.StringToBytes(globalX.ToString()); + autopilot.ParamList[1] = new GenericMessagePacket.ParamListBlock(); + autopilot.ParamList[1].Parameter = Utils.StringToBytes(globalY.ToString()); + autopilot.ParamList[2] = new GenericMessagePacket.ParamListBlock(); + autopilot.ParamList[2].Parameter = Utils.StringToBytes(z.ToString()); + + Client.Network.SendPacket(autopilot); + } + + /// + /// Use the autopilot sim function to move the avatar to a new position + /// + /// The z value is currently not handled properly by the simulator + /// Integer value for the global X coordinate to move to + /// Integer value for the global Y coordinate to move to + /// Floating-point value for the Z coordinate to move to + public void AutoPilot(ulong globalX, ulong globalY, float z) + { + GenericMessagePacket autopilot = new GenericMessagePacket(); + + autopilot.AgentData.AgentID = Client.Self.AgentID; + autopilot.AgentData.SessionID = Client.Self.SessionID; + autopilot.AgentData.TransactionID = UUID.Zero; + autopilot.MethodData.Invoice = UUID.Zero; + autopilot.MethodData.Method = Utils.StringToBytes("autopilot"); + autopilot.ParamList = new GenericMessagePacket.ParamListBlock[3]; + autopilot.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + autopilot.ParamList[0].Parameter = Utils.StringToBytes(globalX.ToString()); + autopilot.ParamList[1] = new GenericMessagePacket.ParamListBlock(); + autopilot.ParamList[1].Parameter = Utils.StringToBytes(globalY.ToString()); + autopilot.ParamList[2] = new GenericMessagePacket.ParamListBlock(); + autopilot.ParamList[2].Parameter = Utils.StringToBytes(z.ToString()); + + Client.Network.SendPacket(autopilot); + } + + /// + /// Use the autopilot sim function to move the avatar to a new position + /// + /// The z value is currently not handled properly by the simulator + /// Integer value for the local X coordinate to move to + /// Integer value for the local Y coordinate to move to + /// Floating-point value for the Z coordinate to move to + public void AutoPilotLocal(int localX, int localY, float z) + { + uint x, y; + Utils.LongToUInts(Client.Network.CurrentSim.Handle, out x, out y); + AutoPilot((ulong)(x + localX), (ulong)(y + localY), z); + } + + /// Macro to cancel autopilot sim function + /// Not certain if this is how it is really done + /// true if control flags were set and AgentUpdate was sent to the simulator + public bool AutoPilotCancel() + { + if (Client.Settings.SEND_AGENT_UPDATES) + { + Movement.AtPos = true; + Movement.SendUpdate(); + Movement.AtPos = false; + Movement.SendUpdate(); + return true; + } + else + { + Logger.Log("Attempted to AutoPilotCancel() but agent updates are disabled", Helpers.LogLevel.Warning, Client); + return false; + } + } + + #endregion Movement actions + + #region Touch and grab + + /// + /// Grabs an object + /// + /// an unsigned integer of the objects ID within the simulator + /// + public void Grab(uint objectLocalID) + { + Grab(objectLocalID, Vector3.Zero, Vector3.Zero, Vector3.Zero, 0, Vector3.Zero, Vector3.Zero, Vector3.Zero); + } + + /// + /// Overload: Grab a simulated object + /// + /// an unsigned integer of the objects ID within the simulator + /// + /// The texture coordinates to grab + /// The surface coordinates to grab + /// The face of the position to grab + /// The region coordinates of the position to grab + /// The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + /// The surface binormal of the position to grab (A binormal is a vector tangen to the surface + /// pointing along the U direction of the tangent space + public void Grab(uint objectLocalID, Vector3 grabOffset, Vector3 uvCoord, Vector3 stCoord, int faceIndex, Vector3 position, + Vector3 normal, Vector3 binormal) + { + ObjectGrabPacket grab = new ObjectGrabPacket(); + + grab.AgentData.AgentID = Client.Self.AgentID; + grab.AgentData.SessionID = Client.Self.SessionID; + + grab.ObjectData.LocalID = objectLocalID; + grab.ObjectData.GrabOffset = grabOffset; + + grab.SurfaceInfo = new ObjectGrabPacket.SurfaceInfoBlock[1]; + grab.SurfaceInfo[0] = new ObjectGrabPacket.SurfaceInfoBlock(); + grab.SurfaceInfo[0].UVCoord = uvCoord; + grab.SurfaceInfo[0].STCoord = stCoord; + grab.SurfaceInfo[0].FaceIndex = faceIndex; + grab.SurfaceInfo[0].Position = position; + grab.SurfaceInfo[0].Normal = normal; + grab.SurfaceInfo[0].Binormal = binormal; + + Client.Network.SendPacket(grab); + } + + /// + /// Drag an object + /// + /// of the object to drag + /// Drag target in region coordinates + public void GrabUpdate(UUID objectID, Vector3 grabPosition) + { + GrabUpdate(objectID, grabPosition, Vector3.Zero, Vector3.Zero, Vector3.Zero, 0, Vector3.Zero, Vector3.Zero, Vector3.Zero); + } + + /// + /// Overload: Drag an object + /// + /// of the object to drag + /// Drag target in region coordinates + /// + /// The texture coordinates to grab + /// The surface coordinates to grab + /// The face of the position to grab + /// The region coordinates of the position to grab + /// The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + /// The surface binormal of the position to grab (A binormal is a vector tangen to the surface + /// pointing along the U direction of the tangent space + public void GrabUpdate(UUID objectID, Vector3 grabPosition, Vector3 grabOffset, Vector3 uvCoord, Vector3 stCoord, int faceIndex, Vector3 position, + Vector3 normal, Vector3 binormal) + { + ObjectGrabUpdatePacket grab = new ObjectGrabUpdatePacket(); + grab.AgentData.AgentID = Client.Self.AgentID; + grab.AgentData.SessionID = Client.Self.SessionID; + + grab.ObjectData.ObjectID = objectID; + grab.ObjectData.GrabOffsetInitial = grabOffset; + grab.ObjectData.GrabPosition = grabPosition; + grab.ObjectData.TimeSinceLast = 0; + + grab.SurfaceInfo = new ObjectGrabUpdatePacket.SurfaceInfoBlock[1]; + grab.SurfaceInfo[0] = new ObjectGrabUpdatePacket.SurfaceInfoBlock(); + grab.SurfaceInfo[0].UVCoord = uvCoord; + grab.SurfaceInfo[0].STCoord = stCoord; + grab.SurfaceInfo[0].FaceIndex = faceIndex; + grab.SurfaceInfo[0].Position = position; + grab.SurfaceInfo[0].Normal = normal; + grab.SurfaceInfo[0].Binormal = binormal; + + Client.Network.SendPacket(grab); + } + + /// + /// Release a grabbed object + /// + /// The Objects Simulator Local ID + /// + /// + /// + public void DeGrab(uint objectLocalID) + { + DeGrab(objectLocalID, Vector3.Zero, Vector3.Zero, 0, Vector3.Zero, Vector3.Zero, Vector3.Zero); + } + + /// + /// Release a grabbed object + /// + /// The Objects Simulator Local ID + /// The texture coordinates to grab + /// The surface coordinates to grab + /// The face of the position to grab + /// The region coordinates of the position to grab + /// The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + /// The surface binormal of the position to grab (A binormal is a vector tangen to the surface + /// pointing along the U direction of the tangent space + public void DeGrab(uint objectLocalID, Vector3 uvCoord, Vector3 stCoord, int faceIndex, Vector3 position, + Vector3 normal, Vector3 binormal) + { + ObjectDeGrabPacket degrab = new ObjectDeGrabPacket(); + degrab.AgentData.AgentID = Client.Self.AgentID; + degrab.AgentData.SessionID = Client.Self.SessionID; + + degrab.ObjectData.LocalID = objectLocalID; + + degrab.SurfaceInfo = new ObjectDeGrabPacket.SurfaceInfoBlock[1]; + degrab.SurfaceInfo[0] = new ObjectDeGrabPacket.SurfaceInfoBlock(); + degrab.SurfaceInfo[0].UVCoord = uvCoord; + degrab.SurfaceInfo[0].STCoord = stCoord; + degrab.SurfaceInfo[0].FaceIndex = faceIndex; + degrab.SurfaceInfo[0].Position = position; + degrab.SurfaceInfo[0].Normal = normal; + degrab.SurfaceInfo[0].Binormal = binormal; + + Client.Network.SendPacket(degrab); + } + + /// + /// Touches an object + /// + /// an unsigned integer of the objects ID within the simulator + /// + public void Touch(uint objectLocalID) + { + Client.Self.Grab(objectLocalID); + Client.Self.DeGrab(objectLocalID); + } + + #endregion Touch and grab + + #region Money + + /// + /// Request the current L$ balance + /// + public void RequestBalance() + { + MoneyBalanceRequestPacket money = new MoneyBalanceRequestPacket(); + money.AgentData.AgentID = Client.Self.AgentID; + money.AgentData.SessionID = Client.Self.SessionID; + money.MoneyData.TransactionID = UUID.Zero; + + Client.Network.SendPacket(money); + } + + /// + /// Give Money to destination Avatar + /// + /// UUID of the Target Avatar + /// Amount in L$ + public void GiveAvatarMoney(UUID target, int amount) + { + GiveMoney(target, amount, String.Empty, MoneyTransactionType.Gift, TransactionFlags.None); + } + + /// + /// Give Money to destination Avatar + /// + /// UUID of the Target Avatar + /// Amount in L$ + /// Description that will show up in the + /// recipients transaction history + public void GiveAvatarMoney(UUID target, int amount, string description) + { + GiveMoney(target, amount, description, MoneyTransactionType.Gift, TransactionFlags.None); + } + + /// + /// Give L$ to an object + /// + /// object to give money to + /// amount of L$ to give + /// name of object + public void GiveObjectMoney(UUID target, int amount, string objectName) + { + GiveMoney(target, amount, objectName, MoneyTransactionType.PayObject, TransactionFlags.None); + } + + /// + /// Give L$ to a group + /// + /// group to give money to + /// amount of L$ to give + public void GiveGroupMoney(UUID target, int amount) + { + GiveMoney(target, amount, String.Empty, MoneyTransactionType.Gift, TransactionFlags.DestGroup); + } + + /// + /// Give L$ to a group + /// + /// group to give money to + /// amount of L$ to give + /// description of transaction + public void GiveGroupMoney(UUID target, int amount, string description) + { + GiveMoney(target, amount, description, MoneyTransactionType.Gift, TransactionFlags.DestGroup); + } + + /// + /// Pay texture/animation upload fee + /// + public void PayUploadFee() + { + GiveMoney(UUID.Zero, Client.Settings.UPLOAD_COST, String.Empty, MoneyTransactionType.UploadCharge, + TransactionFlags.None); + } + + /// + /// Pay texture/animation upload fee + /// + /// description of the transaction + public void PayUploadFee(string description) + { + GiveMoney(UUID.Zero, Client.Settings.UPLOAD_COST, description, MoneyTransactionType.UploadCharge, + TransactionFlags.None); + } + + /// + /// Give Money to destination Object or Avatar + /// + /// UUID of the Target Object/Avatar + /// Amount in L$ + /// Reason (Optional normally) + /// The type of transaction + /// Transaction flags, mostly for identifying group + /// transactions + public void GiveMoney(UUID target, int amount, string description, MoneyTransactionType type, TransactionFlags flags) + { + MoneyTransferRequestPacket money = new MoneyTransferRequestPacket(); + money.AgentData.AgentID = this.id; + money.AgentData.SessionID = Client.Self.SessionID; + money.MoneyData.Description = Utils.StringToBytes(description); + money.MoneyData.DestID = target; + money.MoneyData.SourceID = this.id; + money.MoneyData.TransactionType = (int)type; + money.MoneyData.AggregatePermInventory = 0; // This is weird, apparently always set to zero though + money.MoneyData.AggregatePermNextOwner = 0; // This is weird, apparently always set to zero though + money.MoneyData.Flags = (byte)flags; + money.MoneyData.Amount = amount; + + Client.Network.SendPacket(money); + } + + #endregion Money + + #region Gestures + /// + /// Plays a gesture + /// + /// Asset of the gesture + public void PlayGesture(UUID gestureID) + { + Thread t = new Thread(new ThreadStart(delegate() + { + // First fetch the guesture + AssetGesture gesture = null; + + if (gestureCache.ContainsKey(gestureID)) + { + gesture = gestureCache[gestureID]; + } + else + { + AutoResetEvent gotAsset = new AutoResetEvent(false); + + Client.Assets.RequestAsset(gestureID, AssetType.Gesture, true, + delegate(AssetDownload transfer, Asset asset) + { + if (transfer.Success) + { + gesture = (AssetGesture)asset; + } + + gotAsset.Set(); + } + ); + + gotAsset.WaitOne(30 * 1000, false); + + if (gesture != null && gesture.Decode()) + { + lock (gestureCache) + { + if (!gestureCache.ContainsKey(gestureID)) + { + gestureCache[gestureID] = gesture; + } + } + } + } + + // We got it, now we play it + if (gesture != null) + { + for (int i = 0; i < gesture.Sequence.Count; i++) + { + GestureStep step = gesture.Sequence[i]; + + switch (step.GestureStepType) + { + case GestureStepType.Chat: + Chat(((GestureStepChat)step).Text, 0, ChatType.Normal); + break; + + case GestureStepType.Animation: + GestureStepAnimation anim = (GestureStepAnimation)step; + + if (anim.AnimationStart) + { + if (SignaledAnimations.ContainsKey(anim.ID)) + { + AnimationStop(anim.ID, true); + } + AnimationStart(anim.ID, true); + } + else + { + AnimationStop(anim.ID, true); + } + break; + + case GestureStepType.Sound: + Client.Sound.PlaySound(((GestureStepSound)step).ID); + break; + + case GestureStepType.Wait: + GestureStepWait wait = (GestureStepWait)step; + if (wait.WaitForTime) + { + Thread.Sleep((int)(1000f * wait.WaitTime)); + } + if (wait.WaitForAnimation) + { + // TODO: implement waiting for all animations to end that were triggered + // during playing of this guesture sequence + } + break; + } + } + } + })); + + t.IsBackground = true; + t.Name = "Gesture thread: " + gestureID; + t.Start(); + } + + /// + /// Mark gesture active + /// + /// Inventory of the gesture + /// Asset of the gesture + public void ActivateGesture(UUID invID, UUID assetID) + { + ActivateGesturesPacket p = new ActivateGesturesPacket(); + + p.AgentData.AgentID = AgentID; + p.AgentData.SessionID = SessionID; + p.AgentData.Flags = 0x00; + + ActivateGesturesPacket.DataBlock b = new ActivateGesturesPacket.DataBlock(); + b.ItemID = invID; + b.AssetID = assetID; + b.GestureFlags = 0x00; + + p.Data = new ActivateGesturesPacket.DataBlock[1]; + p.Data[0] = b; + + Client.Network.SendPacket(p); + + } + + /// + /// Mark gesture inactive + /// + /// Inventory of the gesture + public void DeactivateGesture(UUID invID) + { + DeactivateGesturesPacket p = new DeactivateGesturesPacket(); + + p.AgentData.AgentID = AgentID; + p.AgentData.SessionID = SessionID; + p.AgentData.Flags = 0x00; + + DeactivateGesturesPacket.DataBlock b = new DeactivateGesturesPacket.DataBlock(); + b.ItemID = invID; + b.GestureFlags = 0x00; + + p.Data = new DeactivateGesturesPacket.DataBlock[1]; + p.Data[0] = b; + + Client.Network.SendPacket(p); + } + #endregion + + #region Animations + + /// + /// Send an AgentAnimation packet that toggles a single animation on + /// + /// The of the animation to start playing + /// Whether to ensure delivery of this packet or not + public void AnimationStart(UUID animation, bool reliable) + { + Dictionary animations = new Dictionary(); + animations[animation] = true; + + Animate(animations, reliable); + } + + /// + /// Send an AgentAnimation packet that toggles a single animation off + /// + /// The of a + /// currently playing animation to stop playing + /// Whether to ensure delivery of this packet or not + public void AnimationStop(UUID animation, bool reliable) + { + Dictionary animations = new Dictionary(); + animations[animation] = false; + + Animate(animations, reliable); + } + + /// + /// Send an AgentAnimation packet that will toggle animations on or off + /// + /// A list of animation s, and whether to + /// turn that animation on or off + /// Whether to ensure delivery of this packet or not + public void Animate(Dictionary animations, bool reliable) + { + AgentAnimationPacket animate = new AgentAnimationPacket(); + animate.Header.Reliable = reliable; + + animate.AgentData.AgentID = Client.Self.AgentID; + animate.AgentData.SessionID = Client.Self.SessionID; + animate.AnimationList = new AgentAnimationPacket.AnimationListBlock[animations.Count]; + int i = 0; + + foreach (KeyValuePair animation in animations) + { + animate.AnimationList[i] = new AgentAnimationPacket.AnimationListBlock(); + animate.AnimationList[i].AnimID = animation.Key; + animate.AnimationList[i].StartAnim = animation.Value; + + i++; + } + + // TODO: Implement support for this + animate.PhysicalAvatarEventList = new AgentAnimationPacket.PhysicalAvatarEventListBlock[0]; + + Client.Network.SendPacket(animate); + } + + #endregion Animations + + #region Teleporting + + /// + /// Teleports agent to their stored home location + /// + /// true on successful teleport to home location + public bool GoHome() + { + return Teleport(UUID.Zero); + } + + /// + /// Teleport agent to a landmark + /// + /// of the landmark to teleport agent to + /// true on success, false on failure + public bool Teleport(UUID landmark) + { + teleportStat = TeleportStatus.None; + teleportEvent.Reset(); + TeleportLandmarkRequestPacket p = new TeleportLandmarkRequestPacket(); + p.Info = new TeleportLandmarkRequestPacket.InfoBlock(); + p.Info.AgentID = Client.Self.AgentID; + p.Info.SessionID = Client.Self.SessionID; + p.Info.LandmarkID = landmark; + Client.Network.SendPacket(p); + + teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false); + + if (teleportStat == TeleportStatus.None || + teleportStat == TeleportStatus.Start || + teleportStat == TeleportStatus.Progress) + { + teleportMessage = "Teleport timed out."; + teleportStat = TeleportStatus.Failed; + } + + return (teleportStat == TeleportStatus.Finished); + } + + /// + /// Attempt to look up a simulator name and teleport to the discovered + /// destination + /// + /// Region name to look up + /// Position to teleport to + /// True if the lookup and teleport were successful, otherwise + /// false + public bool Teleport(string simName, Vector3 position) + { + return Teleport(simName, position, new Vector3(0, 1.0f, 0)); + } + + /// + /// Attempt to look up a simulator name and teleport to the discovered + /// destination + /// + /// Region name to look up + /// Position to teleport to + /// Target to look at + /// True if the lookup and teleport were successful, otherwise + /// false + public bool Teleport(string simName, Vector3 position, Vector3 lookAt) + { + if (Client.Network.CurrentSim == null) + return false; + + teleportStat = TeleportStatus.None; + + if (simName != Client.Network.CurrentSim.Name) + { + // Teleporting to a foreign sim + GridRegion region; + + if (Client.Grid.GetGridRegion(simName, GridLayerType.Objects, out region)) + { + return Teleport(region.RegionHandle, position, lookAt); + } + else + { + teleportMessage = "Unable to resolve name: " + simName; + teleportStat = TeleportStatus.Failed; + return false; + } + } + else + { + // Teleporting to the sim we're already in + return Teleport(Client.Network.CurrentSim.Handle, position, lookAt); + } + } + + /// + /// Teleport agent to another region + /// + /// handle of region to teleport agent to + /// position in destination sim to teleport to + /// true on success, false on failure + /// This call is blocking + public bool Teleport(ulong regionHandle, Vector3 position) + { + return Teleport(regionHandle, position, new Vector3(0.0f, 1.0f, 0.0f)); + } + + /// + /// Teleport agent to another region + /// + /// handle of region to teleport agent to + /// position in destination sim to teleport to + /// direction in destination sim agent will look at + /// true on success, false on failure + /// This call is blocking + public bool Teleport(ulong regionHandle, Vector3 position, Vector3 lookAt) + { + if (Client.Network.CurrentSim == null || + Client.Network.CurrentSim.Caps == null || + !Client.Network.CurrentSim.Caps.IsEventQueueRunning) + { + // Wait a bit to see if the event queue comes online + AutoResetEvent queueEvent = new AutoResetEvent(false); + EventHandler queueCallback = + delegate(object sender, EventQueueRunningEventArgs e) + { + if (e.Simulator == Client.Network.CurrentSim) + queueEvent.Set(); + }; + + Client.Network.EventQueueRunning += queueCallback; + queueEvent.WaitOne(10 * 1000, false); + Client.Network.EventQueueRunning -= queueCallback; + } + + teleportStat = TeleportStatus.None; + teleportEvent.Reset(); + + RequestTeleport(regionHandle, position, lookAt); + + teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false); + + if (teleportStat == TeleportStatus.None || + teleportStat == TeleportStatus.Start || + teleportStat == TeleportStatus.Progress) + { + teleportMessage = "Teleport timed out."; + teleportStat = TeleportStatus.Failed; + } + + return (teleportStat == TeleportStatus.Finished); + } + + /// + /// Request teleport to a another simulator + /// + /// handle of region to teleport agent to + /// position in destination sim to teleport to + public void RequestTeleport(ulong regionHandle, Vector3 position) + { + RequestTeleport(regionHandle, position, new Vector3(0.0f, 1.0f, 0.0f)); + } + + /// + /// Request teleport to a another simulator + /// + /// handle of region to teleport agent to + /// position in destination sim to teleport to + /// direction in destination sim agent will look at + public void RequestTeleport(ulong regionHandle, Vector3 position, Vector3 lookAt) + { + if (Client.Network.CurrentSim != null && + Client.Network.CurrentSim.Caps != null && + Client.Network.CurrentSim.Caps.IsEventQueueRunning) + { + TeleportLocationRequestPacket teleport = new TeleportLocationRequestPacket(); + teleport.AgentData.AgentID = Client.Self.AgentID; + teleport.AgentData.SessionID = Client.Self.SessionID; + teleport.Info.LookAt = lookAt; + teleport.Info.Position = position; + teleport.Info.RegionHandle = regionHandle; + + Logger.Log("Requesting teleport to region handle " + regionHandle.ToString(), Helpers.LogLevel.Info, Client); + + Client.Network.SendPacket(teleport); + } + else + { + teleportMessage = "CAPS event queue is not running"; + teleportEvent.Set(); + teleportStat = TeleportStatus.Failed; + } + } + + /// + /// Teleport agent to a landmark + /// + /// of the landmark to teleport agent to + public void RequestTeleport(UUID landmark) + { + TeleportLandmarkRequestPacket p = new TeleportLandmarkRequestPacket(); + p.Info = new TeleportLandmarkRequestPacket.InfoBlock(); + p.Info.AgentID = Client.Self.AgentID; + p.Info.SessionID = Client.Self.SessionID; + p.Info.LandmarkID = landmark; + Client.Network.SendPacket(p); + } + + /// + /// Send a teleport lure to another avatar with default "Join me in ..." invitation message + /// + /// target avatars to lure + public void SendTeleportLure(UUID targetID) + { + SendTeleportLure(targetID, "Join me in " + Client.Network.CurrentSim.Name + "!"); + } + + /// + /// Send a teleport lure to another avatar with custom invitation message + /// + /// target avatars to lure + /// custom message to send with invitation + public void SendTeleportLure(UUID targetID, string message) + { + StartLurePacket p = new StartLurePacket(); + p.AgentData.AgentID = Client.Self.id; + p.AgentData.SessionID = Client.Self.SessionID; + p.Info.LureType = 0; + p.Info.Message = Utils.StringToBytes(message); + p.TargetData = new StartLurePacket.TargetDataBlock[] { new StartLurePacket.TargetDataBlock() }; + p.TargetData[0].TargetID = targetID; + Client.Network.SendPacket(p); + } + + /// + /// Respond to a teleport lure by either accepting it and initiating + /// the teleport, or denying it + /// + /// of the avatar sending the lure + /// IM session of the incoming lure request + /// true to accept the lure, false to decline it + public void TeleportLureRespond(UUID requesterID, UUID sessionID, bool accept) + { + if (accept) + { + TeleportLureRequestPacket lure = new TeleportLureRequestPacket(); + + lure.Info.AgentID = Client.Self.AgentID; + lure.Info.SessionID = Client.Self.SessionID; + lure.Info.LureID = sessionID; + lure.Info.TeleportFlags = (uint)TeleportFlags.ViaLure; + + Client.Network.SendPacket(lure); + } + else + { + InstantMessage(Name, requesterID, String.Empty, sessionID, + accept ? InstantMessageDialog.AcceptTeleport : InstantMessageDialog.DenyTeleport, + InstantMessageOnline.Offline, this.SimPosition, UUID.Zero, Utils.EmptyBytes); + } + } + + #endregion Teleporting + + #region Misc + + /// + /// Update agent profile + /// + /// struct containing updated + /// profile information + public void UpdateProfile(Avatar.AvatarProperties profile) + { + AvatarPropertiesUpdatePacket apup = new AvatarPropertiesUpdatePacket(); + apup.AgentData.AgentID = id; + apup.AgentData.SessionID = sessionID; + apup.PropertiesData.AboutText = Utils.StringToBytes(profile.AboutText); + apup.PropertiesData.AllowPublish = profile.AllowPublish; + apup.PropertiesData.FLAboutText = Utils.StringToBytes(profile.FirstLifeText); + apup.PropertiesData.FLImageID = profile.FirstLifeImage; + apup.PropertiesData.ImageID = profile.ProfileImage; + apup.PropertiesData.MaturePublish = profile.MaturePublish; + apup.PropertiesData.ProfileURL = Utils.StringToBytes(profile.ProfileURL); + + Client.Network.SendPacket(apup); + } + + /// + /// Update agents profile interests + /// + /// selection of interests from struct + public void UpdateInterests(Avatar.Interests interests) + { + AvatarInterestsUpdatePacket aiup = new AvatarInterestsUpdatePacket(); + aiup.AgentData.AgentID = id; + aiup.AgentData.SessionID = sessionID; + aiup.PropertiesData.LanguagesText = Utils.StringToBytes(interests.LanguagesText); + aiup.PropertiesData.SkillsMask = interests.SkillsMask; + aiup.PropertiesData.SkillsText = Utils.StringToBytes(interests.SkillsText); + aiup.PropertiesData.WantToMask = interests.WantToMask; + aiup.PropertiesData.WantToText = Utils.StringToBytes(interests.WantToText); + + Client.Network.SendPacket(aiup); + } + + /// + /// Set the height and the width of the client window. This is used + /// by the server to build a virtual camera frustum for our avatar + /// + /// New height of the viewer window + /// New width of the viewer window + public void SetHeightWidth(ushort height, ushort width) + { + AgentHeightWidthPacket heightwidth = new AgentHeightWidthPacket(); + heightwidth.AgentData.AgentID = Client.Self.AgentID; + heightwidth.AgentData.SessionID = Client.Self.SessionID; + heightwidth.AgentData.CircuitCode = Client.Network.CircuitCode; + heightwidth.HeightWidthBlock.Height = height; + heightwidth.HeightWidthBlock.Width = width; + heightwidth.HeightWidthBlock.GenCounter = heightWidthGenCounter++; + + Client.Network.SendPacket(heightwidth); + } + + /// + /// Request the list of muted objects and avatars for this agent + /// + public void RequestMuteList() + { + MuteListRequestPacket mute = new MuteListRequestPacket(); + mute.AgentData.AgentID = Client.Self.AgentID; + mute.AgentData.SessionID = Client.Self.SessionID; + mute.MuteData.MuteCRC = 0; + + Client.Network.SendPacket(mute); + } + + /// + /// Mute an object, resident, etc. + /// + /// Mute type + /// Mute UUID + /// Mute name + public void UpdateMuteListEntry(MuteType type, UUID id, string name) + { + UpdateMuteListEntry(type, id, name, MuteFlags.Default); + } + + /// + /// Mute an object, resident, etc. + /// + /// Mute type + /// Mute UUID + /// Mute name + /// Mute flags + public void UpdateMuteListEntry(MuteType type, UUID id, string name, MuteFlags flags) + { + UpdateMuteListEntryPacket p = new UpdateMuteListEntryPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + + p.MuteData.MuteType = (int)type; + p.MuteData.MuteID = id; + p.MuteData.MuteName = Utils.StringToBytes(name); + p.MuteData.MuteFlags = (uint)flags; + + Client.Network.SendPacket(p); + + MuteEntry me = new MuteEntry(); + me.Type = type; + me.ID = id; + me.Name = name; + me.Flags = flags; + lock (MuteList.Dictionary) + { + MuteList[string.Format("{0}|{1}", me.ID, me.Name)] = me; + } + OnMuteListUpdated(EventArgs.Empty); + + } + + /// + /// Unmute an object, resident, etc. + /// + /// Mute UUID + /// Mute name + public void RemoveMuteListEntry(UUID id, string name) + { + RemoveMuteListEntryPacket p = new RemoveMuteListEntryPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + + p.MuteData.MuteID = id; + p.MuteData.MuteName = Utils.StringToBytes(name); + + Client.Network.SendPacket(p); + + string listKey = string.Format("{0}|{1}", id, name); + if (MuteList.ContainsKey(listKey)) + { + lock (MuteList.Dictionary) + { + MuteList.Remove(listKey); + } + OnMuteListUpdated(EventArgs.Empty); + } + } + + /// + /// Sets home location to agents current position + /// + /// will fire an AlertMessage () with + /// success or failure message + public void SetHome() + { + SetStartLocationRequestPacket s = new SetStartLocationRequestPacket(); + s.AgentData = new SetStartLocationRequestPacket.AgentDataBlock(); + s.AgentData.AgentID = Client.Self.AgentID; + s.AgentData.SessionID = Client.Self.SessionID; + s.StartLocationData = new SetStartLocationRequestPacket.StartLocationDataBlock(); + s.StartLocationData.LocationPos = Client.Self.SimPosition; + s.StartLocationData.LocationID = 1; + s.StartLocationData.SimName = Utils.StringToBytes(String.Empty); + s.StartLocationData.LocationLookAt = Movement.Camera.AtAxis; + Client.Network.SendPacket(s); + } + + /// + /// Move an agent in to a simulator. This packet is the last packet + /// needed to complete the transition in to a new simulator + /// + /// Object + public void CompleteAgentMovement(Simulator simulator) + { + CompleteAgentMovementPacket move = new CompleteAgentMovementPacket(); + + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; + move.AgentData.CircuitCode = Client.Network.CircuitCode; + + Client.Network.SendPacket(move, simulator); + } + + /// + /// Reply to script permissions request + /// + /// Object + /// of the itemID requesting permissions + /// of the taskID requesting permissions + /// list of permissions to allow + public void ScriptQuestionReply(Simulator simulator, UUID itemID, UUID taskID, ScriptPermission permissions) + { + ScriptAnswerYesPacket yes = new ScriptAnswerYesPacket(); + yes.AgentData.AgentID = Client.Self.AgentID; + yes.AgentData.SessionID = Client.Self.SessionID; + yes.Data.ItemID = itemID; + yes.Data.TaskID = taskID; + yes.Data.Questions = (int)permissions; + + Client.Network.SendPacket(yes, simulator); + } + + /// + /// Respond to a group invitation by either accepting or denying it + /// + /// UUID of the group (sent in the AgentID field of the invite message) + /// IM Session ID from the group invitation message + /// Accept the group invitation or deny it + public void GroupInviteRespond(UUID groupID, UUID imSessionID, bool accept) + { + InstantMessage(Name, groupID, String.Empty, imSessionID, + accept ? InstantMessageDialog.GroupInvitationAccept : InstantMessageDialog.GroupInvitationDecline, + InstantMessageOnline.Offline, Vector3.Zero, UUID.Zero, Utils.EmptyBytes); + } + + /// + /// Requests script detection of objects and avatars + /// + /// name of the object/avatar to search for + /// UUID of the object or avatar to search for + /// Type of search from ScriptSensorTypeFlags + /// range of scan (96 max?) + /// the arc in radians to search within + /// an user generated ID to correlate replies with + /// Simulator to perform search in + public void RequestScriptSensor(string name, UUID searchID, ScriptSensorTypeFlags type, float range, float arc, UUID requestID, Simulator sim) + { + ScriptSensorRequestPacket request = new ScriptSensorRequestPacket(); + request.Requester.Arc = arc; + request.Requester.Range = range; + request.Requester.RegionHandle = sim.Handle; + request.Requester.RequestID = requestID; + request.Requester.SearchDir = Quaternion.Identity; // TODO: this needs to be tested + request.Requester.SearchID = searchID; + request.Requester.SearchName = Utils.StringToBytes(name); + request.Requester.SearchPos = Vector3.Zero; + request.Requester.SearchRegions = 0; // TODO: ? + request.Requester.SourceID = Client.Self.AgentID; + request.Requester.Type = (int)type; + + Client.Network.SendPacket(request, sim); + } + + /// + /// Create or update profile pick + /// + /// UUID of the pick to update, or random UUID to create a new pick + /// Is this a top pick? (typically false) + /// UUID of the parcel (UUID.Zero for the current parcel) + /// Name of the pick + /// Global position of the pick landmark + /// UUID of the image displayed with the pick + /// Long description of the pick + public void PickInfoUpdate(UUID pickID, bool topPick, UUID parcelID, string name, Vector3d globalPosition, UUID textureID, string description) + { + PickInfoUpdatePacket pick = new PickInfoUpdatePacket(); + pick.AgentData.AgentID = Client.Self.AgentID; + pick.AgentData.SessionID = Client.Self.SessionID; + pick.Data.PickID = pickID; + pick.Data.Desc = Utils.StringToBytes(description); + pick.Data.CreatorID = Client.Self.AgentID; + pick.Data.TopPick = topPick; + pick.Data.ParcelID = parcelID; + pick.Data.Name = Utils.StringToBytes(name); + pick.Data.SnapshotID = textureID; + pick.Data.PosGlobal = globalPosition; + pick.Data.SortOrder = 0; + pick.Data.Enabled = false; + + Client.Network.SendPacket(pick); + } + + /// + /// Delete profile pick + /// + /// UUID of the pick to delete + public void PickDelete(UUID pickID) + { + PickDeletePacket delete = new PickDeletePacket(); + delete.AgentData.AgentID = Client.Self.AgentID; + delete.AgentData.SessionID = Client.Self.sessionID; + delete.Data.PickID = pickID; + + Client.Network.SendPacket(delete); + } + + /// + /// Create or update profile Classified + /// + /// UUID of the classified to update, or random UUID to create a new classified + /// Defines what catagory the classified is in + /// UUID of the image displayed with the classified + /// Price that the classified will cost to place for a week + /// Global position of the classified landmark + /// Name of the classified + /// Long description of the classified + /// if true, auto renew classified after expiration + public void UpdateClassifiedInfo(UUID classifiedID, DirectoryManager.ClassifiedCategories category, + UUID snapshotID, int price, Vector3d position, string name, string desc, bool autoRenew) + { + ClassifiedInfoUpdatePacket classified = new ClassifiedInfoUpdatePacket(); + classified.AgentData.AgentID = Client.Self.AgentID; + classified.AgentData.SessionID = Client.Self.SessionID; + + classified.Data.ClassifiedID = classifiedID; + classified.Data.Category = (uint)category; + + classified.Data.ParcelID = UUID.Zero; + // TODO: verify/fix ^ + classified.Data.ParentEstate = 0; + // TODO: verify/fix ^ + + classified.Data.SnapshotID = snapshotID; + classified.Data.PosGlobal = position; + + classified.Data.ClassifiedFlags = autoRenew ? (byte)32 : (byte)0; + // TODO: verify/fix ^ + + classified.Data.PriceForListing = price; + classified.Data.Name = Utils.StringToBytes(name); + classified.Data.Desc = Utils.StringToBytes(desc); + Client.Network.SendPacket(classified); + } + + /// + /// Create or update profile Classified + /// + /// UUID of the classified to update, or random UUID to create a new classified + /// Defines what catagory the classified is in + /// UUID of the image displayed with the classified + /// Price that the classified will cost to place for a week + /// Name of the classified + /// Long description of the classified + /// if true, auto renew classified after expiration + public void UpdateClassifiedInfo(UUID classifiedID, DirectoryManager.ClassifiedCategories category, UUID snapshotID, int price, string name, string desc, bool autoRenew) + { + UpdateClassifiedInfo(classifiedID, category, snapshotID, price, Client.Self.GlobalPosition, name, desc, autoRenew); + } + + /// + /// Delete a classified ad + /// + /// The classified ads ID + public void DeleteClassfied(UUID classifiedID) + { + ClassifiedDeletePacket classified = new ClassifiedDeletePacket(); + classified.AgentData.AgentID = Client.Self.AgentID; + classified.AgentData.SessionID = Client.Self.SessionID; + + classified.Data.ClassifiedID = classifiedID; + Client.Network.SendPacket(classified); + } + + /// + /// Fetches resource usage by agents attachmetns + /// + /// Called when the requested information is collected + public void GetAttachmentResources(AttachmentResourcesCallback callback) + { + try + { + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("AttachmentResources"); + CapsClient request = new CapsClient(url); + + request.OnComplete += delegate(CapsClient client, OSD result, Exception error) + { + try + { + if (result == null || error != null) + { + callback(false, null); + } + AttachmentResourcesMessage info = AttachmentResourcesMessage.FromOSD(result); + callback(true, info); + + } + catch (Exception ex) + { + Logger.Log("Failed fetching AttachmentResources", Helpers.LogLevel.Error, Client, ex); + callback(false, null); + } + }; + + request.BeginGetResponse(Client.Settings.CAPS_TIMEOUT); + } + catch (Exception ex) + { + Logger.Log("Failed fetching AttachmentResources", Helpers.LogLevel.Error, Client, ex); + callback(false, null); + } + } + + /// + /// Initates request to set a new display name + /// + /// Previous display name + /// Desired new display name + public void SetDisplayName(string oldName, string newName) + { + Uri uri; + + if (Client.Network.CurrentSim == null || + Client.Network.CurrentSim.Caps == null || + (uri = Client.Network.CurrentSim.Caps.CapabilityURI("SetDisplayName")) == null) + { + Logger.Log("Unable to invoke SetDisplyName capability at this time", Helpers.LogLevel.Warning, Client); + return; + } + + SetDisplayNameMessage msg = new SetDisplayNameMessage(); + msg.OldDisplayName = oldName; + msg.NewDisplayName = newName; + + CapsClient cap = new CapsClient(uri); + cap.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + + /// + /// Tells the sim what UI language is used, and if it's ok to share that with scripts + /// + /// Two letter language code + /// Share language info with scripts + public void UpdateAgentLanguage(string language, bool isPublic) + { + try + { + UpdateAgentLanguageMessage msg = new UpdateAgentLanguageMessage(); + msg.Language = language; + msg.LanguagePublic = isPublic; + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateAgentLanguage"); + if (url != null) + { + CapsClient request = new CapsClient(url); + request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + } + catch (Exception ex) + { + Logger.Log("Failes to update agent language", Helpers.LogLevel.Error, Client, ex); + } + } + + public delegate void AgentAccessCallback(AgentAccessEventArgs e); + + /// + /// Sets agents maturity access level + /// + /// PG, M or A + public void SetAgentAccess(string access) + { + SetAgentAccess(access, null); + } + + /// + /// Sets agents maturity access level + /// + /// PG, M or A + /// Callback function + public void SetAgentAccess(string access, AgentAccessCallback callback) + { + if (Client == null || !Client.Network.Connected || Client.Network.CurrentSim.Caps == null) return; + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateAgentInformation"); + + if (url == null) return; + + CapsClient request = new CapsClient(url); + + request.OnComplete += (client, result, error) => + { + bool success = true; + + if (error == null && result is OSDMap) + { + var map = ((OSDMap)result)["access_prefs"]; + agentAccess = ((OSDMap)map)["max"]; + Logger.Log("Max maturity access set to " + agentAccess, Helpers.LogLevel.Info, Client ); + } + else if (error == null) + { + Logger.Log("Max maturity unchanged at " + agentAccess, Helpers.LogLevel.Info, Client); + } + else + { + Logger.Log("Failed setting max maturity access.", Helpers.LogLevel.Warning, Client); + success = false; + } + + if (callback != null) + { + try { callback(new AgentAccessEventArgs(success, agentAccess)); } + catch { } + } + + }; + OSDMap req = new OSDMap(); + OSDMap prefs = new OSDMap(); + prefs["max"] = access; + req["access_prefs"] = prefs; + + request.BeginGetResponse(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + #endregion Misc + + #region Packet Handlers + + /// + /// Take an incoming ImprovedInstantMessage packet, auto-parse, and if + /// OnInstantMessage is defined call that with the appropriate arguments + /// + /// The sender + /// The EventArgs object containing the packet data + protected void InstantMessageHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + if (packet.Type == PacketType.ImprovedInstantMessage) + { + ImprovedInstantMessagePacket im = (ImprovedInstantMessagePacket)packet; + + if (m_InstantMessage != null) + { + InstantMessage message; + message.FromAgentID = im.AgentData.AgentID; + message.FromAgentName = Utils.BytesToString(im.MessageBlock.FromAgentName); + message.ToAgentID = im.MessageBlock.ToAgentID; + message.ParentEstateID = im.MessageBlock.ParentEstateID; + message.RegionID = im.MessageBlock.RegionID; + message.Position = im.MessageBlock.Position; + message.Dialog = (InstantMessageDialog)im.MessageBlock.Dialog; + message.GroupIM = im.MessageBlock.FromGroup; + message.IMSessionID = im.MessageBlock.ID; + message.Timestamp = new DateTime(im.MessageBlock.Timestamp); + message.Message = Utils.BytesToString(im.MessageBlock.Message); + message.Offline = (InstantMessageOnline)im.MessageBlock.Offline; + message.BinaryBucket = im.MessageBlock.BinaryBucket; + + OnInstantMessage(new InstantMessageEventArgs(message, simulator)); + } + } + } + + /// + /// Take an incoming Chat packet, auto-parse, and if OnChat is defined call + /// that with the appropriate arguments. + /// + /// The sender + /// The EventArgs object containing the packet data + protected void ChatHandler(object sender, PacketReceivedEventArgs e) + { + if (m_Chat != null) + { + Packet packet = e.Packet; + + ChatFromSimulatorPacket chat = (ChatFromSimulatorPacket)packet; + + OnChat(new ChatEventArgs(e.Simulator, Utils.BytesToString(chat.ChatData.Message), + (ChatAudibleLevel)chat.ChatData.Audible, + (ChatType)chat.ChatData.ChatType, + (ChatSourceType)chat.ChatData.SourceType, + Utils.BytesToString(chat.ChatData.FromName), + chat.ChatData.SourceID, + chat.ChatData.OwnerID, + chat.ChatData.Position)); + } + } + + /// + /// Used for parsing llDialogs + /// + /// The sender + /// The EventArgs object containing the packet data + protected void ScriptDialogHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ScriptDialog != null) + { + Packet packet = e.Packet; + + ScriptDialogPacket dialog = (ScriptDialogPacket)packet; + List buttons = new List(); + + foreach (ScriptDialogPacket.ButtonsBlock button in dialog.Buttons) + { + buttons.Add(Utils.BytesToString(button.ButtonLabel)); + } + + UUID ownerID = UUID.Zero; + + if (dialog.OwnerData != null && dialog.OwnerData.Length > 0) + { + ownerID = dialog.OwnerData[0].OwnerID; + } + + OnScriptDialog(new ScriptDialogEventArgs(Utils.BytesToString(dialog.Data.Message), + Utils.BytesToString(dialog.Data.ObjectName), + dialog.Data.ImageID, + dialog.Data.ObjectID, + Utils.BytesToString(dialog.Data.FirstName), + Utils.BytesToString(dialog.Data.LastName), + dialog.Data.ChatChannel, + buttons, + ownerID)); + } + } + + /// + /// Used for parsing llRequestPermissions dialogs + /// + /// The sender + /// The EventArgs object containing the packet data + protected void ScriptQuestionHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ScriptQuestion != null) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ScriptQuestionPacket question = (ScriptQuestionPacket)packet; + + OnScriptQuestion(new ScriptQuestionEventArgs(simulator, + question.Data.TaskID, + question.Data.ItemID, + Utils.BytesToString(question.Data.ObjectName), + Utils.BytesToString(question.Data.ObjectOwner), + (ScriptPermission)question.Data.Questions)); + } + } + + /// + /// Handles Script Control changes when Script with permissions releases or takes a control + /// + /// The sender + /// The EventArgs object containing the packet data + private void ScriptControlChangeHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ScriptControl != null) + { + Packet packet = e.Packet; + + ScriptControlChangePacket change = (ScriptControlChangePacket)packet; + for (int i = 0; i < change.Data.Length; i++) + { + OnScriptControlChange(new ScriptControlEventArgs((ScriptControlChange)change.Data[i].Controls, + change.Data[i].PassToAgent, + change.Data[i].TakeControls)); + } + } + } + + /// + /// Used for parsing llLoadURL Dialogs + /// + /// The sender + /// The EventArgs object containing the packet data + protected void LoadURLHandler(object sender, PacketReceivedEventArgs e) + { + + if (m_LoadURL != null) + { + Packet packet = e.Packet; + + LoadURLPacket loadURL = (LoadURLPacket)packet; + + OnLoadURL(new LoadUrlEventArgs( + Utils.BytesToString(loadURL.Data.ObjectName), + loadURL.Data.ObjectID, + loadURL.Data.OwnerID, + loadURL.Data.OwnerIsGroup, + Utils.BytesToString(loadURL.Data.Message), + Utils.BytesToString(loadURL.Data.URL) + )); + } + } + + /// + /// Update client's Position, LookAt and region handle from incoming packet + /// + /// The sender + /// The EventArgs object containing the packet data + /// This occurs when after an avatar moves into a new sim + private void MovementCompleteHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + AgentMovementCompletePacket movement = (AgentMovementCompletePacket)packet; + + relativePosition = movement.Data.Position; + Movement.Camera.LookDirection(movement.Data.LookAt); + simulator.Handle = movement.Data.RegionHandle; + simulator.SimVersion = Utils.BytesToString(movement.SimData.ChannelVersion); + simulator.AgentMovementComplete = true; + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void HealthHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + health = ((HealthMessagePacket)packet).HealthData.Health; + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AgentDataUpdateHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet; + + if (p.AgentData.AgentID == simulator.Client.Self.AgentID) + { + firstName = Utils.BytesToString(p.AgentData.FirstName); + lastName = Utils.BytesToString(p.AgentData.LastName); + activeGroup = p.AgentData.ActiveGroupID; + activeGroupPowers = (GroupPowers)p.AgentData.GroupPowers; + + if (m_AgentData != null) + { + string groupTitle = Utils.BytesToString(p.AgentData.GroupTitle); + string groupName = Utils.BytesToString(p.AgentData.GroupName); + + OnAgentData(new AgentDataReplyEventArgs(firstName, lastName, activeGroup, groupTitle, activeGroupPowers, groupName)); + } + } + else + { + Logger.Log("Got an AgentDataUpdate packet for avatar " + p.AgentData.AgentID.ToString() + + " instead of " + Client.Self.AgentID.ToString() + ", this shouldn't happen", Helpers.LogLevel.Error, Client); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void MoneyBalanceReplyHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + if (packet.Type == PacketType.MoneyBalanceReply) + { + MoneyBalanceReplyPacket reply = (MoneyBalanceReplyPacket)packet; + this.balance = reply.MoneyData.MoneyBalance; + + if (m_MoneyBalance != null) + { + TransactionInfo transactionInfo = new TransactionInfo(); + transactionInfo.TransactionType = reply.TransactionInfo.TransactionType; + transactionInfo.SourceID = reply.TransactionInfo.SourceID; + transactionInfo.IsSourceGroup = reply.TransactionInfo.IsSourceGroup; + transactionInfo.DestID = reply.TransactionInfo.DestID; + transactionInfo.IsDestGroup = reply.TransactionInfo.IsDestGroup; + transactionInfo.Amount = reply.TransactionInfo.Amount; + transactionInfo.ItemDescription = Utils.BytesToString(reply.TransactionInfo.ItemDescription); + + OnMoneyBalanceReply(new MoneyBalanceReplyEventArgs(reply.MoneyData.TransactionID, + reply.MoneyData.TransactionSuccess, + reply.MoneyData.MoneyBalance, + reply.MoneyData.SquareMetersCredit, + reply.MoneyData.SquareMetersCommitted, + Utils.BytesToString(reply.MoneyData.Description), + transactionInfo)); + } + } + + if (m_Balance != null) + { + OnBalance(new BalanceEventArgs(balance)); + } + } + + /// + /// EQ Message fired with the result of SetDisplayName request + /// + /// The message key + /// the IMessage object containing the deserialized data sent from the simulator + /// The which originated the packet + protected void SetDisplayNameReplyEventHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_SetDisplayNameReply != null) + { + SetDisplayNameReplyMessage msg = (SetDisplayNameReplyMessage)message; + OnSetDisplayNameReply(new SetDisplayNameReplyEventArgs(msg.Status, msg.Reason, msg.DisplayName)); + } + } + + protected void AgentStateUpdateEventHandler(string capsKey, IMessage message, Simulator simulator) + { + if (message is AgentStateUpdateMessage) + { + AgentStateStatus = (AgentStateUpdateMessage)message; + } + } + + protected void EstablishAgentCommunicationEventHandler(string capsKey, IMessage message, Simulator simulator) + { + EstablishAgentCommunicationMessage msg = (EstablishAgentCommunicationMessage)message; + + if (Client.Settings.MULTIPLE_SIMS) + { + + IPEndPoint endPoint = new IPEndPoint(msg.Address, msg.Port); + Simulator sim = Client.Network.FindSimulator(endPoint); + + if (sim == null) + { + Logger.Log("Got EstablishAgentCommunication for unknown sim " + msg.Address + ":" + msg.Port, + Helpers.LogLevel.Error, Client); + + // FIXME: Should we use this opportunity to connect to the simulator? + } + else + { + Logger.Log("Got EstablishAgentCommunication for " + sim.ToString(), + Helpers.LogLevel.Info, Client); + + sim.SetSeedCaps(msg.SeedCapability.ToString()); + } + } + } + + /// + /// Process TeleportFailed message sent via EventQueue, informs agent its last teleport has failed and why. + /// + /// The Message Key + /// An IMessage object Deserialized from the recieved message event + /// The simulator originating the event message + public void TeleportFailedEventHandler(string messageKey, IMessage message, Simulator simulator) + { + TeleportFailedMessage msg = (TeleportFailedMessage)message; + + TeleportFailedPacket failedPacket = new TeleportFailedPacket(); + failedPacket.Info.AgentID = msg.AgentID; + failedPacket.Info.Reason = Utils.StringToBytes(msg.Reason); + + TeleportHandler(this, new PacketReceivedEventArgs(failedPacket, simulator)); + } + + /// + /// Process TeleportFinish from Event Queue and pass it onto our TeleportHandler + /// + /// The message system key for this event + /// IMessage object containing decoded data from OSD + /// The simulator originating the event message + private void TeleportFinishEventHandler(string capsKey, IMessage message, Simulator simulator) + { + TeleportFinishMessage msg = (TeleportFinishMessage)message; + + TeleportFinishPacket p = new TeleportFinishPacket(); + p.Info.AgentID = msg.AgentID; + p.Info.LocationID = (uint)msg.LocationID; + p.Info.RegionHandle = msg.RegionHandle; + p.Info.SeedCapability = Utils.StringToBytes(msg.SeedCapability.ToString()); // FIXME: Check This + p.Info.SimAccess = (byte)msg.SimAccess; + p.Info.SimIP = Utils.IPToUInt(msg.IP); + p.Info.SimPort = (ushort)msg.Port; + p.Info.TeleportFlags = (uint)msg.Flags; + + // pass the packet onto the teleport handler + TeleportHandler(this, new PacketReceivedEventArgs(p, simulator)); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void TeleportHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + bool finished = false; + TeleportFlags flags = TeleportFlags.Default; + + if (packet.Type == PacketType.TeleportStart) + { + TeleportStartPacket start = (TeleportStartPacket)packet; + + teleportMessage = "Teleport started"; + flags = (TeleportFlags)start.Info.TeleportFlags; + teleportStat = TeleportStatus.Start; + + Logger.DebugLog("TeleportStart received, Flags: " + flags.ToString(), Client); + } + else if (packet.Type == PacketType.TeleportProgress) + { + TeleportProgressPacket progress = (TeleportProgressPacket)packet; + + teleportMessage = Utils.BytesToString(progress.Info.Message); + flags = (TeleportFlags)progress.Info.TeleportFlags; + teleportStat = TeleportStatus.Progress; + + Logger.DebugLog("TeleportProgress received, Message: " + teleportMessage + ", Flags: " + flags.ToString(), Client); + } + else if (packet.Type == PacketType.TeleportFailed) + { + TeleportFailedPacket failed = (TeleportFailedPacket)packet; + + teleportMessage = Utils.BytesToString(failed.Info.Reason); + teleportStat = TeleportStatus.Failed; + finished = true; + + Logger.DebugLog("TeleportFailed received, Reason: " + teleportMessage, Client); + } + else if (packet.Type == PacketType.TeleportFinish) + { + TeleportFinishPacket finish = (TeleportFinishPacket)packet; + + flags = (TeleportFlags)finish.Info.TeleportFlags; + string seedcaps = Utils.BytesToString(finish.Info.SeedCapability); + finished = true; + + Logger.DebugLog("TeleportFinish received, Flags: " + flags.ToString(), Client); + + // Connect to the new sim + Client.Network.CurrentSim.AgentMovementComplete = false; // we're not there anymore + Simulator newSimulator = Client.Network.Connect(new IPAddress(finish.Info.SimIP), + finish.Info.SimPort, finish.Info.RegionHandle, true, seedcaps); + + if (newSimulator != null) + { + teleportMessage = "Teleport finished"; + teleportStat = TeleportStatus.Finished; + + Logger.Log("Moved to new sim " + newSimulator.ToString(), Helpers.LogLevel.Info, Client); + } + else + { + teleportMessage = "Failed to connect to the new sim after a teleport"; + teleportStat = TeleportStatus.Failed; + + // We're going to get disconnected now + Logger.Log(teleportMessage, Helpers.LogLevel.Error, Client); + } + } + else if (packet.Type == PacketType.TeleportCancel) + { + //TeleportCancelPacket cancel = (TeleportCancelPacket)packet; + + teleportMessage = "Cancelled"; + teleportStat = TeleportStatus.Cancelled; + finished = true; + + Logger.DebugLog("TeleportCancel received from " + simulator.ToString(), Client); + } + else if (packet.Type == PacketType.TeleportLocal) + { + TeleportLocalPacket local = (TeleportLocalPacket)packet; + + teleportMessage = "Teleport finished"; + flags = (TeleportFlags)local.Info.TeleportFlags; + teleportStat = TeleportStatus.Finished; + relativePosition = local.Info.Position; + Movement.Camera.LookDirection(local.Info.LookAt); + // This field is apparently not used for anything + //local.Info.LocationID; + finished = true; + + Logger.DebugLog("TeleportLocal received, Flags: " + flags.ToString(), Client); + } + + if (m_Teleport != null) + { + OnTeleport(new TeleportEventArgs(teleportMessage, teleportStat, flags)); + } + + if (finished) teleportEvent.Set(); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarAnimationHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + AvatarAnimationPacket animation = (AvatarAnimationPacket)packet; + + if (animation.Sender.ID == Client.Self.AgentID) + { + lock (SignaledAnimations.Dictionary) + { + // Reset the signaled animation list + SignaledAnimations.Dictionary.Clear(); + + for (int i = 0; i < animation.AnimationList.Length; i++) + { + UUID animID = animation.AnimationList[i].AnimID; + int sequenceID = animation.AnimationList[i].AnimSequenceID; + + // Add this animation to the list of currently signaled animations + SignaledAnimations.Dictionary[animID] = sequenceID; + + if (i < animation.AnimationSourceList.Length) + { + // FIXME: The server tells us which objects triggered our animations, + // we should store this info + + //animation.AnimationSourceList[i].ObjectID + } + + if (i < animation.PhysicalAvatarEventList.Length) + { + // FIXME: What is this? + } + + if (Client.Settings.SEND_AGENT_UPDATES) + { + // We have to manually tell the server to stop playing some animations + if (animID == Animations.STANDUP || + animID == Animations.PRE_JUMP || + animID == Animations.LAND || + animID == Animations.MEDIUM_LAND) + { + Movement.FinishAnim = true; + Movement.SendUpdate(true); + Movement.FinishAnim = false; + } + } + } + } + } + + if (m_AnimationsChanged != null) + { + WorkPool.QueueUserWorkItem(delegate(object o) + { OnAnimationsChanged(new AnimationsChangedEventArgs(this.SignaledAnimations)); }); + } + + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void MeanCollisionAlertHandler(object sender, PacketReceivedEventArgs e) + { + if (m_MeanCollision != null) + { + Packet packet = e.Packet; + MeanCollisionAlertPacket collision = (MeanCollisionAlertPacket)packet; + + for (int i = 0; i < collision.MeanCollision.Length; i++) + { + MeanCollisionAlertPacket.MeanCollisionBlock block = collision.MeanCollision[i]; + + DateTime time = Utils.UnixTimeToDateTime(block.Time); + MeanCollisionType type = (MeanCollisionType)block.Type; + + OnMeanCollision(new MeanCollisionEventArgs(type, block.Perp, block.Victim, block.Mag, time)); + } + } + } + + private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason, + LoginResponseData reply) + { + id = reply.AgentID; + sessionID = reply.SessionID; + secureSessionID = reply.SecureSessionID; + firstName = reply.FirstName; + lastName = reply.LastName; + startLocation = reply.StartLocation; + agentAccess = reply.AgentAccess; + Movement.Camera.LookDirection(reply.LookAt); + homePosition = reply.HomePosition; + homeLookAt = reply.HomeLookAt; + lookAt = reply.LookAt; + } + + private void Network_OnDisconnected(object sender, DisconnectedEventArgs e) + { + // Null out the cached fullName since it can change after logging + // in again (with a different account name or different login + // server but using the same GridClient object + fullName = null; + } + + /// + /// Crossed region handler for message that comes across the EventQueue. Sent to an agent + /// when the agent crosses a sim border into a new region. + /// + /// The message key + /// the IMessage object containing the deserialized data sent from the simulator + /// The which originated the packet + private void CrossedRegionEventHandler(string capsKey, IMessage message, Simulator simulator) + { + CrossedRegionMessage crossed = (CrossedRegionMessage)message; + + IPEndPoint endPoint = new IPEndPoint(crossed.IP, crossed.Port); + + Logger.DebugLog("Crossed in to new region area, attempting to connect to " + endPoint.ToString(), Client); + + Simulator oldSim = Client.Network.CurrentSim; + Simulator newSim = Client.Network.Connect(endPoint, crossed.RegionHandle, true, crossed.SeedCapability.ToString()); + + if (newSim != null) + { + Logger.Log("Finished crossing over in to region " + newSim.ToString(), Helpers.LogLevel.Info, Client); + oldSim.AgentMovementComplete = false; // We're no longer there + if (m_RegionCrossed != null) + { + OnRegionCrossed(new RegionCrossedEventArgs(oldSim, newSim)); + } + } + else + { + // The old simulator will (poorly) handle our movement still, so the connection isn't + // completely shot yet + Logger.Log("Failed to connect to new region " + endPoint.ToString() + " after crossing over", + Helpers.LogLevel.Warning, Client); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + /// This packet is now being sent via the EventQueue + protected void CrossedRegionHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + CrossedRegionPacket crossing = (CrossedRegionPacket)packet; + string seedCap = Utils.BytesToString(crossing.RegionData.SeedCapability); + IPEndPoint endPoint = new IPEndPoint(crossing.RegionData.SimIP, crossing.RegionData.SimPort); + + Logger.DebugLog("Crossed in to new region area, attempting to connect to " + endPoint.ToString(), Client); + + Simulator oldSim = Client.Network.CurrentSim; + Simulator newSim = Client.Network.Connect(endPoint, crossing.RegionData.RegionHandle, true, seedCap); + + if (newSim != null) + { + Logger.Log("Finished crossing over in to region " + newSim.ToString(), Helpers.LogLevel.Info, Client); + + if (m_RegionCrossed != null) + { + OnRegionCrossed(new RegionCrossedEventArgs(oldSim, newSim)); + } + } + else + { + // The old simulator will (poorly) handle our movement still, so the connection isn't + // completely shot yet + Logger.Log("Failed to connect to new region " + endPoint.ToString() + " after crossing over", + Helpers.LogLevel.Warning, Client); + } + } + + /// + /// Group Chat event handler + /// + /// The capability Key + /// IMessage object containing decoded data from OSD + /// + protected void ChatterBoxSessionEventReplyEventHandler(string capsKey, IMessage message, Simulator simulator) + { + ChatterboxSessionEventReplyMessage msg = (ChatterboxSessionEventReplyMessage)message; + + if (!msg.Success) + { + RequestJoinGroupChat(msg.SessionID); + Logger.Log("Attempt to send group chat to non-existant session for group " + msg.SessionID, + Helpers.LogLevel.Info, Client); + } + } + + /// + /// Response from request to join a group chat + /// + /// + /// IMessage object containing decoded data from OSD + /// + protected void ChatterBoxSessionStartReplyEventHandler(string capsKey, IMessage message, Simulator simulator) + { + ChatterBoxSessionStartReplyMessage msg = (ChatterBoxSessionStartReplyMessage)message; + + if (msg.Success) + { + lock (GroupChatSessions.Dictionary) + if (!GroupChatSessions.ContainsKey(msg.SessionID)) + GroupChatSessions.Add(msg.SessionID, new List()); + } + + OnGroupChatJoined(new GroupChatJoinedEventArgs(msg.SessionID, msg.SessionName, msg.TempSessionID, msg.Success)); + } + + /// + /// Someone joined or left group chat + /// + /// + /// IMessage object containing decoded data from OSD + /// + private void ChatterBoxSessionAgentListUpdatesEventHandler(string capsKey, IMessage message, Simulator simulator) + { + ChatterBoxSessionAgentListUpdatesMessage msg = (ChatterBoxSessionAgentListUpdatesMessage)message; + + lock (GroupChatSessions.Dictionary) + if (!GroupChatSessions.ContainsKey(msg.SessionID)) + GroupChatSessions.Add(msg.SessionID, new List()); + + for (int i = 0; i < msg.Updates.Length; i++) + { + ChatSessionMember fndMbr; + lock (GroupChatSessions.Dictionary) + { + fndMbr = GroupChatSessions[msg.SessionID].Find(delegate(ChatSessionMember member) + { + return member.AvatarKey == msg.Updates[i].AgentID; + }); + } + + if (msg.Updates[i].Transition != null) + { + if (msg.Updates[i].Transition.Equals("ENTER")) + { + if (fndMbr.AvatarKey == UUID.Zero) + { + fndMbr = new ChatSessionMember(); + fndMbr.AvatarKey = msg.Updates[i].AgentID; + + lock (GroupChatSessions.Dictionary) + GroupChatSessions[msg.SessionID].Add(fndMbr); + + if (m_ChatSessionMemberAdded != null) + { + OnChatSessionMemberAdded(new ChatSessionMemberAddedEventArgs(msg.SessionID, fndMbr.AvatarKey)); + } + } + } + else if (msg.Updates[i].Transition.Equals("LEAVE")) + { + if (fndMbr.AvatarKey != UUID.Zero) + lock (GroupChatSessions.Dictionary) + GroupChatSessions[msg.SessionID].Remove(fndMbr); + + if (m_ChatSessionMemberLeft != null) + { + OnChatSessionMemberLeft(new ChatSessionMemberLeftEventArgs(msg.SessionID, msg.Updates[i].AgentID)); + } + } + } + + // handle updates + ChatSessionMember update_member = GroupChatSessions.Dictionary[msg.SessionID].Find(delegate(ChatSessionMember m) + { + return m.AvatarKey == msg.Updates[i].AgentID; + }); + + + update_member.MuteText = msg.Updates[i].MuteText; + update_member.MuteVoice = msg.Updates[i].MuteVoice; + + update_member.CanVoiceChat = msg.Updates[i].CanVoiceChat; + update_member.IsModerator = msg.Updates[i].IsModerator; + + // replace existing member record + lock (GroupChatSessions.Dictionary) + { + int found = GroupChatSessions.Dictionary[msg.SessionID].FindIndex(delegate(ChatSessionMember m) + { + return m.AvatarKey == msg.Updates[i].AgentID; + }); + + if (found >= 0) + GroupChatSessions.Dictionary[msg.SessionID][found] = update_member; + } + } + } + + /// + /// Handle a group chat Invitation + /// + /// Caps Key + /// IMessage object containing decoded data from OSD + /// Originating Simulator + private void ChatterBoxInvitationEventHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_InstantMessage != null) + { + ChatterBoxInvitationMessage msg = (ChatterBoxInvitationMessage)message; + + //TODO: do something about invitations to voice group chat/friends conference + //Skip for now + if (msg.Voice) return; + + InstantMessage im = new InstantMessage(); + + im.FromAgentID = msg.FromAgentID; + im.FromAgentName = msg.FromAgentName; + im.ToAgentID = msg.ToAgentID; + im.ParentEstateID = (uint)msg.ParentEstateID; + im.RegionID = msg.RegionID; + im.Position = msg.Position; + im.Dialog = msg.Dialog; + im.GroupIM = msg.GroupIM; + im.IMSessionID = msg.IMSessionID; + im.Timestamp = msg.Timestamp; + im.Message = msg.Message; + im.Offline = msg.Offline; + im.BinaryBucket = msg.BinaryBucket; + try + { + ChatterBoxAcceptInvite(msg.IMSessionID); + } + catch (Exception ex) + { + Logger.Log("Failed joining IM:", Helpers.LogLevel.Warning, Client, ex); + } + OnInstantMessage(new InstantMessageEventArgs(im, simulator)); + } + } + + + /// + /// Moderate a chat session + /// + /// the of the session to moderate, for group chats this will be the groups UUID + /// the of the avatar to moderate + /// Either "voice" to moderate users voice, or "text" to moderate users text session + /// true to moderate (silence user), false to allow avatar to speak + public void ModerateChatSessions(UUID sessionID, UUID memberID, string key, bool moderate) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + throw new Exception("ChatSessionRequest capability is not currently available"); + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("ChatSessionRequest"); + + if (url != null) + { + ChatSessionRequestMuteUpdate req = new ChatSessionRequestMuteUpdate(); + + req.RequestKey = key; + req.RequestValue = moderate; + req.SessionID = sessionID; + req.AgentID = memberID; + + CapsClient request = new CapsClient(url); + request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("ChatSessionRequest capability is not currently available"); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AlertMessageHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AlertMessage != null) + { + Packet packet = e.Packet; + + AlertMessagePacket alert = (AlertMessagePacket)packet; + + OnAlertMessage(new AlertMessageEventArgs(Utils.BytesToString(alert.AlertData.Message))); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void CameraConstraintHandler(object sender, PacketReceivedEventArgs e) + { + if (m_CameraConstraint != null) + { + Packet packet = e.Packet; + + CameraConstraintPacket camera = (CameraConstraintPacket)packet; + OnCameraConstraint(new CameraConstraintEventArgs(camera.CameraCollidePlane.Plane)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ScriptSensorReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ScriptSensorReply != null) + { + Packet packet = e.Packet; + + ScriptSensorReplyPacket reply = (ScriptSensorReplyPacket)packet; + + for (int i = 0; i < reply.SensedData.Length; i++) + { + ScriptSensorReplyPacket.SensedDataBlock block = reply.SensedData[i]; + ScriptSensorReplyPacket.RequesterBlock requestor = reply.Requester; + + OnScriptSensorReply(new ScriptSensorReplyEventArgs(requestor.SourceID, block.GroupID, Utils.BytesToString(block.Name), + block.ObjectID, block.OwnerID, block.Position, block.Range, block.Rotation, (ScriptSensorTypeFlags)block.Type, block.Velocity)); + } + } + + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarSitResponseHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarSitResponse != null) + { + Packet packet = e.Packet; + + AvatarSitResponsePacket sit = (AvatarSitResponsePacket)packet; + + OnAvatarSitResponse(new AvatarSitResponseEventArgs(sit.SitObject.ID, sit.SitTransform.AutoPilot, sit.SitTransform.CameraAtOffset, + sit.SitTransform.CameraEyeOffset, sit.SitTransform.ForceMouselook, sit.SitTransform.SitPosition, + sit.SitTransform.SitRotation)); + } + } + + protected void MuteListUpdateHander(object sender, PacketReceivedEventArgs e) + { + MuteListUpdatePacket packet = (MuteListUpdatePacket)e.Packet; + if (packet.MuteData.AgentID != Client.Self.AgentID) + { + return; + } + + WorkPool.QueueUserWorkItem(sync => + { + using (AutoResetEvent gotMuteList = new AutoResetEvent(false)) + { + string fileName = Utils.BytesToString(packet.MuteData.Filename); + string muteList = string.Empty; + ulong xferID = 0; + byte[] assetData = null; + + EventHandler xferCallback = (object xsender, XferReceivedEventArgs xe) => + { + if (xe.Xfer.XferID == xferID) + { + assetData = xe.Xfer.AssetData; + gotMuteList.Set(); + } + }; + + + Client.Assets.XferReceived += xferCallback; + xferID = Client.Assets.RequestAssetXfer(fileName, true, false, UUID.Zero, AssetType.Unknown, true); + + if (gotMuteList.WaitOne(60 * 1000, false)) + { + muteList = Utils.BytesToString(assetData); + + lock (MuteList.Dictionary) + { + MuteList.Dictionary.Clear(); + foreach (var line in muteList.Split('\n')) + { + if (line.Trim() == string.Empty) continue; + + try + { + Match m; + if ((m = Regex.Match(line, @"(?\d+)\s+(?[a-zA-Z0-9-]+)\s+(?[^|]+)|(?.+)", RegexOptions.CultureInvariant)).Success) + { + MuteEntry me = new MuteEntry(); + me.Type = (MuteType)int.Parse(m.Groups["MyteType"].Value); + me.ID = new UUID(m.Groups["Key"].Value); + me.Name = m.Groups["Name"].Value; + int flags = 0; + int.TryParse(m.Groups["Flags"].Value, out flags); + me.Flags = (MuteFlags)flags; + MuteList[string.Format("{0}|{1}", me.ID, me.Name)] = me; + } + else + { + throw new ArgumentException("Invalid mutelist entry line"); + } + } + catch (Exception ex) + { + Logger.Log("Failed to parse the mute list line: " + line, Helpers.LogLevel.Warning, Client, ex); + } + } + } + + OnMuteListUpdated(EventArgs.Empty); + } + else + { + Logger.Log("Timed out waiting for mute list download", Helpers.LogLevel.Warning, Client); + } + + Client.Assets.XferReceived -= xferCallback; + + } + }); + } + + #endregion Packet Handlers + } + + #region Event Argument Classes + /// + /// Class for sending info on the success of the opration + /// of setting the maturity access level + /// + public class AgentAccessEventArgs : EventArgs + { + readonly string mNewLevel; + readonly bool mSuccess; + + /// + /// New maturity accesss level returned from the sim + /// + public string NewLevel { get { return mNewLevel; } } + + /// + /// True if setting the new maturity access level has succedded + /// + public bool Success { get { return mSuccess; } } + + /// + /// Creates new instance of the EventArgs class + /// + /// Has setting new maturty access level succeeded + /// New maturity access level as returned by the simulator + public AgentAccessEventArgs(bool success, string newLevel) + { + mNewLevel = newLevel; + mSuccess = success; + } + } + + /// + /// + /// + public class ChatEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly string m_Message; + private readonly ChatAudibleLevel m_AudibleLevel; + private readonly ChatType m_Type; + private readonly ChatSourceType m_SourceType; + private readonly string m_FromName; + private readonly UUID m_SourceID; + private readonly UUID m_OwnerID; + private readonly Vector3 m_Position; + + /// Get the simulator sending the message + public Simulator Simulator { get { return m_Simulator; } } + /// Get the message sent + public string Message { get { return m_Message; } } + /// Get the audible level of the message + public ChatAudibleLevel AudibleLevel { get { return m_AudibleLevel; } } + /// Get the type of message sent: whisper, shout, etc + public ChatType Type { get { return m_Type; } } + /// Get the source type of the message sender + public ChatSourceType SourceType { get { return m_SourceType; } } + /// Get the name of the agent or object sending the message + public string FromName { get { return m_FromName; } } + /// Get the ID of the agent or object sending the message + public UUID SourceID { get { return m_SourceID; } } + /// Get the ID of the object owner, or the agent ID sending the message + public UUID OwnerID { get { return m_OwnerID; } } + /// Get the position of the agent or object sending the message + public Vector3 Position { get { return m_Position; } } + + /// + /// Construct a new instance of the ChatEventArgs object + /// + /// Sim from which the message originates + /// The message sent + /// The audible level of the message + /// The type of message sent: whisper, shout, etc + /// The source type of the message sender + /// The name of the agent or object sending the message + /// The ID of the agent or object sending the message + /// The ID of the object owner, or the agent ID sending the message + /// The position of the agent or object sending the message + public ChatEventArgs(Simulator simulator, string message, ChatAudibleLevel audible, ChatType type, + ChatSourceType sourceType, string fromName, UUID sourceId, UUID ownerid, Vector3 position) + { + this.m_Simulator = simulator; + this.m_Message = message; + this.m_AudibleLevel = audible; + this.m_Type = type; + this.m_SourceType = sourceType; + this.m_FromName = fromName; + this.m_SourceID = sourceId; + this.m_Position = position; + this.m_OwnerID = ownerid; + } + } + + /// Contains the data sent when a primitive opens a dialog with this agent + public class ScriptDialogEventArgs : EventArgs + { + private readonly string m_Message; + private readonly string m_ObjectName; + private readonly UUID m_ImageID; + private readonly UUID m_ObjectID; + private readonly string m_FirstName; + private readonly string m_LastName; + private readonly int m_Channel; + private readonly List m_ButtonLabels; + private readonly UUID m_OwnerID; + + /// Get the dialog message + public string Message { get { return m_Message; } } + /// Get the name of the object that sent the dialog request + public string ObjectName { get { return m_ObjectName; } } + /// Get the ID of the image to be displayed + public UUID ImageID { get { return m_ImageID; } } + /// Get the ID of the primitive sending the dialog + public UUID ObjectID { get { return m_ObjectID; } } + /// Get the first name of the senders owner + public string FirstName { get { return m_FirstName; } } + /// Get the last name of the senders owner + public string LastName { get { return m_LastName; } } + /// Get the communication channel the dialog was sent on, responses + /// should also send responses on this same channel + public int Channel { get { return m_Channel; } } + /// Get the string labels containing the options presented in this dialog + public List ButtonLabels { get { return m_ButtonLabels; } } + /// UUID of the scritped object owner + public UUID OwnerID { get { return m_OwnerID; } } + + /// + /// Construct a new instance of the ScriptDialogEventArgs + /// + /// The dialog message + /// The name of the object that sent the dialog request + /// The ID of the image to be displayed + /// The ID of the primitive sending the dialog + /// The first name of the senders owner + /// The last name of the senders owner + /// The communication channel the dialog was sent on + /// The string labels containing the options presented in this dialog + /// UUID of the scritped object owner + public ScriptDialogEventArgs(string message, string objectName, UUID imageID, + UUID objectID, string firstName, string lastName, int chatChannel, List buttons, UUID ownerID) + { + this.m_Message = message; + this.m_ObjectName = objectName; + this.m_ImageID = imageID; + this.m_ObjectID = objectID; + this.m_FirstName = firstName; + this.m_LastName = lastName; + this.m_Channel = chatChannel; + this.m_ButtonLabels = buttons; + this.m_OwnerID = ownerID; + } + } + + /// Contains the data sent when a primitive requests debit or other permissions + /// requesting a YES or NO answer + public class ScriptQuestionEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly UUID m_TaskID; + private readonly UUID m_ItemID; + private readonly string m_ObjectName; + private readonly string m_ObjectOwnerName; + private readonly ScriptPermission m_Questions; + + /// Get the simulator containing the object sending the request + public Simulator Simulator { get { return m_Simulator; } } + /// Get the ID of the script making the request + public UUID TaskID { get { return m_TaskID; } } + /// Get the ID of the primitive containing the script making the request + public UUID ItemID { get { return m_ItemID; } } + /// Get the name of the primitive making the request + public string ObjectName { get { return m_ObjectName; } } + /// Get the name of the owner of the object making the request + public string ObjectOwnerName { get { return m_ObjectOwnerName; } } + /// Get the permissions being requested + public ScriptPermission Questions { get { return m_Questions; } } + + /// + /// Construct a new instance of the ScriptQuestionEventArgs + /// + /// The simulator containing the object sending the request + /// The ID of the script making the request + /// The ID of the primitive containing the script making the request + /// The name of the primitive making the request + /// The name of the owner of the object making the request + /// The permissions being requested + public ScriptQuestionEventArgs(Simulator simulator, UUID taskID, UUID itemID, string objectName, string objectOwner, ScriptPermission questions) + { + this.m_Simulator = simulator; + this.m_TaskID = taskID; + this.m_ItemID = itemID; + this.m_ObjectName = objectName; + this.m_ObjectOwnerName = objectOwner; + this.m_Questions = questions; + } + + } + + /// Contains the data sent when a primitive sends a request + /// to an agent to open the specified URL + public class LoadUrlEventArgs : EventArgs + { + private readonly string m_ObjectName; + private readonly UUID m_ObjectID; + private readonly UUID m_OwnerID; + private readonly bool m_OwnerIsGroup; + private readonly string m_Message; + private readonly string m_URL; + + /// Get the name of the object sending the request + public string ObjectName { get { return m_ObjectName; } } + /// Get the ID of the object sending the request + public UUID ObjectID { get { return m_ObjectID; } } + /// Get the ID of the owner of the object sending the request + public UUID OwnerID { get { return m_OwnerID; } } + /// True if the object is owned by a group + public bool OwnerIsGroup { get { return m_OwnerIsGroup; } } + /// Get the message sent with the request + public string Message { get { return m_Message; } } + /// Get the URL the object sent + public string URL { get { return m_URL; } } + + /// + /// Construct a new instance of the LoadUrlEventArgs + /// + /// The name of the object sending the request + /// The ID of the object sending the request + /// The ID of the owner of the object sending the request + /// True if the object is owned by a group + /// The message sent with the request + /// The URL the object sent + public LoadUrlEventArgs(string objectName, UUID objectID, UUID ownerID, bool ownerIsGroup, string message, string URL) + { + this.m_ObjectName = objectName; + this.m_ObjectID = objectID; + this.m_OwnerID = ownerID; + this.m_OwnerIsGroup = ownerIsGroup; + this.m_Message = message; + this.m_URL = URL; + } + } + + /// The date received from an ImprovedInstantMessage + public class InstantMessageEventArgs : EventArgs + { + private readonly InstantMessage m_IM; + private readonly Simulator m_Simulator; + + /// Get the InstantMessage object + public InstantMessage IM { get { return m_IM; } } + /// Get the simulator where the InstantMessage origniated + public Simulator Simulator { get { return m_Simulator; } } + + /// + /// Construct a new instance of the InstantMessageEventArgs object + /// + /// the InstantMessage object + /// the simulator where the InstantMessage origniated + public InstantMessageEventArgs(InstantMessage im, Simulator simulator) + { + this.m_IM = im; + this.m_Simulator = simulator; + } + } + + /// Contains the currency balance + public class BalanceEventArgs : EventArgs + { + private readonly int m_Balance; + + /// + /// Get the currenct balance + /// + public int Balance { get { return m_Balance; } } + + /// + /// Construct a new BalanceEventArgs object + /// + /// The currenct balance + public BalanceEventArgs(int balance) + { + this.m_Balance = balance; + } + } + + /// Contains the transaction summary when an item is purchased, + /// money is given, or land is purchased + public class MoneyBalanceReplyEventArgs : EventArgs + { + private readonly UUID m_TransactionID; + private readonly bool m_Success; + private readonly int m_Balance; + private readonly int m_MetersCredit; + private readonly int m_MetersCommitted; + private readonly string m_Description; + private TransactionInfo m_TransactionInfo; + + /// Get the ID of the transaction + public UUID TransactionID { get { return m_TransactionID; } } + /// True of the transaction was successful + public bool Success { get { return m_Success; } } + /// Get the remaining currency balance + public int Balance { get { return m_Balance; } } + /// Get the meters credited + public int MetersCredit { get { return m_MetersCredit; } } + /// Get the meters comitted + public int MetersCommitted { get { return m_MetersCommitted; } } + /// Get the description of the transaction + public string Description { get { return m_Description; } } + /// Detailed transaction information + public TransactionInfo TransactionInfo { get { return m_TransactionInfo; } } + /// + /// Construct a new instance of the MoneyBalanceReplyEventArgs object + /// + /// The ID of the transaction + /// True of the transaction was successful + /// The current currency balance + /// The meters credited + /// The meters comitted + /// A brief description of the transaction + /// Transaction info + public MoneyBalanceReplyEventArgs(UUID transactionID, bool transactionSuccess, int balance, int metersCredit, int metersCommitted, string description, TransactionInfo transactionInfo) + { + this.m_TransactionID = transactionID; + this.m_Success = transactionSuccess; + this.m_Balance = balance; + this.m_MetersCredit = metersCredit; + this.m_MetersCommitted = metersCommitted; + this.m_Description = description; + this.m_TransactionInfo = transactionInfo; + } + } + + // string message, TeleportStatus status, TeleportFlags flags + public class TeleportEventArgs : EventArgs + { + private readonly string m_Message; + private readonly TeleportStatus m_Status; + private readonly TeleportFlags m_Flags; + + public string Message { get { return m_Message; } } + public TeleportStatus Status { get { return m_Status; } } + public TeleportFlags Flags { get { return m_Flags; } } + + public TeleportEventArgs(string message, TeleportStatus status, TeleportFlags flags) + { + this.m_Message = message; + this.m_Status = status; + this.m_Flags = flags; + } + } + + /// Data sent from the simulator containing information about your agent and active group information + public class AgentDataReplyEventArgs : EventArgs + { + private readonly string m_FirstName; + private readonly string m_LastName; + private readonly UUID m_ActiveGroupID; + private readonly string m_GroupTitle; + private readonly GroupPowers m_GroupPowers; + private readonly string m_GroupName; + + /// Get the agents first name + public string FirstName { get { return m_FirstName; } } + /// Get the agents last name + public string LastName { get { return m_LastName; } } + /// Get the active group ID of your agent + public UUID ActiveGroupID { get { return m_ActiveGroupID; } } + /// Get the active groups title of your agent + public string GroupTitle { get { return m_GroupTitle; } } + /// Get the combined group powers of your agent + public GroupPowers GroupPowers { get { return m_GroupPowers; } } + /// Get the active group name of your agent + public string GroupName { get { return m_GroupName; } } + + /// + /// Construct a new instance of the AgentDataReplyEventArgs object + /// + /// The agents first name + /// The agents last name + /// The agents active group ID + /// The group title of the agents active group + /// The combined group powers the agent has in the active group + /// The name of the group the agent has currently active + public AgentDataReplyEventArgs(string firstName, string lastName, UUID activeGroupID, + string groupTitle, GroupPowers groupPowers, string groupName) + { + this.m_FirstName = firstName; + this.m_LastName = lastName; + this.m_ActiveGroupID = activeGroupID; + this.m_GroupTitle = groupTitle; + this.m_GroupPowers = groupPowers; + this.m_GroupName = groupName; + } + } + + /// Data sent by the simulator to indicate the active/changed animations + /// applied to your agent + public class AnimationsChangedEventArgs : EventArgs + { + private readonly InternalDictionary m_Animations; + + /// Get the dictionary that contains the changed animations + public InternalDictionary Animations { get { return m_Animations; } } + + /// + /// Construct a new instance of the AnimationsChangedEventArgs class + /// + /// The dictionary that contains the changed animations + public AnimationsChangedEventArgs(InternalDictionary agentAnimations) + { + this.m_Animations = agentAnimations; + } + + } + + /// + /// Data sent from a simulator indicating a collision with your agent + /// + public class MeanCollisionEventArgs : EventArgs + { + private readonly MeanCollisionType m_Type; + private readonly UUID m_Aggressor; + private readonly UUID m_Victim; + private readonly float m_Magnitude; + private readonly DateTime m_Time; + + /// Get the Type of collision + public MeanCollisionType Type { get { return m_Type; } } + /// Get the ID of the agent or object that collided with your agent + public UUID Aggressor { get { return m_Aggressor; } } + /// Get the ID of the agent that was attacked + public UUID Victim { get { return m_Victim; } } + /// A value indicating the strength of the collision + public float Magnitude { get { return m_Magnitude; } } + /// Get the time the collision occurred + public DateTime Time { get { return m_Time; } } + + /// + /// Construct a new instance of the MeanCollisionEventArgs class + /// + /// The type of collision that occurred + /// The ID of the agent or object that perpetrated the agression + /// The ID of the Victim + /// The strength of the collision + /// The Time the collision occurred + public MeanCollisionEventArgs(MeanCollisionType type, UUID perp, UUID victim, + float magnitude, DateTime time) + { + this.m_Type = type; + this.m_Aggressor = perp; + this.m_Victim = victim; + this.m_Magnitude = magnitude; + this.m_Time = time; + } + } + + /// Data sent to your agent when it crosses region boundaries + public class RegionCrossedEventArgs : EventArgs + { + private readonly Simulator m_OldSimulator; + private readonly Simulator m_NewSimulator; + + /// Get the simulator your agent just left + public Simulator OldSimulator { get { return m_OldSimulator; } } + /// Get the simulator your agent is now in + public Simulator NewSimulator { get { return m_NewSimulator; } } + + /// + /// Construct a new instance of the RegionCrossedEventArgs class + /// + /// The simulator your agent just left + /// The simulator your agent is now in + public RegionCrossedEventArgs(Simulator oldSim, Simulator newSim) + { + this.m_OldSimulator = oldSim; + this.m_NewSimulator = newSim; + } + } + + /// Data sent from the simulator when your agent joins a group chat session + public class GroupChatJoinedEventArgs : EventArgs + { + private readonly UUID m_SessionID; + private readonly string m_SessionName; + private readonly UUID m_TmpSessionID; + private readonly bool m_Success; + + /// Get the ID of the group chat session + public UUID SessionID { get { return m_SessionID; } } + /// Get the name of the session + public string SessionName { get { return m_SessionName; } } + /// Get the temporary session ID used for establishing new sessions + public UUID TmpSessionID { get { return m_TmpSessionID; } } + /// True if your agent successfully joined the session + public bool Success { get { return m_Success; } } + + /// + /// Construct a new instance of the GroupChatJoinedEventArgs class + /// + /// The ID of the session + /// The name of the session + /// A temporary session id used for establishing new sessions + /// True of your agent successfully joined the session + public GroupChatJoinedEventArgs(UUID groupChatSessionID, string sessionName, UUID tmpSessionID, bool success) + { + this.m_SessionID = groupChatSessionID; + this.m_SessionName = sessionName; + this.m_TmpSessionID = tmpSessionID; + this.m_Success = success; + } + } + + /// Data sent by the simulator containing urgent messages + public class AlertMessageEventArgs : EventArgs + { + private readonly string m_Message; + + /// Get the alert message + public string Message { get { return m_Message; } } + + /// + /// Construct a new instance of the AlertMessageEventArgs class + /// + /// The alert message + public AlertMessageEventArgs(string message) + { + this.m_Message = message; + } + } + + /// Data sent by a script requesting to take or release specified controls to your agent + public class ScriptControlEventArgs : EventArgs + { + private readonly ScriptControlChange m_Controls; + private readonly bool m_Pass; + private readonly bool m_Take; + + /// Get the controls the script is attempting to take or release to the agent + public ScriptControlChange Controls { get { return m_Controls; } } + /// True if the script is passing controls back to the agent + public bool Pass { get { return m_Pass; } } + /// True if the script is requesting controls be released to the script + public bool Take { get { return m_Take; } } + + /// + /// Construct a new instance of the ScriptControlEventArgs class + /// + /// The controls the script is attempting to take or release to the agent + /// True if the script is passing controls back to the agent + /// True if the script is requesting controls be released to the script + public ScriptControlEventArgs(ScriptControlChange controls, bool pass, bool take) + { + m_Controls = controls; + m_Pass = pass; + m_Take = take; + } + } + + /// + /// Data sent from the simulator to an agent to indicate its view limits + /// + public class CameraConstraintEventArgs : EventArgs + { + private readonly Vector4 m_CollidePlane; + + /// Get the collision plane + public Vector4 CollidePlane { get { return m_CollidePlane; } } + + /// + /// Construct a new instance of the CameraConstraintEventArgs class + /// + /// The collision plane + public CameraConstraintEventArgs(Vector4 collidePlane) + { + m_CollidePlane = collidePlane; + } + } + + /// + /// Data containing script sensor requests which allow an agent to know the specific details + /// of a primitive sending script sensor requests + /// + public class ScriptSensorReplyEventArgs : EventArgs + { + private readonly UUID m_RequestorID; + private readonly UUID m_GroupID; + private readonly string m_Name; + private readonly UUID m_ObjectID; + private readonly UUID m_OwnerID; + private readonly Vector3 m_Position; + private readonly float m_Range; + private readonly Quaternion m_Rotation; + private readonly ScriptSensorTypeFlags m_Type; + private readonly Vector3 m_Velocity; + + /// Get the ID of the primitive sending the sensor + public UUID RequestorID { get { return m_RequestorID; } } + /// Get the ID of the group associated with the primitive + public UUID GroupID { get { return m_GroupID; } } + /// Get the name of the primitive sending the sensor + public string Name { get { return m_Name; } } + /// Get the ID of the primitive sending the sensor + public UUID ObjectID { get { return m_ObjectID; } } + /// Get the ID of the owner of the primitive sending the sensor + public UUID OwnerID { get { return m_OwnerID; } } + /// Get the position of the primitive sending the sensor + public Vector3 Position { get { return m_Position; } } + /// Get the range the primitive specified to scan + public float Range { get { return m_Range; } } + /// Get the rotation of the primitive sending the sensor + public Quaternion Rotation { get { return m_Rotation; } } + /// Get the type of sensor the primitive sent + public ScriptSensorTypeFlags Type { get { return m_Type; } } + /// Get the velocity of the primitive sending the sensor + public Vector3 Velocity { get { return m_Velocity; } } + + /// + /// Construct a new instance of the ScriptSensorReplyEventArgs + /// + /// The ID of the primitive sending the sensor + /// The ID of the group associated with the primitive + /// The name of the primitive sending the sensor + /// The ID of the primitive sending the sensor + /// The ID of the owner of the primitive sending the sensor + /// The position of the primitive sending the sensor + /// The range the primitive specified to scan + /// The rotation of the primitive sending the sensor + /// The type of sensor the primitive sent + /// The velocity of the primitive sending the sensor + public ScriptSensorReplyEventArgs(UUID requestorID, UUID groupID, string name, + UUID objectID, UUID ownerID, Vector3 position, float range, Quaternion rotation, + ScriptSensorTypeFlags type, Vector3 velocity) + { + this.m_RequestorID = requestorID; + this.m_GroupID = groupID; + this.m_Name = name; + this.m_ObjectID = objectID; + this.m_OwnerID = ownerID; + this.m_Position = position; + this.m_Range = range; + this.m_Rotation = rotation; + this.m_Type = type; + this.m_Velocity = velocity; + } + } + + /// Contains the response data returned from the simulator in response to a + public class AvatarSitResponseEventArgs : EventArgs + { + private readonly UUID m_ObjectID; + private readonly bool m_Autopilot; + private readonly Vector3 m_CameraAtOffset; + private readonly Vector3 m_CameraEyeOffset; + private readonly bool m_ForceMouselook; + private readonly Vector3 m_SitPosition; + private readonly Quaternion m_SitRotation; + + /// Get the ID of the primitive the agent will be sitting on + public UUID ObjectID { get { return m_ObjectID; } } + /// True if the simulator Autopilot functions were involved + public bool Autopilot { get { return m_Autopilot; } } + /// Get the camera offset of the agent when seated + public Vector3 CameraAtOffset { get { return m_CameraAtOffset; } } + /// Get the camera eye offset of the agent when seated + public Vector3 CameraEyeOffset { get { return m_CameraEyeOffset; } } + /// True of the agent will be in mouselook mode when seated + public bool ForceMouselook { get { return m_ForceMouselook; } } + /// Get the position of the agent when seated + public Vector3 SitPosition { get { return m_SitPosition; } } + /// Get the rotation of the agent when seated + public Quaternion SitRotation { get { return m_SitRotation; } } + + /// Construct a new instance of the AvatarSitResponseEventArgs object + public AvatarSitResponseEventArgs(UUID objectID, bool autoPilot, Vector3 cameraAtOffset, + Vector3 cameraEyeOffset, bool forceMouselook, Vector3 sitPosition, Quaternion sitRotation) + { + this.m_ObjectID = objectID; + this.m_Autopilot = autoPilot; + this.m_CameraAtOffset = cameraAtOffset; + this.m_CameraEyeOffset = cameraEyeOffset; + this.m_ForceMouselook = forceMouselook; + this.m_SitPosition = sitPosition; + this.m_SitRotation = sitRotation; + } + } + + /// Data sent when an agent joins a chat session your agent is currently participating in + public class ChatSessionMemberAddedEventArgs : EventArgs + { + private readonly UUID m_SessionID; + private readonly UUID m_AgentID; + + /// Get the ID of the chat session + public UUID SessionID { get { return m_SessionID; } } + /// Get the ID of the agent that joined + public UUID AgentID { get { return m_AgentID; } } + + /// + /// Construct a new instance of the ChatSessionMemberAddedEventArgs object + /// + /// The ID of the chat session + /// The ID of the agent joining + public ChatSessionMemberAddedEventArgs(UUID sessionID, UUID agentID) + { + this.m_SessionID = sessionID; + this.m_AgentID = agentID; + } + } + + /// Data sent when an agent exits a chat session your agent is currently participating in + public class ChatSessionMemberLeftEventArgs : EventArgs + { + private readonly UUID m_SessionID; + private readonly UUID m_AgentID; + + /// Get the ID of the chat session + public UUID SessionID { get { return m_SessionID; } } + /// Get the ID of the agent that left + public UUID AgentID { get { return m_AgentID; } } + + /// + /// Construct a new instance of the ChatSessionMemberLeftEventArgs object + /// + /// The ID of the chat session + /// The ID of the Agent that left + public ChatSessionMemberLeftEventArgs(UUID sessionID, UUID agentID) + { + this.m_SessionID = sessionID; + this.m_AgentID = agentID; + } + } + + /// Event arguments with the result of setting display name operation + public class SetDisplayNameReplyEventArgs : EventArgs + { + private readonly int m_Status; + private readonly string m_Reason; + private readonly AgentDisplayName m_DisplayName; + + /// Status code, 200 indicates settign display name was successful + public int Status { get { return m_Status; } } + + /// Textual description of the status + public string Reason { get { return m_Reason; } } + + /// Details of the newly set display name + public AgentDisplayName DisplayName { get { return m_DisplayName; } } + + /// Default constructor + public SetDisplayNameReplyEventArgs(int status, string reason, AgentDisplayName displayName) + { + m_Status = status; + m_Reason = reason; + m_DisplayName = displayName; + } + } + + #endregion +} diff --git a/OpenMetaverse/AgentManagerCamera.cs b/OpenMetaverse/AgentManagerCamera.cs new file mode 100644 index 0000000..f0c1de2 --- /dev/null +++ b/OpenMetaverse/AgentManagerCamera.cs @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + public partial class AgentManager + { + public partial class AgentMovement + { + /// + /// Camera controls for the agent, mostly a thin wrapper around + /// CoordinateFrame. This class is only responsible for state + /// tracking and math, it does not send any packets + /// + public class AgentCamera + { + /// + public float Far; + + /// The camera is a local frame of reference inside of + /// the larger grid space. This is where the math happens + private CoordinateFrame Frame; + + /// + public Vector3 Position + { + get { return Frame.Origin; } + set { Frame.Origin = value; } + } + /// + public Vector3 AtAxis + { + get { return Frame.YAxis; } + set { Frame.YAxis = value; } + } + /// + public Vector3 LeftAxis + { + get { return Frame.XAxis; } + set { Frame.XAxis = value; } + } + /// + public Vector3 UpAxis + { + get { return Frame.ZAxis; } + set { Frame.ZAxis = value; } + } + + /// + /// Default constructor + /// + public AgentCamera() + { + Frame = new CoordinateFrame(new Vector3(128f, 128f, 20f)); + Far = 128f; + } + + public void Roll(float angle) + { + Frame.Roll(angle); + } + + public void Pitch(float angle) + { + Frame.Pitch(angle); + } + + public void Yaw(float angle) + { + Frame.Yaw(angle); + } + + public void LookDirection(Vector3 target) + { + Frame.LookDirection(target); + } + + public void LookDirection(Vector3 target, Vector3 upDirection) + { + Frame.LookDirection(target, upDirection); + } + + public void LookDirection(double heading) + { + Frame.LookDirection(heading); + } + + public void LookAt(Vector3 position, Vector3 target) + { + Frame.LookAt(position, target); + } + + public void LookAt(Vector3 position, Vector3 target, Vector3 upDirection) + { + Frame.LookAt(position, target, upDirection); + } + + public void SetPositionOrientation(Vector3 position, float roll, float pitch, float yaw) + { + Frame.Origin = position; + + Frame.ResetAxes(); + + Frame.Roll(roll); + Frame.Pitch(pitch); + Frame.Yaw(yaw); + } + } + } + } +} diff --git a/OpenMetaverse/AgentManagerMovement.cs b/OpenMetaverse/AgentManagerMovement.cs new file mode 100644 index 0000000..e22682a --- /dev/null +++ b/OpenMetaverse/AgentManagerMovement.cs @@ -0,0 +1,760 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + public partial class AgentManager + { + #region Enums + + /// + /// Used to specify movement actions for your agent + /// + [Flags] + public enum ControlFlags + { + /// Empty flag + NONE = 0, + /// Move Forward (SL Keybinding: W/Up Arrow) + AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX, + /// Move Backward (SL Keybinding: S/Down Arrow) + AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX, + /// Move Left (SL Keybinding: Shift-(A/Left Arrow)) + AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX, + /// Move Right (SL Keybinding: Shift-(D/Right Arrow)) + AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX, + /// Not Flying: Jump/Flying: Move Up (SL Keybinding: E) + AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX, + /// Not Flying: Croutch/Flying: Move Down (SL Keybinding: C) + AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX, + /// Unused + AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX, + /// Unused + AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX, + /// Unused + AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX, + /// Unused + AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX, + /// ORed with AGENT_CONTROL_AT_* if the keyboard is being used + AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX, + /// ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used + AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX, + /// ORed with AGENT_CONTROL_UP_* if the keyboard is being used + AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX, + /// Fly + AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX, + /// + AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX, + /// Finish our current animation + AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX, + /// Stand up from the ground or a prim seat + AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX, + /// Sit on the ground at our current location + AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX, + /// Whether mouselook is currently enabled + AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX, + /// Legacy, used if a key was pressed for less than a certain amount of time + AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX, + /// Legacy, used if a key was pressed for less than a certain amount of time + AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX, + /// Legacy, used if a key was pressed for less than a certain amount of time + AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX, + /// Legacy, used if a key was pressed for less than a certain amount of time + AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX, + /// Legacy, used if a key was pressed for less than a certain amount of time + AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX, + /// Legacy, used if a key was pressed for less than a certain amount of time + AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX, + /// + AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX, + /// + AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX, + /// Set when the avatar is idled or set to away. Note that the away animation is + /// activated separately from setting this flag + AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX, + /// + AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX, + /// + AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX, + /// + AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX, + /// + AGENT_CONTROL_ML_LBUTTON_UP = 0x1 << CONTROL_ML_LBUTTON_UP_INDEX + } + + #endregion Enums + + #region AgentUpdate Constants + + private const int CONTROL_AT_POS_INDEX = 0; + private const int CONTROL_AT_NEG_INDEX = 1; + private const int CONTROL_LEFT_POS_INDEX = 2; + private const int CONTROL_LEFT_NEG_INDEX = 3; + private const int CONTROL_UP_POS_INDEX = 4; + private const int CONTROL_UP_NEG_INDEX = 5; + private const int CONTROL_PITCH_POS_INDEX = 6; + private const int CONTROL_PITCH_NEG_INDEX = 7; + private const int CONTROL_YAW_POS_INDEX = 8; + private const int CONTROL_YAW_NEG_INDEX = 9; + private const int CONTROL_FAST_AT_INDEX = 10; + private const int CONTROL_FAST_LEFT_INDEX = 11; + private const int CONTROL_FAST_UP_INDEX = 12; + private const int CONTROL_FLY_INDEX = 13; + private const int CONTROL_STOP_INDEX = 14; + private const int CONTROL_FINISH_ANIM_INDEX = 15; + private const int CONTROL_STAND_UP_INDEX = 16; + private const int CONTROL_SIT_ON_GROUND_INDEX = 17; + private const int CONTROL_MOUSELOOK_INDEX = 18; + private const int CONTROL_NUDGE_AT_POS_INDEX = 19; + private const int CONTROL_NUDGE_AT_NEG_INDEX = 20; + private const int CONTROL_NUDGE_LEFT_POS_INDEX = 21; + private const int CONTROL_NUDGE_LEFT_NEG_INDEX = 22; + private const int CONTROL_NUDGE_UP_POS_INDEX = 23; + private const int CONTROL_NUDGE_UP_NEG_INDEX = 24; + private const int CONTROL_TURN_LEFT_INDEX = 25; + private const int CONTROL_TURN_RIGHT_INDEX = 26; + private const int CONTROL_AWAY_INDEX = 27; + private const int CONTROL_LBUTTON_DOWN_INDEX = 28; + private const int CONTROL_LBUTTON_UP_INDEX = 29; + private const int CONTROL_ML_LBUTTON_DOWN_INDEX = 30; + private const int CONTROL_ML_LBUTTON_UP_INDEX = 31; + private const int TOTAL_CONTROLS = 32; + + #endregion AgentUpdate Constants + + /// + /// Agent movement and camera control + /// + /// Agent movement is controlled by setting specific + /// After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags + /// This is most easily accomplished by setting one or more of the AgentMovement properties + /// + /// Movement of an avatar is always based on a compass direction, for example AtPos will move the + /// agent from West to East or forward on the X Axis, AtNeg will of course move agent from + /// East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis + /// The Z axis is Up, finer grained control of movements can be done using the Nudge properties + /// + public partial class AgentMovement + { + #region Properties + + /// Move agent positive along the X axis + public bool AtPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, value); } + } + /// Move agent negative along the X axis + public bool AtNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, value); } + } + /// Move agent positive along the Y axis + public bool LeftPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS, value); } + } + /// Move agent negative along the Y axis + public bool LeftNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG, value); } + } + /// Move agent positive along the Z axis + public bool UpPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, value); } + } + /// Move agent negative along the Z axis + public bool UpNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, value); } + } + /// + public bool PitchPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS, value); } + } + /// + public bool PitchNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG, value); } + } + /// + public bool YawPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS, value); } + } + /// + public bool YawNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG, value); } + } + /// + public bool FastAt + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT, value); } + } + /// + public bool FastLeft + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT, value); } + } + /// + public bool FastUp + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP, value); } + } + /// Causes simulator to make agent fly + public bool Fly + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY, value); } + } + /// Stop movement + public bool Stop + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP, value); } + } + /// Finish animation + public bool FinishAnim + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM, value); } + } + /// Stand up from a sit + public bool StandUp + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP, value); } + } + /// Tells simulator to sit agent on ground + public bool SitOnGround + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND, value); } + } + /// Place agent into mouselook mode + public bool Mouselook + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK, value); } + } + /// Nudge agent positive along the X axis + public bool NudgeAtPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, value); } + } + /// Nudge agent negative along the X axis + public bool NudgeAtNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, value); } + } + /// Nudge agent positive along the Y axis + public bool NudgeLeftPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS, value); } + } + /// Nudge agent negative along the Y axis + public bool NudgeLeftNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG, value); } + } + /// Nudge agent positive along the Z axis + public bool NudgeUpPos + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS, value); } + } + /// Nudge agent negative along the Z axis + public bool NudgeUpNeg + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG, value); } + } + /// + public bool TurnLeft + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT, value); } + } + /// + public bool TurnRight + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT, value); } + } + /// Tell simulator to mark agent as away + public bool Away + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY, value); } + } + /// + public bool LButtonDown + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN, value); } + } + /// + public bool LButtonUp + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP, value); } + } + /// + public bool MLButtonDown + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN, value); } + } + /// + public bool MLButtonUp + { + get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP); } + set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP, value); } + } + /// + /// Returns "always run" value, or changes it by sending a SetAlwaysRunPacket + /// + public bool AlwaysRun + { + get + { + return alwaysRun; + } + set + { + alwaysRun = value; + SetAlwaysRunPacket run = new SetAlwaysRunPacket(); + run.AgentData.AgentID = Client.Self.AgentID; + run.AgentData.SessionID = Client.Self.SessionID; + run.AgentData.AlwaysRun = alwaysRun; + Client.Network.SendPacket(run); + } + } + /// The current value of the agent control flags + public uint AgentControls + { + get { return agentControls; } + } + + /// Gets or sets the interval in milliseconds at which + /// AgentUpdate packets are sent to the current simulator. Setting + /// this to a non-zero value will also enable the packet sending if + /// it was previously off, and setting it to zero will disable + public int UpdateInterval + { + get + { + return updateInterval; + } + set + { + if (value > 0) + { + if (updateTimer != null) + { + updateTimer.Change(value, value); + } + updateInterval = value; + } + else + { + if (updateTimer != null) + { + updateTimer.Change(Timeout.Infinite, Timeout.Infinite); + } + updateInterval = 0; + } + } + } + /// Gets or sets whether AgentUpdate packets are sent to + /// the current simulator + public bool UpdateEnabled + { + get { return (updateInterval != 0); } + } + + /// Reset movement controls every time we send an update + public bool AutoResetControls + { + get { return autoResetControls; } + set { autoResetControls = value; } + } + + #endregion Properties + + /// Agent camera controls + public AgentCamera Camera; + /// Currently only used for hiding your group title + public AgentFlags Flags = AgentFlags.None; + /// Action state of the avatar, which can currently be + /// typing and editing + public AgentState State = AgentState.None; + /// + public Quaternion BodyRotation = Quaternion.Identity; + /// + public Quaternion HeadRotation = Quaternion.Identity; + + #region Change tracking + /// + private Quaternion LastBodyRotation; + /// + private Quaternion LastHeadRotation; + /// + private Vector3 LastCameraCenter; + /// + private Vector3 LastCameraXAxis; + /// + private Vector3 LastCameraYAxis; + /// + private Vector3 LastCameraZAxis; + /// + private float LastFar; + #endregion Change tracking + + private bool alwaysRun; + private GridClient Client; + private uint agentControls; + private int duplicateCount; + private AgentState lastState; + /// Timer for sending AgentUpdate packets + private Timer updateTimer; + private int updateInterval; + private bool autoResetControls; + + /// Default constructor + public AgentMovement(GridClient client) + { + Client = client; + Camera = new AgentCamera(); + Client.Network.LoginProgress += Network_OnConnected; + Client.Network.Disconnected += Network_OnDisconnected; + updateInterval = Settings.DEFAULT_AGENT_UPDATE_INTERVAL; + } + + private void CleanupTimer() + { + if (updateTimer != null) + { + updateTimer.Dispose(); + updateTimer = null; + } + } + + private void Network_OnDisconnected(object sender, DisconnectedEventArgs e) + { + CleanupTimer(); + } + + private void Network_OnConnected(object sender, LoginProgressEventArgs e) + { + if (e.Status == LoginStatus.Success) + { + CleanupTimer(); + updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed), null, updateInterval, updateInterval); + } + } + + /// + /// Send an AgentUpdate with the camera set at the current agent + /// position and pointing towards the heading specified + /// + /// Camera rotation in radians + /// Whether to send the AgentUpdate reliable + /// or not + public void UpdateFromHeading(double heading, bool reliable) + { + Camera.Position = Client.Self.SimPosition; + Camera.LookDirection(heading); + + BodyRotation.Z = (float)Math.Sin(heading / 2.0d); + BodyRotation.W = (float)Math.Cos(heading / 2.0d); + HeadRotation = BodyRotation; + + SendUpdate(reliable); + } + + /// + /// Rotates the avatar body and camera toward a target position. + /// This will also anchor the camera position on the avatar + /// + /// Region coordinates to turn toward + public bool TurnToward(Vector3 target) + { + return TurnToward(target, true); + } + + /// + /// Rotates the avatar body and camera toward a target position. + /// This will also anchor the camera position on the avatar + /// + /// Region coordinates to turn toward + /// whether to send update or not + public bool TurnToward(Vector3 target, bool sendUpdate) + { + if (Client.Settings.SEND_AGENT_UPDATES) + { + Quaternion parentRot = Quaternion.Identity; + + if (Client.Self.SittingOn > 0) + { + if (!Client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(Client.Self.SittingOn)) + { + Logger.Log("Attempted TurnToward but parent prim is not in dictionary", Helpers.LogLevel.Warning, Client); + return false; + } + else parentRot = Client.Network.CurrentSim.ObjectsPrimitives[Client.Self.SittingOn].Rotation; + } + + Quaternion between = Vector3.RotationBetween(Vector3.UnitX, Vector3.Normalize(target - Client.Self.SimPosition)); + Quaternion rot = between * (Quaternion.Identity / parentRot); + + BodyRotation = rot; + HeadRotation = rot; + Camera.LookAt(Client.Self.SimPosition, target); + + if (sendUpdate) SendUpdate(); + + return true; + } + else + { + Logger.Log("Attempted TurnToward but agent updates are disabled", Helpers.LogLevel.Warning, Client); + return false; + } + } + + /// + /// Send new AgentUpdate packet to update our current camera + /// position and rotation + /// + public void SendUpdate() + { + SendUpdate(false, Client.Network.CurrentSim); + } + + /// + /// Send new AgentUpdate packet to update our current camera + /// position and rotation + /// + /// Whether to require server acknowledgement + /// of this packet + public void SendUpdate(bool reliable) + { + SendUpdate(reliable, Client.Network.CurrentSim); + } + + /// + /// Send new AgentUpdate packet to update our current camera + /// position and rotation + /// + /// Whether to require server acknowledgement + /// of this packet + /// Simulator to send the update to + public void SendUpdate(bool reliable, Simulator simulator) + { + // Since version 1.40.4 of the Linden simulator, sending this update + // causes corruption of the agent position in the simulator + if (simulator != null && (!simulator.AgentMovementComplete)) + return; + + Vector3 origin = Camera.Position; + Vector3 xAxis = Camera.LeftAxis; + Vector3 yAxis = Camera.AtAxis; + Vector3 zAxis = Camera.UpAxis; + + // Attempted to sort these in a rough order of how often they might change + if (agentControls == 0 && + yAxis == LastCameraYAxis && + origin == LastCameraCenter && + State == lastState && + HeadRotation == LastHeadRotation && + BodyRotation == LastBodyRotation && + xAxis == LastCameraXAxis && + Camera.Far == LastFar && + zAxis == LastCameraZAxis) + { + ++duplicateCount; + } + else + { + duplicateCount = 0; + } + + if (Client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK || duplicateCount < 10) + { + // Store the current state to do duplicate checking + LastHeadRotation = HeadRotation; + LastBodyRotation = BodyRotation; + LastCameraYAxis = yAxis; + LastCameraCenter = origin; + LastCameraXAxis = xAxis; + LastCameraZAxis = zAxis; + LastFar = Camera.Far; + lastState = State; + + // Build the AgentUpdate packet and send it + AgentUpdatePacket update = new AgentUpdatePacket(); + update.Header.Reliable = reliable; + + update.AgentData.AgentID = Client.Self.AgentID; + update.AgentData.SessionID = Client.Self.SessionID; + update.AgentData.HeadRotation = HeadRotation; + update.AgentData.BodyRotation = BodyRotation; + update.AgentData.CameraAtAxis = xAxis; + update.AgentData.CameraCenter = origin; + update.AgentData.CameraLeftAxis = yAxis; + update.AgentData.CameraUpAxis = zAxis; + update.AgentData.Far = Camera.Far; + update.AgentData.State = (byte)State; + update.AgentData.ControlFlags = agentControls; + update.AgentData.Flags = (byte)Flags; + + Client.Network.SendPacket(update, simulator); + + if (autoResetControls) { + ResetControlFlags(); + } + } + } + + /// + /// Builds an AgentUpdate packet entirely from parameters. This + /// will not touch the state of Self.Movement or + /// Self.Movement.Camera in any way + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void SendManualUpdate(AgentManager.ControlFlags controlFlags, Vector3 position, Vector3 forwardAxis, + Vector3 leftAxis, Vector3 upAxis, Quaternion bodyRotation, Quaternion headRotation, float farClip, + AgentFlags flags, AgentState state, bool reliable) + { + // Since version 1.40.4 of the Linden simulator, sending this update + // causes corruption of the agent position in the simulator + if (Client.Network.CurrentSim != null && (!Client.Network.CurrentSim.HandshakeComplete)) + return; + + AgentUpdatePacket update = new AgentUpdatePacket(); + + update.AgentData.AgentID = Client.Self.AgentID; + update.AgentData.SessionID = Client.Self.SessionID; + update.AgentData.BodyRotation = bodyRotation; + update.AgentData.HeadRotation = headRotation; + update.AgentData.CameraCenter = position; + update.AgentData.CameraAtAxis = forwardAxis; + update.AgentData.CameraLeftAxis = leftAxis; + update.AgentData.CameraUpAxis = upAxis; + update.AgentData.Far = farClip; + update.AgentData.ControlFlags = (uint)controlFlags; + update.AgentData.Flags = (byte)flags; + update.AgentData.State = (byte)state; + + update.Header.Reliable = reliable; + + Client.Network.SendPacket(update); + } + + private bool GetControlFlag(ControlFlags flag) + { + return (agentControls & (uint)flag) != 0; + } + + private void SetControlFlag(ControlFlags flag, bool value) + { + if (value) agentControls |= (uint)flag; + else agentControls &= ~((uint)flag); + } + + public void ResetControlFlags() + { + // Reset all of the flags except for persistent settings like + // away, fly, mouselook, and crouching + agentControls &= + (uint)(ControlFlags.AGENT_CONTROL_AWAY | + ControlFlags.AGENT_CONTROL_FLY | + ControlFlags.AGENT_CONTROL_MOUSELOOK | + ControlFlags.AGENT_CONTROL_UP_NEG); + } + + + /// + /// Sends update of Field of Vision vertical angle to the simulator + /// + /// Angle in radians + public void SetFOVVerticalAngle(float angle) + { + OpenMetaverse.Packets.AgentFOVPacket msg = new OpenMetaverse.Packets.AgentFOVPacket(); + msg.AgentData.AgentID = Client.Self.AgentID; + msg.AgentData.SessionID = Client.Self.SessionID; + msg.AgentData.CircuitCode = Client.Network.CircuitCode; + msg.FOVBlock.GenCounter = 0; + msg.FOVBlock.VerticalAngle = angle; + Client.Network.SendPacket(msg); + } + + private void UpdateTimer_Elapsed(object obj) + { + if (Client.Network.Connected && Client.Settings.SEND_AGENT_UPDATES) + { + //Send an AgentUpdate packet + SendUpdate(false, Client.Network.CurrentSim); + } + } + } + } +} diff --git a/OpenMetaverse/AgentThrottle.cs b/OpenMetaverse/AgentThrottle.cs new file mode 100644 index 0000000..fe36013 --- /dev/null +++ b/OpenMetaverse/AgentThrottle.cs @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + /// + /// Throttles the network traffic for various different traffic types. + /// Access this class through GridClient.Throttle + /// + public class AgentThrottle + { + /// Maximum bits per second for resending unacknowledged packets + public float Resend + { + get { return resend; } + set + { + if (value > 150000.0f) resend = 150000.0f; + else if (value < 10000.0f) resend = 10000.0f; + else resend = value; + } + } + /// Maximum bits per second for LayerData terrain + public float Land + { + get { return land; } + set + { + if (value > 170000.0f) land = 170000.0f; + else if (value < 0.0f) land = 0.0f; // We don't have control of these so allow throttling to 0 + else land = value; + } + } + /// Maximum bits per second for LayerData wind data + public float Wind + { + get { return wind; } + set + { + if (value > 34000.0f) wind = 34000.0f; + else if (value < 0.0f) wind = 0.0f; // We don't have control of these so allow throttling to 0 + else wind = value; + } + } + /// Maximum bits per second for LayerData clouds + public float Cloud + { + get { return cloud; } + set + { + if (value > 34000.0f) cloud = 34000.0f; + else if (value < 0.0f) cloud = 0.0f; // We don't have control of these so allow throttling to 0 + else cloud = value; + } + } + /// Unknown, includes object data + public float Task + { + get { return task; } + set + { + if (value > 446000.0f) task = 446000.0f; + else if (value < 4000.0f) task = 4000.0f; + else task = value; + } + } + /// Maximum bits per second for textures + public float Texture + { + get { return texture; } + set + { + if (value > 446000.0f) texture = 446000.0f; + else if (value < 4000.0f) texture = 4000.0f; + else texture = value; + } + } + /// Maximum bits per second for downloaded assets + public float Asset + { + get { return asset; } + set + { + if (value > 220000.0f) asset = 220000.0f; + else if (value < 10000.0f) asset = 10000.0f; + else asset = value; + } + } + + /// Maximum bits per second the entire connection, divided up + /// between invidiual streams using default multipliers + public float Total + { + get { return Resend + Land + Wind + Cloud + Task + Texture + Asset; } + set + { + // Sane initial values + Resend = (value * 0.1f); + Land = (float)(value * 0.52f / 3f); + Wind = (float)(value * 0.05f); + Cloud = (float)(value * 0.05f); + Task = (float)(value * 0.704f / 3f); + Texture = (float)(value * 0.704f / 3f); + Asset = (float)(value * 0.484f / 3f); + } + } + + private GridClient Client; + private float resend; + private float land; + private float wind; + private float cloud; + private float task; + private float texture; + private float asset; + + /// + /// Default constructor, uses a default high total of 1500 KBps (1536000) + /// + public AgentThrottle(GridClient client) + { + Client = client; + Total = 1536000.0f; + } + + /// + /// Constructor that decodes an existing AgentThrottle packet in to + /// individual values + /// + /// Reference to the throttle data in an AgentThrottle + /// packet + /// Offset position to start reading at in the + /// throttle data + /// This is generally not needed in clients as the server will + /// never send a throttle packet to the client + public AgentThrottle(byte[] data, int pos) + { + byte[] adjData; + + if (!BitConverter.IsLittleEndian) + { + byte[] newData = new byte[7 * 4]; + Buffer.BlockCopy(data, pos, newData, 0, 7 * 4); + + for (int i = 0; i < 7; i++) + Array.Reverse(newData, i * 4, 4); + + adjData = newData; + } + else + { + adjData = data; + } + + Resend = BitConverter.ToSingle(adjData, pos); pos += 4; + Land = BitConverter.ToSingle(adjData, pos); pos += 4; + Wind = BitConverter.ToSingle(adjData, pos); pos += 4; + Cloud = BitConverter.ToSingle(adjData, pos); pos += 4; + Task = BitConverter.ToSingle(adjData, pos); pos += 4; + Texture = BitConverter.ToSingle(adjData, pos); pos += 4; + Asset = BitConverter.ToSingle(adjData, pos); + } + + /// + /// Send an AgentThrottle packet to the current server using the + /// current values + /// + public void Set() + { + Set(Client.Network.CurrentSim); + } + + /// + /// Send an AgentThrottle packet to the specified server using the + /// current values + /// + public void Set(Simulator simulator) + { + AgentThrottlePacket throttle = new AgentThrottlePacket(); + throttle.AgentData.AgentID = Client.Self.AgentID; + throttle.AgentData.SessionID = Client.Self.SessionID; + throttle.AgentData.CircuitCode = Client.Network.CircuitCode; + throttle.Throttle.GenCounter = 0; + throttle.Throttle.Throttles = this.ToBytes(); + + Client.Network.SendPacket(throttle, simulator); + } + + /// + /// Convert the current throttle values to a byte array that can be put + /// in an AgentThrottle packet + /// + /// Byte array containing all the throttle values + public byte[] ToBytes() + { + byte[] data = new byte[7 * 4]; + int i = 0; + + Buffer.BlockCopy(Utils.FloatToBytes(Resend), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes(Land), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes(Wind), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes(Cloud), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes(Task), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes(Texture), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes(Asset), 0, data, i, 4); i += 4; + + return data; + } + } +} diff --git a/OpenMetaverse/Animations.cs b/OpenMetaverse/Animations.cs new file mode 100644 index 0000000..ddd77a2 --- /dev/null +++ b/OpenMetaverse/Animations.cs @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Collections.Generic; + +namespace OpenMetaverse +{ + /// + /// Static pre-defined animations available to all agents + /// + public static class Animations + { + /// Agent with afraid expression on face + public readonly static UUID AFRAID = new UUID("6b61c8e8-4747-0d75-12d7-e49ff207a4ca"); + /// Agent aiming a bazooka (right handed) + public readonly static UUID AIM_BAZOOKA_R = new UUID("b5b4a67d-0aee-30d2-72cd-77b333e932ef"); + /// Agent aiming a bow (left handed) + public readonly static UUID AIM_BOW_L = new UUID("46bb4359-de38-4ed8-6a22-f1f52fe8f506"); + /// Agent aiming a hand gun (right handed) + public readonly static UUID AIM_HANDGUN_R = new UUID("3147d815-6338-b932-f011-16b56d9ac18b"); + /// Agent aiming a rifle (right handed) + public readonly static UUID AIM_RIFLE_R = new UUID("ea633413-8006-180a-c3ba-96dd1d756720"); + /// Agent with angry expression on face + public readonly static UUID ANGRY = new UUID("5747a48e-073e-c331-f6f3-7c2149613d3e"); + /// Agent hunched over (away) + public readonly static UUID AWAY = new UUID("fd037134-85d4-f241-72c6-4f42164fedee"); + /// Agent doing a backflip + public readonly static UUID BACKFLIP = new UUID("c4ca6188-9127-4f31-0158-23c4e2f93304"); + /// Agent laughing while holding belly + public readonly static UUID BELLY_LAUGH = new UUID("18b3a4b5-b463-bd48-e4b6-71eaac76c515"); + /// Agent blowing a kiss + public readonly static UUID BLOW_KISS = new UUID("db84829b-462c-ee83-1e27-9bbee66bd624"); + /// Agent with bored expression on face + public readonly static UUID BORED = new UUID("b906c4ba-703b-1940-32a3-0c7f7d791510"); + /// Agent bowing to audience + public readonly static UUID BOW = new UUID("82e99230-c906-1403-4d9c-3889dd98daba"); + /// Agent brushing himself/herself off + public readonly static UUID BRUSH = new UUID("349a3801-54f9-bf2c-3bd0-1ac89772af01"); + /// Agent in busy mode + public readonly static UUID BUSY = new UUID("efcf670c-2d18-8128-973a-034ebc806b67"); + /// Agent clapping hands + public readonly static UUID CLAP = new UUID("9b0c1c4e-8ac7-7969-1494-28c874c4f668"); + /// Agent doing a curtsey bow + public readonly static UUID COURTBOW = new UUID("9ba1c942-08be-e43a-fb29-16ad440efc50"); + /// Agent crouching + public readonly static UUID CROUCH = new UUID("201f3fdf-cb1f-dbec-201f-7333e328ae7c"); + /// Agent crouching while walking + public readonly static UUID CROUCHWALK = new UUID("47f5f6fb-22e5-ae44-f871-73aaaf4a6022"); + /// Agent crying + public readonly static UUID CRY = new UUID("92624d3e-1068-f1aa-a5ec-8244585193ed"); + /// Agent unanimated with arms out (e.g. setting appearance) + public readonly static UUID CUSTOMIZE = new UUID("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53"); + /// Agent re-animated after set appearance finished + public readonly static UUID CUSTOMIZE_DONE = new UUID("6883a61a-b27b-5914-a61e-dda118a9ee2c"); + /// Agent dancing + public readonly static UUID DANCE1 = new UUID("b68a3d7c-de9e-fc87-eec8-543d787e5b0d"); + /// Agent dancing + public readonly static UUID DANCE2 = new UUID("928cae18-e31d-76fd-9cc9-2f55160ff818"); + /// Agent dancing + public readonly static UUID DANCE3 = new UUID("30047778-10ea-1af7-6881-4db7a3a5a114"); + /// Agent dancing + public readonly static UUID DANCE4 = new UUID("951469f4-c7b2-c818-9dee-ad7eea8c30b7"); + /// Agent dancing + public readonly static UUID DANCE5 = new UUID("4bd69a1d-1114-a0b4-625f-84e0a5237155"); + /// Agent dancing + public readonly static UUID DANCE6 = new UUID("cd28b69b-9c95-bb78-3f94-8d605ff1bb12"); + /// Agent dancing + public readonly static UUID DANCE7 = new UUID("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6"); + /// Agent dancing + public readonly static UUID DANCE8 = new UUID("b0dc417c-1f11-af36-2e80-7e7489fa7cdc"); + /// Agent on ground unanimated + public readonly static UUID DEAD = new UUID("57abaae6-1d17-7b1b-5f98-6d11a6411276"); + /// Agent boozing it up + public readonly static UUID DRINK = new UUID("0f86e355-dd31-a61c-fdb0-3a96b9aad05f"); + /// Agent with embarassed expression on face + public readonly static UUID EMBARRASSED = new UUID("514af488-9051-044a-b3fc-d4dbf76377c6"); + /// Agent with afraid expression on face + public readonly static UUID EXPRESS_AFRAID = new UUID("aa2df84d-cf8f-7218-527b-424a52de766e"); + /// Agent with angry expression on face + public readonly static UUID EXPRESS_ANGER = new UUID("1a03b575-9634-b62a-5767-3a679e81f4de"); + /// Agent with bored expression on face + public readonly static UUID EXPRESS_BORED = new UUID("214aa6c1-ba6a-4578-f27c-ce7688f61d0d"); + /// Agent crying + public readonly static UUID EXPRESS_CRY = new UUID("d535471b-85bf-3b4d-a542-93bea4f59d33"); + /// Agent showing disdain (dislike) for something + public readonly static UUID EXPRESS_DISDAIN = new UUID("d4416ff1-09d3-300f-4183-1b68a19b9fc1"); + /// Agent with embarassed expression on face + public readonly static UUID EXPRESS_EMBARRASSED = new UUID("0b8c8211-d78c-33e8-fa28-c51a9594e424"); + /// Agent with frowning expression on face + public readonly static UUID EXPRESS_FROWN = new UUID("fee3df48-fa3d-1015-1e26-a205810e3001"); + /// Agent with kissy face + public readonly static UUID EXPRESS_KISS = new UUID("1e8d90cc-a84e-e135-884c-7c82c8b03a14"); + /// Agent expressing laughgter + public readonly static UUID EXPRESS_LAUGH = new UUID("62570842-0950-96f8-341c-809e65110823"); + /// Agent with open mouth + public readonly static UUID EXPRESS_OPEN_MOUTH = new UUID("d63bc1f9-fc81-9625-a0c6-007176d82eb7"); + /// Agent with repulsed expression on face + public readonly static UUID EXPRESS_REPULSED = new UUID("f76cda94-41d4-a229-2872-e0296e58afe1"); + /// Agent expressing sadness + public readonly static UUID EXPRESS_SAD = new UUID("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7"); + /// Agent shrugging shoulders + public readonly static UUID EXPRESS_SHRUG = new UUID("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef"); + /// Agent with a smile + public readonly static UUID EXPRESS_SMILE = new UUID("b7c7c833-e3d3-c4e3-9fc0-131237446312"); + /// Agent expressing surprise + public readonly static UUID EXPRESS_SURPRISE = new UUID("728646d9-cc79-08b2-32d6-937f0a835c24"); + /// Agent sticking tongue out + public readonly static UUID EXPRESS_TONGUE_OUT = new UUID("835965c6-7f2f-bda2-5deb-2478737f91bf"); + /// Agent with big toothy smile + public readonly static UUID EXPRESS_TOOTHSMILE = new UUID("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e"); + /// Agent winking + public readonly static UUID EXPRESS_WINK = new UUID("da020525-4d94-59d6-23d7-81fdebf33148"); + /// Agent expressing worry + public readonly static UUID EXPRESS_WORRY = new UUID("9c05e5c7-6f07-6ca4-ed5a-b230390c3950"); + /// Agent falling down + public readonly static UUID FALLDOWN = new UUID("666307d9-a860-572d-6fd4-c3ab8865c094"); + /// Agent walking (feminine version) + public readonly static UUID FEMALE_WALK = new UUID("f5fc7433-043d-e819-8298-f519a119b688"); + /// Agent wagging finger (disapproval) + public readonly static UUID FINGER_WAG = new UUID("c1bc7f36-3ba0-d844-f93c-93be945d644f"); + /// I'm not sure I want to know + public readonly static UUID FIST_PUMP = new UUID("7db00ccd-f380-f3ee-439d-61968ec69c8a"); + /// Agent in superman position + public readonly static UUID FLY = new UUID("aec4610c-757f-bc4e-c092-c6e9caf18daf"); + /// Agent in superman position + public readonly static UUID FLYSLOW = new UUID("2b5a38b2-5e00-3a97-a495-4c826bc443e6"); + /// Agent greeting another + public readonly static UUID HELLO = new UUID("9b29cd61-c45b-5689-ded2-91756b8d76a9"); + /// Agent holding bazooka (right handed) + public readonly static UUID HOLD_BAZOOKA_R = new UUID("ef62d355-c815-4816-2474-b1acc21094a6"); + /// Agent holding a bow (left handed) + public readonly static UUID HOLD_BOW_L = new UUID("8b102617-bcba-037b-86c1-b76219f90c88"); + /// Agent holding a handgun (right handed) + public readonly static UUID HOLD_HANDGUN_R = new UUID("efdc1727-8b8a-c800-4077-975fc27ee2f2"); + /// Agent holding a rifle (right handed) + public readonly static UUID HOLD_RIFLE_R = new UUID("3d94bad0-c55b-7dcc-8763-033c59405d33"); + /// Agent throwing an object (right handed) + public readonly static UUID HOLD_THROW_R = new UUID("7570c7b5-1f22-56dd-56ef-a9168241bbb6"); + /// Agent in static hover + public readonly static UUID HOVER = new UUID("4ae8016b-31b9-03bb-c401-b1ea941db41d"); + /// Agent hovering downward + public readonly static UUID HOVER_DOWN = new UUID("20f063ea-8306-2562-0b07-5c853b37b31e"); + /// Agent hovering upward + public readonly static UUID HOVER_UP = new UUID("62c5de58-cb33-5743-3d07-9e4cd4352864"); + /// Agent being impatient + public readonly static UUID IMPATIENT = new UUID("5ea3991f-c293-392e-6860-91dfa01278a3"); + /// Agent jumping + public readonly static UUID JUMP = new UUID("2305bd75-1ca9-b03b-1faa-b176b8a8c49e"); + /// Agent jumping with fervor + public readonly static UUID JUMP_FOR_JOY = new UUID("709ea28e-1573-c023-8bf8-520c8bc637fa"); + /// Agent point to lips then rear end + public readonly static UUID KISS_MY_BUTT = new UUID("19999406-3a3a-d58c-a2ac-d72e555dcf51"); + /// Agent landing from jump, finished flight, etc + public readonly static UUID LAND = new UUID("7a17b059-12b2-41b1-570a-186368b6aa6f"); + /// Agent laughing + public readonly static UUID LAUGH_SHORT = new UUID("ca5b3f14-3194-7a2b-c894-aa699b718d1f"); + /// Agent landing from jump, finished flight, etc + public readonly static UUID MEDIUM_LAND = new UUID("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57"); + /// Agent sitting on a motorcycle + public readonly static UUID MOTORCYCLE_SIT = new UUID("08464f78-3a8e-2944-cba5-0c94aff3af29"); + /// + public readonly static UUID MUSCLE_BEACH = new UUID("315c3a41-a5f3-0ba4-27da-f893f769e69b"); + /// Agent moving head side to side + public readonly static UUID NO = new UUID("5a977ed9-7f72-44e9-4c4c-6e913df8ae74"); + /// Agent moving head side to side with unhappy expression + public readonly static UUID NO_UNHAPPY = new UUID("d83fa0e5-97ed-7eb2-e798-7bd006215cb4"); + /// Agent taunting another + public readonly static UUID NYAH_NYAH = new UUID("f061723d-0a18-754f-66ee-29a44795a32f"); + /// + public readonly static UUID ONETWO_PUNCH = new UUID("eefc79be-daae-a239-8c04-890f5d23654a"); + /// Agent giving peace sign + public readonly static UUID PEACE = new UUID("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9"); + /// Agent pointing at self + public readonly static UUID POINT_ME = new UUID("17c024cc-eef2-f6a0-3527-9869876d7752"); + /// Agent pointing at another + public readonly static UUID POINT_YOU = new UUID("ec952cca-61ef-aa3b-2789-4d1344f016de"); + /// Agent preparing for jump (bending knees) + public readonly static UUID PRE_JUMP = new UUID("7a4e87fe-de39-6fcb-6223-024b00893244"); + /// Agent punching with left hand + public readonly static UUID PUNCH_LEFT = new UUID("f3300ad9-3462-1d07-2044-0fef80062da0"); + /// Agent punching with right hand + public readonly static UUID PUNCH_RIGHT = new UUID("c8e42d32-7310-6906-c903-cab5d4a34656"); + /// Agent acting repulsed + public readonly static UUID REPULSED = new UUID("36f81a92-f076-5893-dc4b-7c3795e487cf"); + /// Agent trying to be Chuck Norris + public readonly static UUID ROUNDHOUSE_KICK = new UUID("49aea43b-5ac3-8a44-b595-96100af0beda"); + /// Rocks, Paper, Scissors 1, 2, 3 + public readonly static UUID RPS_COUNTDOWN = new UUID("35db4f7e-28c2-6679-cea9-3ee108f7fc7f"); + /// Agent with hand flat over other hand + public readonly static UUID RPS_PAPER = new UUID("0836b67f-7f7b-f37b-c00a-460dc1521f5a"); + /// Agent with fist over other hand + public readonly static UUID RPS_ROCK = new UUID("42dd95d5-0bc6-6392-f650-777304946c0f"); + /// Agent with two fingers spread over other hand + public readonly static UUID RPS_SCISSORS = new UUID("16803a9f-5140-e042-4d7b-d28ba247c325"); + /// Agent running + public readonly static UUID RUN = new UUID("05ddbff8-aaa9-92a1-2b74-8fe77a29b445"); + /// Agent appearing sad + public readonly static UUID SAD = new UUID("0eb702e2-cc5a-9a88-56a5-661a55c0676a"); + /// Agent saluting + public readonly static UUID SALUTE = new UUID("cd7668a6-7011-d7e2-ead8-fc69eff1a104"); + /// Agent shooting bow (left handed) + public readonly static UUID SHOOT_BOW_L = new UUID("e04d450d-fdb5-0432-fd68-818aaf5935f8"); + /// Agent cupping mouth as if shouting + public readonly static UUID SHOUT = new UUID("6bd01860-4ebd-127a-bb3d-d1427e8e0c42"); + /// Agent shrugging shoulders + public readonly static UUID SHRUG = new UUID("70ea714f-3a97-d742-1b01-590a8fcd1db5"); + /// Agent in sit position + public readonly static UUID SIT = new UUID("1a5fe8ac-a804-8a5d-7cbd-56bd83184568"); + /// Agent in sit position (feminine) + public readonly static UUID SIT_FEMALE = new UUID("b1709c8d-ecd3-54a1-4f28-d55ac0840782"); + /// Agent in sit position (generic) + public readonly static UUID SIT_GENERIC = new UUID("245f3c54-f1c0-bf2e-811f-46d8eeb386e7"); + /// Agent sitting on ground + public readonly static UUID SIT_GROUND = new UUID("1c7600d6-661f-b87b-efe2-d7421eb93c86"); + /// Agent sitting on ground + public readonly static UUID SIT_GROUND_staticRAINED = new UUID("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e"); + /// + public readonly static UUID SIT_TO_STAND = new UUID("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e"); + /// Agent sleeping on side + public readonly static UUID SLEEP = new UUID("f2bed5f9-9d44-39af-b0cd-257b2a17fe40"); + /// Agent smoking + public readonly static UUID SMOKE_IDLE = new UUID("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a"); + /// Agent inhaling smoke + public readonly static UUID SMOKE_INHALE = new UUID("6802d553-49da-0778-9f85-1599a2266526"); + /// + public readonly static UUID SMOKE_THROW_DOWN = new UUID("0a9fb970-8b44-9114-d3a9-bf69cfe804d6"); + /// Agent taking a picture + public readonly static UUID SNAPSHOT = new UUID("eae8905b-271a-99e2-4c0e-31106afd100c"); + /// Agent standing + public readonly static UUID STAND = new UUID("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f"); + /// Agent standing up + public readonly static UUID STANDUP = new UUID("3da1d753-028a-5446-24f3-9c9b856d9422"); + /// Agent standing + public readonly static UUID STAND_1 = new UUID("15468e00-3400-bb66-cecc-646d7c14458e"); + /// Agent standing + public readonly static UUID STAND_2 = new UUID("370f3a20-6ca6-9971-848c-9a01bc42ae3c"); + /// Agent standing + public readonly static UUID STAND_3 = new UUID("42b46214-4b44-79ae-deb8-0df61424ff4b"); + /// Agent standing + public readonly static UUID STAND_4 = new UUID("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f"); + /// Agent stretching + public readonly static UUID STRETCH = new UUID("80700431-74ec-a008-14f8-77575e73693f"); + /// Agent in stride (fast walk) + public readonly static UUID STRIDE = new UUID("1cb562b0-ba21-2202-efb3-30f82cdf9595"); + /// Agent surfing + public readonly static UUID SURF = new UUID("41426836-7437-7e89-025d-0aa4d10f1d69"); + /// Agent acting surprised + public readonly static UUID SURPRISE = new UUID("313b9881-4302-73c0-c7d0-0e7a36b6c224"); + /// Agent striking with a sword + public readonly static UUID SWORD_STRIKE = new UUID("85428680-6bf9-3e64-b489-6f81087c24bd"); + /// Agent talking (lips moving) + public readonly static UUID TALK = new UUID("5c682a95-6da4-a463-0bf6-0f5b7be129d1"); + /// Agent throwing a tantrum + public readonly static UUID TANTRUM = new UUID("11000694-3f41-adc2-606b-eee1d66f3724"); + /// Agent throwing an object (right handed) + public readonly static UUID THROW_R = new UUID("aa134404-7dac-7aca-2cba-435f9db875ca"); + /// Agent trying on a shirt + public readonly static UUID TRYON_SHIRT = new UUID("83ff59fe-2346-f236-9009-4e3608af64c1"); + /// Agent turning to the left + public readonly static UUID TURNLEFT = new UUID("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135"); + /// Agent turning to the right + public readonly static UUID TURNRIGHT = new UUID("2d6daa51-3192-6794-8e2e-a15f8338ec30"); + /// Agent typing + public readonly static UUID TYPE = new UUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9"); + /// Agent walking + public readonly static UUID WALK = new UUID("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0"); + /// Agent whispering + public readonly static UUID WHISPER = new UUID("7693f268-06c7-ea71-fa21-2b30d6533f8f"); + /// Agent whispering with fingers in mouth + public readonly static UUID WHISTLE = new UUID("b1ed7982-c68e-a982-7561-52a88a5298c0"); + /// Agent winking + public readonly static UUID WINK = new UUID("869ecdad-a44b-671e-3266-56aef2e3ac2e"); + /// Agent winking + public readonly static UUID WINK_HOLLYWOOD = new UUID("c0c4030f-c02b-49de-24ba-2331f43fe41c"); + /// Agent worried + public readonly static UUID WORRY = new UUID("9f496bd2-589a-709f-16cc-69bf7df1d36c"); + /// Agent nodding yes + public readonly static UUID YES = new UUID("15dd911d-be82-2856-26db-27659b142875"); + /// Agent nodding yes with happy face + public readonly static UUID YES_HAPPY = new UUID("b8c8b2a3-9008-1771-3bfc-90924955ab2d"); + /// Agent floating with legs and arms crossed + public readonly static UUID YOGA_FLOAT = new UUID("42ecd00b-9947-a97c-400a-bbc9174c7aeb"); + + /// + /// A dictionary containing all pre-defined animations + /// + /// A dictionary containing the pre-defined animations, + /// where the key is the animations ID, and the value is a string + /// containing a name to identify the purpose of the animation + public static Dictionary ToDictionary() + { + Dictionary dict = new Dictionary(); + Type type = typeof(Animations); + foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Static)) + { + dict.Add((UUID)field.GetValue(type), field.Name); + } + return dict; + } + } +} diff --git a/OpenMetaverse/AppearanceManager.cs b/OpenMetaverse/AppearanceManager.cs new file mode 100644 index 0000000..c87e5fd --- /dev/null +++ b/OpenMetaverse/AppearanceManager.cs @@ -0,0 +1,2567 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Drawing; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.Imaging; +using OpenMetaverse.Assets; +using OpenMetaverse.Http; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// Index of TextureEntry slots for avatar appearances + /// + public enum AvatarTextureIndex + { + Unknown = -1, + HeadBodypaint = 0, + UpperShirt, + LowerPants, + EyesIris, + Hair, + UpperBodypaint, + LowerBodypaint, + LowerShoes, + HeadBaked, + UpperBaked, + LowerBaked, + EyesBaked, + LowerSocks, + UpperJacket, + LowerJacket, + UpperGloves, + UpperUndershirt, + LowerUnderpants, + Skirt, + SkirtBaked, + HairBaked, + LowerAlpha, + UpperAlpha, + HeadAlpha, + EyesAlpha, + HairAlpha, + HeadTattoo, + UpperTattoo, + LowerTattoo, + NumberOfEntries + } + + /// + /// Bake layers for avatar appearance + /// + public enum BakeType + { + Unknown = -1, + Head = 0, + UpperBody = 1, + LowerBody = 2, + Eyes = 3, + Skirt = 4, + Hair = 5 + } + + /// + /// Appearance Flags, introdued with server side baking, currently unused + /// + [Flags] + public enum AppearanceFlags : uint + { + None = 0 + } + + + #endregion Enums + + public class AppearanceManager + { + #region Constants + /// Mask for multiple attachments + public static readonly byte ATTACHMENT_ADD = 0x80; + /// Mapping between BakeType and AvatarTextureIndex + public static readonly byte[] BakeIndexToTextureIndex = new byte[BAKED_TEXTURE_COUNT] { 8, 9, 10, 11, 19, 20 }; + /// Maximum number of concurrent downloads for wearable assets and textures + const int MAX_CONCURRENT_DOWNLOADS = 5; + /// Maximum number of concurrent uploads for baked textures + const int MAX_CONCURRENT_UPLOADS = 6; + /// Timeout for fetching inventory listings + const int INVENTORY_TIMEOUT = 1000 * 30; + /// Timeout for fetching a single wearable, or receiving a single packet response + const int WEARABLE_TIMEOUT = 1000 * 30; + /// Timeout for fetching a single texture + const int TEXTURE_TIMEOUT = 1000 * 120; + /// Timeout for uploading a single baked texture + const int UPLOAD_TIMEOUT = 1000 * 90; + /// Number of times to retry bake upload + const int UPLOAD_RETRIES = 2; + /// When changing outfit, kick off rebake after + /// 20 seconds has passed since the last change + const int REBAKE_DELAY = 1000 * 20; + + /// Total number of wearables for each avatar + public const int WEARABLE_COUNT = 16; + /// Total number of baked textures on each avatar + public const int BAKED_TEXTURE_COUNT = 6; + /// Total number of wearables per bake layer + public const int WEARABLES_PER_LAYER = 9; + /// Map of what wearables are included in each bake + public static readonly WearableType[][] WEARABLE_BAKE_MAP = new WearableType[][] + { + new WearableType[] { WearableType.Shape, WearableType.Skin, WearableType.Tattoo, WearableType.Hair, WearableType.Alpha, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid }, + new WearableType[] { WearableType.Shape, WearableType.Skin, WearableType.Tattoo, WearableType.Shirt, WearableType.Jacket, WearableType.Gloves, WearableType.Undershirt, WearableType.Alpha, WearableType.Invalid }, + new WearableType[] { WearableType.Shape, WearableType.Skin, WearableType.Tattoo, WearableType.Pants, WearableType.Shoes, WearableType.Socks, WearableType.Jacket, WearableType.Underpants, WearableType.Alpha }, + new WearableType[] { WearableType.Eyes, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid }, + new WearableType[] { WearableType.Skirt, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid }, + new WearableType[] { WearableType.Hair, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid, WearableType.Invalid } + }; + /// Magic values to finalize the cache check hashes for each + /// bake + public static readonly UUID[] BAKED_TEXTURE_HASH = new UUID[] + { + new UUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6"), + new UUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f"), + new UUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f"), + new UUID("b2cf28af-b840-1071-3c6a-78085d8128b5"), + new UUID("ea800387-ea1a-14e0-56cb-24f2022f969a"), + new UUID("0af1ef7c-ad24-11dd-8790-001f5bf833e8") + }; + /// Default avatar texture, used to detect when a custom + /// texture is not set for a face + public static readonly UUID DEFAULT_AVATAR_TEXTURE = new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); + + #endregion Constants + + #region Structs / Classes + + /// + /// Contains information about a wearable inventory item + /// + public class WearableData + { + /// Inventory ItemID of the wearable + public UUID ItemID; + /// AssetID of the wearable asset + public UUID AssetID; + /// WearableType of the wearable + public WearableType WearableType; + /// AssetType of the wearable + public AssetType AssetType; + /// Asset data for the wearable + public AssetWearable Asset; + + public override string ToString() + { + return String.Format("ItemID: {0}, AssetID: {1}, WearableType: {2}, AssetType: {3}, Asset: {4}", + ItemID, AssetID, WearableType, AssetType, Asset != null ? Asset.Name : "(null)"); + } + } + + /// + /// Data collected from visual params for each wearable + /// needed for the calculation of the color + /// + public struct ColorParamInfo + { + public VisualParam VisualParam; + public VisualColorParam VisualColorParam; + public float Value; + public WearableType WearableType; + } + + /// + /// Holds a texture assetID and the data needed to bake this layer into + /// an outfit texture. Used to keep track of currently worn textures + /// and baking data + /// + public struct TextureData + { + /// A texture AssetID + public UUID TextureID; + /// Asset data for the texture + public AssetTexture Texture; + /// Collection of alpha masks that needs applying + public Dictionary AlphaMasks; + /// Tint that should be applied to the texture + public Color4 Color; + /// Where on avatar does this texture belong + public AvatarTextureIndex TextureIndex; + + public override string ToString() + { + return String.Format("TextureID: {0}, Texture: {1}", + TextureID, Texture != null ? Texture.AssetData.Length + " bytes" : "(null)"); + } + } + + #endregion Structs / Classes + + #region Event delegates, Raise Events + + /// The event subscribers. null if no subcribers + private EventHandler m_AgentWearablesReply; + + /// Raises the AgentWearablesReply event + /// An AgentWearablesReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnAgentWearables(AgentWearablesReplyEventArgs e) + { + EventHandler handler = m_AgentWearablesReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AgentWearablesLock = new object(); + + /// Triggered when an AgentWearablesUpdate packet is received, + /// telling us what our avatar is currently wearing + /// request. + public event EventHandler AgentWearablesReply + { + add { lock (m_AgentWearablesLock) { m_AgentWearablesReply += value; } } + remove { lock (m_AgentWearablesLock) { m_AgentWearablesReply -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_AgentCachedBakesReply; + + /// Raises the CachedBakesReply event + /// An AgentCachedBakesReplyEventArgs object containing the + /// data returned from the data server AgentCachedTextureResponse + protected virtual void OnAgentCachedBakes(AgentCachedBakesReplyEventArgs e) + { + EventHandler handler = m_AgentCachedBakesReply; + if (handler != null) + handler(this, e); + } + + + /// Thread sync lock object + private readonly object m_AgentCachedBakesLock = new object(); + + /// Raised when an AgentCachedTextureResponse packet is + /// received, giving a list of cached bakes that were found on the + /// simulator + /// request. + public event EventHandler CachedBakesReply + { + add { lock (m_AgentCachedBakesLock) { m_AgentCachedBakesReply += value; } } + remove { lock (m_AgentCachedBakesLock) { m_AgentCachedBakesReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_AppearanceSet; + + /// Raises the AppearanceSet event + /// An AppearanceSetEventArgs object indicating if the operatin was successfull + protected virtual void OnAppearanceSet(AppearanceSetEventArgs e) + { + EventHandler handler = m_AppearanceSet; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AppearanceSetLock = new object(); + + /// + /// Raised when appearance data is sent to the simulator, also indicates + /// the main appearance thread is finished. + /// + /// request. + public event EventHandler AppearanceSet + { + add { lock (m_AppearanceSetLock) { m_AppearanceSet += value; } } + remove { lock (m_AppearanceSetLock) { m_AppearanceSet -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_RebakeAvatarReply; + + /// Raises the RebakeAvatarRequested event + /// An RebakeAvatarTexturesEventArgs object containing the + /// data returned from the data server + protected virtual void OnRebakeAvatar(RebakeAvatarTexturesEventArgs e) + { + EventHandler handler = m_RebakeAvatarReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_RebakeAvatarLock = new object(); + + /// + /// Triggered when the simulator requests the agent rebake its appearance. + /// + /// + public event EventHandler RebakeAvatarRequested + { + add { lock (m_RebakeAvatarLock) { m_RebakeAvatarReply += value; } } + remove { lock (m_RebakeAvatarLock) { m_RebakeAvatarReply -= value; } } + } + + #endregion + + #region Properties and public fields + + /// + /// Returns true if AppearanceManager is busy and trying to set or change appearance will fail + /// + public bool ManagerBusy + { + get + { + return AppearanceThreadRunning != 0; + } + } + + /// Visual parameters last sent to the sim + public byte[] MyVisualParameters = null; + + /// Textures about this client sent to the sim + public Primitive.TextureEntry MyTextures = null; + + #endregion Properties + + #region Private Members + + /// A cache of wearables currently being worn + private Dictionary Wearables = new Dictionary(); + /// A cache of textures currently being worn + private TextureData[] Textures = new TextureData[(int)AvatarTextureIndex.NumberOfEntries]; + /// Incrementing serial number for AgentCachedTexture packets + private int CacheCheckSerialNum = -1; + /// Incrementing serial number for AgentSetAppearance packets + private int SetAppearanceSerialNum = 0; + /// Indicates if WearablesRequest succeeded + private bool GotWearables = false; + /// Indicates whether or not the appearance thread is currently + /// running, to prevent multiple appearance threads from running + /// simultaneously + private int AppearanceThreadRunning = 0; + /// Reference to our agent + private GridClient Client; + /// + /// Timer used for delaying rebake on changing outfit + /// + private Timer RebakeScheduleTimer; + /// + /// Main appearance thread + /// + private Thread AppearanceThread; + /// + /// Is server baking complete. It needs doing only once + /// + private bool ServerBakingDone = false; + #endregion Private Members + + /// + /// Default constructor + /// + /// A reference to our agent + public AppearanceManager(GridClient client) + { + Client = client; + + Client.Network.RegisterCallback(PacketType.AgentWearablesUpdate, AgentWearablesUpdateHandler); + Client.Network.RegisterCallback(PacketType.AgentCachedTextureResponse, AgentCachedTextureResponseHandler); + Client.Network.RegisterCallback(PacketType.RebakeAvatarTextures, RebakeAvatarTexturesHandler); + + Client.Network.EventQueueRunning += Network_OnEventQueueRunning; + Client.Network.Disconnected += Network_OnDisconnected; + } + + #region Publics Methods + + /// + /// Obsolete method for setting appearance. This function no longer does anything. + /// Use RequestSetAppearance() to manually start the appearance thread + /// + [Obsolete("Appearance is now handled automatically")] + public void SetPreviousAppearance() + { + } + + /// + /// Obsolete method for setting appearance. This function no longer does anything. + /// Use RequestSetAppearance() to manually start the appearance thread + /// + /// Unused parameter + [Obsolete("Appearance is now handled automatically")] + public void SetPreviousAppearance(bool allowBake) + { + } + + /// + /// Starts the appearance setting thread + /// + public void RequestSetAppearance() + { + RequestSetAppearance(false); + } + + /// + /// Starts the appearance setting thread + /// + /// True to force rebaking, otherwise false + public void RequestSetAppearance(bool forceRebake) + { + if (Interlocked.CompareExchange(ref AppearanceThreadRunning, 1, 0) != 0) + { + Logger.Log("Appearance thread is already running, skipping", Helpers.LogLevel.Warning); + return; + } + + // If we have an active delayed scheduled appearance bake, we dispose of it + if (RebakeScheduleTimer != null) + { + RebakeScheduleTimer.Dispose(); + RebakeScheduleTimer = null; + } + + // This is the first time setting appearance, run through the entire sequence + AppearanceThread = new Thread( + delegate() + { + bool success = true; + try + { + if (forceRebake) + { + // Set all of the baked textures to UUID.Zero to force rebaking + for (int bakedIndex = 0; bakedIndex < BAKED_TEXTURE_COUNT; bakedIndex++) + Textures[(int)BakeTypeToAgentTextureIndex((BakeType)bakedIndex)].TextureID = UUID.Zero; + } + + // Is this server side baking enabled sim + if (ServerBakingRegion()) + { + if (!GotWearables) + { + // Fetch a list of the current agent wearables + if (GetAgentWearables()) + { + GotWearables = true; + } + } + + if (!ServerBakingDone || forceRebake) + { + if (UpdateAvatarAppearance()) + { + ServerBakingDone = true; + } + else + { + success = false; + } + } + } + else // Classic client side baking + { + if (!GotWearables) + { + // Fetch a list of the current agent wearables + if (!GetAgentWearables()) + { + Logger.Log("Failed to retrieve a list of current agent wearables, appearance cannot be set", + Helpers.LogLevel.Error, Client); + throw new Exception("Failed to retrieve a list of current agent wearables, appearance cannot be set"); + } + GotWearables = true; + } + + // If we get back to server side backing region re-request server bake + ServerBakingDone = false; + + // Download and parse all of the agent wearables + if (!DownloadWearables()) + { + success = false; + Logger.Log("One or more agent wearables failed to download, appearance will be incomplete", + Helpers.LogLevel.Warning, Client); + } + + // If this is the first time setting appearance and we're not forcing rebakes, check the server + // for cached bakes + if (SetAppearanceSerialNum == 0 && !forceRebake) + { + // Compute hashes for each bake layer and compare against what the simulator currently has + if (!GetCachedBakes()) + { + Logger.Log("Failed to get a list of cached bakes from the simulator, appearance will be rebaked", + Helpers.LogLevel.Warning, Client); + } + } + + // Download textures, compute bakes, and upload for any cache misses + if (!CreateBakes()) + { + success = false; + Logger.Log("Failed to create or upload one or more bakes, appearance will be incomplete", + Helpers.LogLevel.Warning, Client); + } + + // Send the appearance packet + RequestAgentSetAppearance(); + } + } + catch (Exception e) + { + Logger.Log( + string.Format("Failed to set appearance with exception {0}", e), Helpers.LogLevel.Warning, Client); + + success = false; + } + finally + { + AppearanceThreadRunning = 0; + + OnAppearanceSet(new AppearanceSetEventArgs(success)); + } + } + ); + + AppearanceThread.Name = "Appearance"; + AppearanceThread.IsBackground = true; + AppearanceThread.Start(); + } + + /// + /// Check if current region supports server side baking + /// + /// True if server side baking support is detected + public bool ServerBakingRegion() + { + return Client.Network.CurrentSim != null && + ((Client.Network.CurrentSim.Protocols & RegionProtocols.AgentAppearanceService) != 0); + } + + /// + /// Ask the server what textures our agent is currently wearing + /// + public void RequestAgentWearables() + { + AgentWearablesRequestPacket request = new AgentWearablesRequestPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + Client.Network.SendPacket(request); + } + + /// + /// Build hashes out of the texture assetIDs for each baking layer to + /// ask the simulator whether it has cached copies of each baked texture + /// + public void RequestCachedBakes() + { + List hashes = new List(); + + // Build hashes for each of the bake layers from the individual components + lock (Wearables) + { + for (int bakedIndex = 0; bakedIndex < BAKED_TEXTURE_COUNT; bakedIndex++) + { + // Don't do a cache request for a skirt bake if we're not wearing a skirt + if (bakedIndex == (int)BakeType.Skirt && !Wearables.ContainsKey(WearableType.Skirt)) + continue; + + // Build a hash of all the texture asset IDs in this baking layer + UUID hash = UUID.Zero; + for (int wearableIndex = 0; wearableIndex < WEARABLES_PER_LAYER; wearableIndex++) + { + WearableType type = WEARABLE_BAKE_MAP[bakedIndex][wearableIndex]; + + WearableData wearable; + if (type != WearableType.Invalid && Wearables.TryGetValue(type, out wearable)) + hash ^= wearable.AssetID; + } + + if (hash != UUID.Zero) + { + // Hash with our secret value for this baked layer + hash ^= BAKED_TEXTURE_HASH[bakedIndex]; + + // Add this to the list of hashes to send out + AgentCachedTexturePacket.WearableDataBlock block = new AgentCachedTexturePacket.WearableDataBlock(); + block.ID = hash; + block.TextureIndex = (byte)bakedIndex; + hashes.Add(block); + + Logger.DebugLog("Checking cache for " + (BakeType)block.TextureIndex + ", hash=" + block.ID, Client); + } + } + } + + // Only send the packet out if there's something to check + if (hashes.Count > 0) + { + AgentCachedTexturePacket cache = new AgentCachedTexturePacket(); + cache.AgentData.AgentID = Client.Self.AgentID; + cache.AgentData.SessionID = Client.Self.SessionID; + cache.AgentData.SerialNum = Interlocked.Increment(ref CacheCheckSerialNum); + + cache.WearableData = hashes.ToArray(); + + Client.Network.SendPacket(cache); + } + } + + /// + /// Returns the AssetID of the asset that is currently being worn in a + /// given WearableType slot + /// + /// WearableType slot to get the AssetID for + /// The UUID of the asset being worn in the given slot, or + /// UUID.Zero if no wearable is attached to the given slot or wearables + /// have not been downloaded yet + public UUID GetWearableAsset(WearableType type) + { + WearableData wearable; + + if (Wearables.TryGetValue(type, out wearable)) + return wearable.AssetID; + else + return UUID.Zero; + } + + /// + /// Add a wearable to the current outfit and set appearance + /// + /// Wearable to be added to the outfit + public void AddToOutfit(InventoryItem wearableItem) + { + List wearableItems = new List { wearableItem }; + AddToOutfit(wearableItems); + } + + /// + /// Add a wearable to the current outfit and set appearance + /// + /// Wearable to be added to the outfit + /// Should existing item on the same point or of the same type be replaced + public void AddToOutfit(InventoryItem wearableItem, bool replace) + { + List wearableItems = new List { wearableItem }; + AddToOutfit(wearableItems, true); + } + + /// + /// Add a list of wearables to the current outfit and set appearance + /// + /// List of wearable inventory items to + /// be added to the outfit + /// Should existing item on the same point or of the same type be replaced + public void AddToOutfit(List wearableItems) + { + AddToOutfit(wearableItems, true); + } + + /// + /// Add a list of wearables to the current outfit and set appearance + /// + /// List of wearable inventory items to + /// be added to the outfit + /// Should existing item on the same point or of the same type be replaced + public void AddToOutfit(List wearableItems, bool replace) + { + List wearables = new List(); + List attachments = new List(); + + for (int i = 0; i < wearableItems.Count; i++) + { + InventoryItem item = wearableItems[i]; + + if (item is InventoryWearable) + wearables.Add((InventoryWearable)item); + else if (item is InventoryAttachment || item is InventoryObject) + attachments.Add(item); + } + + lock (Wearables) + { + // Add the given wearables to the wearables collection + for (int i = 0; i < wearables.Count; i++) + { + InventoryWearable wearableItem = wearables[i]; + + WearableData wd = new WearableData(); + wd.AssetID = wearableItem.AssetUUID; + wd.AssetType = wearableItem.AssetType; + wd.ItemID = wearableItem.UUID; + wd.WearableType = wearableItem.WearableType; + + Wearables[wearableItem.WearableType] = wd; + } + } + + if (attachments.Count > 0) + { + AddAttachments(attachments, false, replace); + } + + if (wearables.Count > 0) + { + SendAgentIsNowWearing(); + DelayedRequestSetAppearance(); + } + } + + /// + /// Remove a wearable from the current outfit and set appearance + /// + /// Wearable to be removed from the outfit + public void RemoveFromOutfit(InventoryItem wearableItem) + { + List wearableItems = new List(); + wearableItems.Add(wearableItem); + RemoveFromOutfit(wearableItems); + } + + + /// + /// Removes a list of wearables from the current outfit and set appearance + /// + /// List of wearable inventory items to + /// be removed from the outfit + public void RemoveFromOutfit(List wearableItems) + { + List wearables = new List(); + List attachments = new List(); + + for (int i = 0; i < wearableItems.Count; i++) + { + InventoryItem item = wearableItems[i]; + + if (item is InventoryWearable) + wearables.Add((InventoryWearable)item); + else if (item is InventoryAttachment || item is InventoryObject) + attachments.Add(item); + } + + bool needSetAppearance = false; + lock (Wearables) + { + // Remove the given wearables from the wearables collection + for (int i = 0; i < wearables.Count; i++) + { + InventoryWearable wearableItem = wearables[i]; + if (wearables[i].AssetType != AssetType.Bodypart // Remove if it's not a body part + && Wearables.ContainsKey(wearableItem.WearableType) // And we have that wearabe type + && Wearables[wearableItem.WearableType].ItemID == wearableItem.UUID // And we are wearing it + ) + { + Wearables.Remove(wearableItem.WearableType); + needSetAppearance = true; + } + } + } + + for (int i = 0; i < attachments.Count; i++) + { + Detach(attachments[i].UUID); + } + + if (needSetAppearance) + { + SendAgentIsNowWearing(); + DelayedRequestSetAppearance(); + } + } + + /// + /// Replace the current outfit with a list of wearables and set appearance + /// + /// List of wearable inventory items that + /// define a new outfit + public void ReplaceOutfit(List wearableItems) + { + ReplaceOutfit(wearableItems, true); + } + + /// + /// Replace the current outfit with a list of wearables and set appearance + /// + /// List of wearable inventory items that + /// define a new outfit + /// Check if we have all body parts, set this to false only + /// if you know what you're doing + public void ReplaceOutfit(List wearableItems, bool safe) + { + List wearables = new List(); + List attachments = new List(); + + for (int i = 0; i < wearableItems.Count; i++) + { + InventoryItem item = wearableItems[i]; + + if (item is InventoryWearable) + wearables.Add((InventoryWearable)item); + else if (item is InventoryAttachment || item is InventoryObject) + attachments.Add(item); + } + + if (safe) + { + // If we don't already have a the current agent wearables downloaded, updating to a + // new set of wearables that doesn't have all of the bodyparts can leave the avatar + // in an inconsistent state. If any bodypart entries are empty, we need to fetch the + // current wearables first + bool needsCurrentWearables = false; + lock (Wearables) + { + for (int i = 0; i < WEARABLE_COUNT; i++) + { + WearableType wearableType = (WearableType)i; + if (WearableTypeToAssetType(wearableType) == AssetType.Bodypart && !Wearables.ContainsKey(wearableType)) + { + needsCurrentWearables = true; + break; + } + } + } + + if (needsCurrentWearables && !GetAgentWearables()) + { + Logger.Log("Failed to fetch the current agent wearables, cannot safely replace outfit", + Helpers.LogLevel.Error); + return; + } + } + + // Replace our local Wearables collection, send the packet(s) to update our + // attachments, tell sim what we are wearing now, and start the baking process + if (!safe) + { + SetAppearanceSerialNum++; + } + ReplaceOutfit(wearables); + AddAttachments(attachments, true, false); + SendAgentIsNowWearing(); + DelayedRequestSetAppearance(); + } + + /// + /// Checks if an inventory item is currently being worn + /// + /// The inventory item to check against the agent + /// wearables + /// The WearableType slot that the item is being worn in, + /// or WearbleType.Invalid if it is not currently being worn + public WearableType IsItemWorn(InventoryItem item) + { + lock (Wearables) + { + foreach (KeyValuePair entry in Wearables) + { + if (entry.Value.ItemID == item.UUID) + return entry.Key; + } + } + + return WearableType.Invalid; + } + + /// + /// Returns a copy of the agents currently worn wearables + /// + /// A copy of the agents currently worn wearables + /// Avoid calling this function multiple times as it will make + /// a copy of all of the wearable data each time + public Dictionary GetWearables() + { + lock (Wearables) + return new Dictionary(Wearables); + } + + /// + /// Calls either or + /// depending on the value of + /// replaceItems + /// + /// List of wearable inventory items to add + /// to the outfit or become a new outfit + /// True to replace existing items with the + /// new list of items, false to add these items to the existing outfit + public void WearOutfit(List wearables, bool replaceItems) + { + List wearableItems = new List(wearables.Count); + for (int i = 0; i < wearables.Count; i++) + { + if (wearables[i] is InventoryItem) + wearableItems.Add((InventoryItem)wearables[i]); + } + + if (replaceItems) + ReplaceOutfit(wearableItems); + else + AddToOutfit(wearableItems); + } + + #endregion Publics Methods + + #region Attachments + + /// + /// Adds a list of attachments to our agent + /// + /// A List containing the attachments to add + /// If true, tells simulator to remove existing attachment + /// first + public void AddAttachments(List attachments, bool removeExistingFirst) + { + AddAttachments(attachments, removeExistingFirst, true); + } + + /// + /// Adds a list of attachments to our agent + /// + /// A List containing the attachments to add + /// If true, tells simulator to remove existing attachment + /// If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + /// first + public void AddAttachments(List attachments, bool removeExistingFirst, bool replace) + { + // Use RezMultipleAttachmentsFromInv to clear out current attachments, and attach new ones + RezMultipleAttachmentsFromInvPacket attachmentsPacket = new RezMultipleAttachmentsFromInvPacket(); + attachmentsPacket.AgentData.AgentID = Client.Self.AgentID; + attachmentsPacket.AgentData.SessionID = Client.Self.SessionID; + + attachmentsPacket.HeaderData.CompoundMsgID = UUID.Random(); + attachmentsPacket.HeaderData.FirstDetachAll = removeExistingFirst; + attachmentsPacket.HeaderData.TotalObjects = (byte)attachments.Count; + + attachmentsPacket.ObjectData = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[attachments.Count]; + for (int i = 0; i < attachments.Count; i++) + { + if (attachments[i] is InventoryAttachment) + { + InventoryAttachment attachment = (InventoryAttachment)attachments[i]; + attachmentsPacket.ObjectData[i] = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock(); + attachmentsPacket.ObjectData[i].AttachmentPt = replace ? (byte)attachment.AttachmentPoint : (byte)(ATTACHMENT_ADD | (byte)attachment.AttachmentPoint); + attachmentsPacket.ObjectData[i].EveryoneMask = (uint)attachment.Permissions.EveryoneMask; + attachmentsPacket.ObjectData[i].GroupMask = (uint)attachment.Permissions.GroupMask; + attachmentsPacket.ObjectData[i].ItemFlags = (uint)attachment.Flags; + attachmentsPacket.ObjectData[i].ItemID = attachment.UUID; + attachmentsPacket.ObjectData[i].Name = Utils.StringToBytes(attachment.Name); + attachmentsPacket.ObjectData[i].Description = Utils.StringToBytes(attachment.Description); + attachmentsPacket.ObjectData[i].NextOwnerMask = (uint)attachment.Permissions.NextOwnerMask; + attachmentsPacket.ObjectData[i].OwnerID = attachment.OwnerID; + } + else if (attachments[i] is InventoryObject) + { + InventoryObject attachment = (InventoryObject)attachments[i]; + attachmentsPacket.ObjectData[i] = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock(); + attachmentsPacket.ObjectData[i].AttachmentPt = replace ? (byte)0 : ATTACHMENT_ADD; + attachmentsPacket.ObjectData[i].EveryoneMask = (uint)attachment.Permissions.EveryoneMask; + attachmentsPacket.ObjectData[i].GroupMask = (uint)attachment.Permissions.GroupMask; + attachmentsPacket.ObjectData[i].ItemFlags = (uint)attachment.Flags; + attachmentsPacket.ObjectData[i].ItemID = attachment.UUID; + attachmentsPacket.ObjectData[i].Name = Utils.StringToBytes(attachment.Name); + attachmentsPacket.ObjectData[i].Description = Utils.StringToBytes(attachment.Description); + attachmentsPacket.ObjectData[i].NextOwnerMask = (uint)attachment.Permissions.NextOwnerMask; + attachmentsPacket.ObjectData[i].OwnerID = attachment.OwnerID; + } + else + { + Logger.Log("Cannot attach inventory item " + attachments[i].Name, Helpers.LogLevel.Warning, Client); + } + } + + Client.Network.SendPacket(attachmentsPacket); + } + + /// + /// Attach an item to our agent at a specific attach point + /// + /// A to attach + /// the on the avatar + /// to attach the item to + public void Attach(InventoryItem item, AttachmentPoint attachPoint) + { + Attach(item, attachPoint, true); + } + + /// + /// Attach an item to our agent at a specific attach point + /// + /// A to attach + /// the on the avatar + /// If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + /// to attach the item to + public void Attach(InventoryItem item, AttachmentPoint attachPoint, bool replace) + { + Attach(item.UUID, item.OwnerID, item.Name, item.Description, item.Permissions, item.Flags, + attachPoint, replace); + } + + /// + /// Attach an item to our agent specifying attachment details + /// + /// The of the item to attach + /// The attachments owner + /// The name of the attachment + /// The description of the attahment + /// The to apply when attached + /// The of the attachment + /// The on the agent + /// to attach the item to + public void Attach(UUID itemID, UUID ownerID, string name, string description, + Permissions perms, uint itemFlags, AttachmentPoint attachPoint) + { + Attach(itemID, ownerID, name, description, perms, itemFlags, attachPoint, true); + } + + /// + /// Attach an item to our agent specifying attachment details + /// + /// The of the item to attach + /// The attachments owner + /// The name of the attachment + /// The description of the attahment + /// The to apply when attached + /// The of the attachment + /// The on the agent + /// If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + /// to attach the item to + public void Attach(UUID itemID, UUID ownerID, string name, string description, + Permissions perms, uint itemFlags, AttachmentPoint attachPoint, bool replace) + { + // TODO: At some point it might be beneficial to have AppearanceManager track what we + // are currently wearing for attachments to make enumeration and detachment easier + RezSingleAttachmentFromInvPacket attach = new RezSingleAttachmentFromInvPacket(); + + attach.AgentData.AgentID = Client.Self.AgentID; + attach.AgentData.SessionID = Client.Self.SessionID; + + attach.ObjectData.AttachmentPt = replace ? (byte)attachPoint : (byte)(ATTACHMENT_ADD | (byte)attachPoint); + attach.ObjectData.Description = Utils.StringToBytes(description); + attach.ObjectData.EveryoneMask = (uint)perms.EveryoneMask; + attach.ObjectData.GroupMask = (uint)perms.GroupMask; + attach.ObjectData.ItemFlags = itemFlags; + attach.ObjectData.ItemID = itemID; + attach.ObjectData.Name = Utils.StringToBytes(name); + attach.ObjectData.NextOwnerMask = (uint)perms.NextOwnerMask; + attach.ObjectData.OwnerID = ownerID; + + Client.Network.SendPacket(attach); + } + + /// + /// Detach an item from our agent using an object + /// + /// An object + public void Detach(InventoryItem item) + { + Detach(item.UUID); + } + + /// + /// Detach an item from our agent + /// + /// The inventory itemID of the item to detach + public void Detach(UUID itemID) + { + DetachAttachmentIntoInvPacket detach = new DetachAttachmentIntoInvPacket(); + detach.ObjectData.AgentID = Client.Self.AgentID; + detach.ObjectData.ItemID = itemID; + + Client.Network.SendPacket(detach); + } + + #endregion Attachments + + #region Appearance Helpers + + /// + /// Inform the sim which wearables are part of our current outfit + /// + private void SendAgentIsNowWearing() + { + AgentIsNowWearingPacket wearing = new AgentIsNowWearingPacket(); + wearing.AgentData.AgentID = Client.Self.AgentID; + wearing.AgentData.SessionID = Client.Self.SessionID; + wearing.WearableData = new AgentIsNowWearingPacket.WearableDataBlock[WEARABLE_COUNT]; + + lock (Wearables) + { + for (int i = 0; i < WEARABLE_COUNT; i++) + { + WearableType type = (WearableType)i; + wearing.WearableData[i] = new AgentIsNowWearingPacket.WearableDataBlock(); + wearing.WearableData[i].WearableType = (byte)i; + + if (Wearables.ContainsKey(type)) + wearing.WearableData[i].ItemID = Wearables[type].ItemID; + else + wearing.WearableData[i].ItemID = UUID.Zero; + } + } + + Client.Network.SendPacket(wearing); + } + + /// + /// Replaces the Wearables collection with a list of new wearable items + /// + /// Wearable items to replace the Wearables collection with + private void ReplaceOutfit(List wearableItems) + { + Dictionary newWearables = new Dictionary(); + + lock (Wearables) + { + // Preserve body parts from the previous set of wearables. They may be overwritten, + // but cannot be missing in the new set + foreach (KeyValuePair entry in Wearables) + { + if (entry.Value.AssetType == AssetType.Bodypart) + newWearables[entry.Key] = entry.Value; + } + + // Add the given wearables to the new wearables collection + for (int i = 0; i < wearableItems.Count; i++) + { + InventoryWearable wearableItem = wearableItems[i]; + + WearableData wd = new WearableData(); + wd.AssetID = wearableItem.AssetUUID; + wd.AssetType = wearableItem.AssetType; + wd.ItemID = wearableItem.UUID; + wd.WearableType = wearableItem.WearableType; + + newWearables[wearableItem.WearableType] = wd; + } + + // Replace the Wearables collection + Wearables = newWearables; + } + } + + /// + /// Calculates base color/tint for a specific wearable + /// based on its params + /// + /// All the color info gathered from wearable's VisualParams + /// passed as list of ColorParamInfo tuples + /// Base color/tint for the wearable + public static Color4 GetColorFromParams(List param) + { + // Start off with a blank slate, black, fully transparent + Color4 res = new Color4(0, 0, 0, 0); + + // Apply color modification from each color parameter + foreach (ColorParamInfo p in param) + { + int n = p.VisualColorParam.Colors.Length; + + Color4 paramColor = new Color4(0, 0, 0, 0); + + if (n == 1) + { + // We got only one color in this param, use it for application + // to the final color + paramColor = p.VisualColorParam.Colors[0]; + } + else if (n > 1) + { + // We have an array of colors in this parameter + // First, we need to find out, based on param value + // between which two elements of the array our value lands + + // Size of the step using which we iterate from Min to Max + float step = (p.VisualParam.MaxValue - p.VisualParam.MinValue) / ((float)n - 1); + + // Our color should land inbetween colors in the array with index a and b + int indexa = 0; + int indexb = 0; + + int i = 0; + + for (float a = p.VisualParam.MinValue; a <= p.VisualParam.MaxValue; a += step) + { + if (a <= p.Value) + { + indexa = i; + } + else + { + break; + } + + i++; + } + + // Sanity check that we don't go outside bounds of the array + if (indexa > n - 1) + indexa = n - 1; + + indexb = (indexa == n - 1) ? indexa : indexa + 1; + + // How far is our value from Index A on the + // line from Index A to Index B + float distance = p.Value - (float)indexa * step; + + // We are at Index A (allowing for some floating point math fuzz), + // use the color on that index + if (distance < 0.00001f || indexa == indexb) + { + paramColor = p.VisualColorParam.Colors[indexa]; + } + else + { + // Not so simple as being precisely on the index eh? No problem. + // We take the two colors that our param value places us between + // and then find the value for each ARGB element that is + // somewhere on the line between color1 and color2 at some + // distance from the first color + Color4 c1 = paramColor = p.VisualColorParam.Colors[indexa]; + Color4 c2 = paramColor = p.VisualColorParam.Colors[indexb]; + + // Distance is some fraction of the step, use that fraction + // to find the value in the range from color1 to color2 + paramColor = Color4.Lerp(c1, c2, distance / step); + } + + // Please leave this fragment even if its commented out + // might prove useful should ($deity forbid) there be bugs in this code + //string carray = ""; + //foreach (Color c in p.VisualColorParam.Colors) + //{ + // carray += c.ToString() + " - "; + //} + //Logger.DebugLog("Calculating color for " + p.WearableType + " from " + p.VisualParam.Name + ", value is " + p.Value + " in range " + p.VisualParam.MinValue + " - " + p.VisualParam.MaxValue + " step " + step + " with " + n + " elements " + carray + " A: " + indexa + " B: " + indexb + " at distance " + distance); + } + + // Now that we have calculated color from the scale of colors + // that visual params provided, lets apply it to the result + switch (p.VisualColorParam.Operation) + { + case VisualColorOperation.Add: + res += paramColor; + break; + case VisualColorOperation.Multiply: + res *= paramColor; + break; + case VisualColorOperation.Blend: + res = Color4.Lerp(res, paramColor, p.Value); + break; + } + } + + return res; + } + + /// + /// Blocking method to populate the Wearables dictionary + /// + /// True on success, otherwise false + bool GetAgentWearables() + { + AutoResetEvent wearablesEvent = new AutoResetEvent(false); + EventHandler wearablesCallback = ((s, e) => wearablesEvent.Set()); + + AgentWearablesReply += wearablesCallback; + + RequestAgentWearables(); + + bool success = wearablesEvent.WaitOne(WEARABLE_TIMEOUT, false); + + AgentWearablesReply -= wearablesCallback; + + return success; + } + + /// + /// Blocking method to populate the Textures array with cached bakes + /// + /// True on success, otherwise false + bool GetCachedBakes() + { + AutoResetEvent cacheCheckEvent = new AutoResetEvent(false); + EventHandler cacheCallback = (sender, e) => cacheCheckEvent.Set(); + + CachedBakesReply += cacheCallback; + + RequestCachedBakes(); + + bool success = cacheCheckEvent.WaitOne(WEARABLE_TIMEOUT, false); + + CachedBakesReply -= cacheCallback; + + return success; + } + + /// + /// Populates textures and visual params from a decoded asset + /// + /// Wearable to decode + /// + /// Populates textures and visual params from a decoded asset + /// + /// Wearable to decode + public static void DecodeWearableParams(WearableData wearable, ref TextureData[] textures) + { + Dictionary alphaMasks = new Dictionary(); + List colorParams = new List(); + + // Populate collection of alpha masks from visual params + // also add color tinting information + foreach (KeyValuePair kvp in wearable.Asset.Params) + { + if (!VisualParams.Params.ContainsKey(kvp.Key)) continue; + + VisualParam p = VisualParams.Params[kvp.Key]; + + ColorParamInfo colorInfo = new ColorParamInfo(); + colorInfo.WearableType = wearable.WearableType; + colorInfo.VisualParam = p; + colorInfo.Value = kvp.Value; + + // Color params + if (p.ColorParams.HasValue) + { + colorInfo.VisualColorParam = p.ColorParams.Value; + + if (wearable.WearableType == WearableType.Tattoo) + { + if (kvp.Key == 1062 || kvp.Key == 1063 || kvp.Key == 1064) + { + colorParams.Add(colorInfo); + } + } + else if (wearable.WearableType == WearableType.Jacket) + { + if (kvp.Key == 809 || kvp.Key == 810 || kvp.Key == 811) + { + colorParams.Add(colorInfo); + } + } + else if (wearable.WearableType == WearableType.Hair) + { + // Param 112 - Rainbow + // Param 113 - Red + // Param 114 - Blonde + // Param 115 - White + if (kvp.Key == 112 || kvp.Key == 113 || kvp.Key == 114 || kvp.Key == 115) + { + colorParams.Add(colorInfo); + } + } + else if (wearable.WearableType == WearableType.Skin) + { + // For skin we skip makeup params for now and use only the 3 + // that are used to determine base skin tone + // Param 108 - Rainbow Color + // Param 110 - Red Skin (Ruddiness) + // Param 111 - Pigment + if (kvp.Key == 108 || kvp.Key == 110 || kvp.Key == 111) + { + colorParams.Add(colorInfo); + } + } + else + { + colorParams.Add(colorInfo); + } + } + + // Add alpha mask + if (p.AlphaParams.HasValue && p.AlphaParams.Value.TGAFile != string.Empty && !p.IsBumpAttribute && !alphaMasks.ContainsKey(p.AlphaParams.Value)) + { + alphaMasks.Add(p.AlphaParams.Value, kvp.Value == 0 ? 0.01f : kvp.Value); + } + + // Alhpa masks can also be specified in sub "driver" params + if (p.Drivers != null) + { + for (int i = 0; i < p.Drivers.Length; i++) + { + if (VisualParams.Params.ContainsKey(p.Drivers[i])) + { + VisualParam driver = VisualParams.Params[p.Drivers[i]]; + if (driver.AlphaParams.HasValue && driver.AlphaParams.Value.TGAFile != string.Empty && !driver.IsBumpAttribute && !alphaMasks.ContainsKey(driver.AlphaParams.Value)) + { + alphaMasks.Add(driver.AlphaParams.Value, kvp.Value == 0 ? 0.01f : kvp.Value); + } + } + } + } + } + + Color4 wearableColor = Color4.White; // Never actually used + if (colorParams.Count > 0) + { + wearableColor = GetColorFromParams(colorParams); + Logger.DebugLog("Setting tint " + wearableColor + " for " + wearable.WearableType); + } + + // Loop through all of the texture IDs in this decoded asset and put them in our cache of worn textures + foreach (KeyValuePair entry in wearable.Asset.Textures) + { + int i = (int)entry.Key; + + // Update information about color and alpha masks for this texture + textures[i].AlphaMasks = alphaMasks; + textures[i].Color = wearableColor; + + // If this texture changed, update the TextureID and clear out the old cached texture asset + if (textures[i].TextureID != entry.Value) + { + // Treat DEFAULT_AVATAR_TEXTURE as null + if (entry.Value != AppearanceManager.DEFAULT_AVATAR_TEXTURE) + textures[i].TextureID = entry.Value; + else + textures[i].TextureID = UUID.Zero; + + textures[i].Texture = null; + } + } + } + + /// + /// Blocking method to download and parse currently worn wearable assets + /// + /// True on success, otherwise false + private bool DownloadWearables() + { + bool success = true; + + // Make a copy of the wearables dictionary to enumerate over + Dictionary wearables; + lock (Wearables) + wearables = new Dictionary(Wearables); + + // We will refresh the textures (zero out all non bake textures) + for (int i = 0; i < Textures.Length; i++) + { + bool isBake = false; + for (int j = 0; j < BakeIndexToTextureIndex.Length; j++) + { + if (BakeIndexToTextureIndex[j] == i) + { + isBake = true; + break; + } + } + if (!isBake) + Textures[i] = new TextureData(); + } + + int pendingWearables = wearables.Count; + foreach (WearableData wearable in wearables.Values) + { + if (wearable.Asset != null) + { + DecodeWearableParams(wearable, ref Textures); + --pendingWearables; + } + } + + if (pendingWearables == 0) + return true; + + Logger.DebugLog("Downloading " + pendingWearables + " wearable assets"); + + Parallel.ForEach(Math.Min(pendingWearables, MAX_CONCURRENT_DOWNLOADS), wearables.Values, + delegate(WearableData wearable) + { + if (wearable.Asset == null) + { + AutoResetEvent downloadEvent = new AutoResetEvent(false); + + // Fetch this wearable asset + Client.Assets.RequestAsset(wearable.AssetID, wearable.AssetType, true, + delegate(AssetDownload transfer, Asset asset) + { + if (transfer.Success && asset is AssetWearable) + { + // Update this wearable with the freshly downloaded asset + wearable.Asset = (AssetWearable)asset; + + if (wearable.Asset.Decode()) + { + DecodeWearableParams(wearable, ref Textures); + Logger.DebugLog("Downloaded wearable asset " + wearable.WearableType + " with " + wearable.Asset.Params.Count + + " visual params and " + wearable.Asset.Textures.Count + " textures", Client); + + } + else + { + wearable.Asset = null; + Logger.Log("Failed to decode asset:" + Environment.NewLine + + Utils.BytesToString(asset.AssetData), Helpers.LogLevel.Error, Client); + } + } + else + { + Logger.Log("Wearable " + wearable.AssetID + "(" + wearable.WearableType + ") failed to download, " + + transfer.Status, Helpers.LogLevel.Warning, Client); + } + + downloadEvent.Set(); + } + ); + + if (!downloadEvent.WaitOne(WEARABLE_TIMEOUT, false)) + { + Logger.Log("Timed out downloading wearable asset " + wearable.AssetID + " (" + wearable.WearableType + ")", + Helpers.LogLevel.Error, Client); + success = false; + } + + --pendingWearables; + } + } + ); + + return success; + } + + /// + /// Get a list of all of the textures that need to be downloaded for a + /// single bake layer + /// + /// Bake layer to get texture AssetIDs for + /// A list of texture AssetIDs to download + private List GetTextureDownloadList(BakeType bakeType) + { + List indices = BakeTypeToTextures(bakeType); + List textures = new List(); + + for (int i = 0; i < indices.Count; i++) + { + AvatarTextureIndex index = indices[i]; + + if (index == AvatarTextureIndex.Skirt && !Wearables.ContainsKey(WearableType.Skirt)) + continue; + + AddTextureDownload(index, textures); + } + + return textures; + } + + /// + /// Helper method to lookup the TextureID for a single layer and add it + /// to a list if it is not already present + /// + /// + /// + private void AddTextureDownload(AvatarTextureIndex index, List textures) + { + TextureData textureData = Textures[(int)index]; + // Add the textureID to the list if this layer has a valid textureID set, it has not already + // been downloaded, and it is not already in the download list + if (textureData.TextureID != UUID.Zero && textureData.Texture == null && !textures.Contains(textureData.TextureID)) + textures.Add(textureData.TextureID); + } + + /// + /// Blocking method to download all of the textures needed for baking + /// the given bake layers + /// + /// A list of layers that need baking + /// No return value is given because the baking will happen + /// whether or not all textures are successfully downloaded + private void DownloadTextures(List bakeLayers) + { + List textureIDs = new List(); + + for (int i = 0; i < bakeLayers.Count; i++) + { + List layerTextureIDs = GetTextureDownloadList(bakeLayers[i]); + + for (int j = 0; j < layerTextureIDs.Count; j++) + { + UUID uuid = layerTextureIDs[j]; + if (!textureIDs.Contains(uuid)) + textureIDs.Add(uuid); + } + } + + Logger.DebugLog("Downloading " + textureIDs.Count + " textures for baking"); + + Parallel.ForEach(MAX_CONCURRENT_DOWNLOADS, textureIDs, + delegate(UUID textureID) + { + try + { + AutoResetEvent downloadEvent = new AutoResetEvent(false); + + Client.Assets.RequestImage(textureID, + delegate(TextureRequestState state, AssetTexture assetTexture) + { + if (state == TextureRequestState.Finished) + { + assetTexture.Decode(); + + for (int i = 0; i < Textures.Length; i++) + { + if (Textures[i].TextureID == textureID) + Textures[i].Texture = assetTexture; + } + } + else + { + Logger.Log("Texture " + textureID + " failed to download, one or more bakes will be incomplete", + Helpers.LogLevel.Warning); + } + + downloadEvent.Set(); + } + ); + + downloadEvent.WaitOne(TEXTURE_TIMEOUT, false); + } + catch (Exception e) + { + Logger.Log( + string.Format("Download of texture {0} failed with exception {1}", textureID, e), + Helpers.LogLevel.Warning, Client); + } + } + ); + } + + /// + /// Blocking method to create and upload baked textures for all of the + /// missing bakes + /// + /// True on success, otherwise false + private bool CreateBakes() + { + bool success = true; + List pendingBakes = new List(); + + // Check each bake layer in the Textures array for missing bakes + for (int bakedIndex = 0; bakedIndex < BAKED_TEXTURE_COUNT; bakedIndex++) + { + AvatarTextureIndex textureIndex = BakeTypeToAgentTextureIndex((BakeType)bakedIndex); + + if (Textures[(int)textureIndex].TextureID == UUID.Zero) + { + // If this is the skirt layer and we're not wearing a skirt then skip it + if (bakedIndex == (int)BakeType.Skirt && !Wearables.ContainsKey(WearableType.Skirt)) + continue; + + pendingBakes.Add((BakeType)bakedIndex); + } + } + + if (pendingBakes.Count > 0) + { + DownloadTextures(pendingBakes); + + Parallel.ForEach(Math.Min(MAX_CONCURRENT_UPLOADS, pendingBakes.Count), pendingBakes, + delegate(BakeType bakeType) + { + if (!CreateBake(bakeType)) + success = false; + } + ); + } + + // Free up all the textures we're holding on to + for (int i = 0; i < Textures.Length; i++) + { + Textures[i].Texture = null; + } + + // We just allocated and freed a ridiculous amount of memory while + // baking. Signal to the GC to clean up + GC.Collect(); + + return success; + } + + /// + /// Blocking method to create and upload a baked texture for a single + /// bake layer + /// + /// Layer to bake + /// True on success, otherwise false + private bool CreateBake(BakeType bakeType) + { + List textureIndices = BakeTypeToTextures(bakeType); + Baker oven = new Baker(bakeType); + + for (int i = 0; i < textureIndices.Count; i++) + { + AvatarTextureIndex textureIndex = textureIndices[i]; + TextureData texture = Textures[(int)textureIndex]; + texture.TextureIndex = textureIndex; + + oven.AddTexture(texture); + } + + int start = Environment.TickCount; + oven.Bake(); + Logger.DebugLog("Baking " + bakeType + " took " + (Environment.TickCount - start) + "ms"); + + UUID newAssetID = UUID.Zero; + int retries = UPLOAD_RETRIES; + + while (newAssetID == UUID.Zero && retries > 0) + { + newAssetID = UploadBake(oven.BakedTexture.AssetData); + --retries; + } + + Textures[(int)BakeTypeToAgentTextureIndex(bakeType)].TextureID = newAssetID; + + if (newAssetID == UUID.Zero) + { + Logger.Log("Failed uploading bake " + bakeType, Helpers.LogLevel.Warning); + return false; + } + + return true; + } + + /// + /// Blocking method to upload a baked texture + /// + /// Five channel JPEG2000 texture data to upload + /// UUID of the newly created asset on success, otherwise UUID.Zero + private UUID UploadBake(byte[] textureData) + { + UUID bakeID = UUID.Zero; + AutoResetEvent uploadEvent = new AutoResetEvent(false); + + Client.Assets.RequestUploadBakedTexture(textureData, + delegate(UUID newAssetID) + { + bakeID = newAssetID; + uploadEvent.Set(); + } + ); + + // FIXME: evalute the need for timeout here, RequestUploadBakedTexture() will + // timout either on Client.Settings.TRANSFER_TIMEOUT or Client.Settings.CAPS_TIMEOUT + // depending on which upload method is used. + uploadEvent.WaitOne(UPLOAD_TIMEOUT, false); + + return bakeID; + } + + /// + /// Creates a dictionary of visual param values from the downloaded wearables + /// + /// A dictionary of visual param indices mapping to visual param + /// values for our agent that can be fed to the Baker class + private Dictionary MakeParamValues() + { + Dictionary paramValues = new Dictionary(VisualParams.Params.Count); + + lock (Wearables) + { + foreach (KeyValuePair kvp in VisualParams.Params) + { + // Only Group-0 parameters are sent in AgentSetAppearance packets + if (kvp.Value.Group == 0) + { + bool found = false; + VisualParam vp = kvp.Value; + + // Try and find this value in our collection of downloaded wearables + foreach (WearableData data in Wearables.Values) + { + float paramValue; + if (data.Asset != null && data.Asset.Params.TryGetValue(vp.ParamID, out paramValue)) + { + paramValues.Add(vp.ParamID, paramValue); + found = true; + break; + } + } + + // Use a default value if we don't have one set for it + if (!found) paramValues.Add(vp.ParamID, vp.DefaultValue); + } + } + } + + return paramValues; + } + + /// + /// Initate server baking process + /// + /// True if the server baking was successful + private bool UpdateAvatarAppearance() + { + Caps caps = Client.Network.CurrentSim.Caps; + if (caps == null) + { + return false; + } + + Uri url = caps.CapabilityURI("UpdateAvatarAppearance"); + if (url == null) + { + return false; + } + + InventoryFolder COF = GetCOF(); + if (COF == null) + { + return false; + } + else + { + // TODO: create Current Outfit Folder + } + + CapsClient capsRequest = new CapsClient(url); + OSDMap request = new OSDMap(1); + request["cof_version"] = COF.Version; + + string msg = "Setting server side baking failed"; + + OSD res = capsRequest.GetResponse(request, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT * 2); + + if (res != null && res is OSDMap) + { + OSDMap result = (OSDMap)res; + if (result["success"]) + { + Logger.Log("Successfully set appearance", Helpers.LogLevel.Info, Client); + // TODO: Set local visual params and baked textures based on the result here + return true; + } + else + { + if (result.ContainsKey("error")) + { + msg += ": " + result["error"].AsString(); + } + } + } + + Logger.Log(msg, Helpers.LogLevel.Error, Client); + + return false; + } + + /// + /// Get the latest version of COF + /// + /// Current Outfit Folder (or null if getting the data failed) + private InventoryFolder GetCOF() + { + List root = null; + AutoResetEvent folderReceived = new AutoResetEvent(false); + + EventHandler callback = (sender, e) => + { + if (e.FolderID == Client.Inventory.Store.RootFolder.UUID) + { + if (e.Success) + { + root = Client.Inventory.Store.GetContents(Client.Inventory.Store.RootFolder.UUID); + } + folderReceived.Set(); + } + }; + + Client.Inventory.FolderUpdated += callback; + Client.Inventory.RequestFolderContentsCap(Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate); + folderReceived.WaitOne(Client.Settings.CAPS_TIMEOUT); + Client.Inventory.FolderUpdated -= callback; + + InventoryFolder COF = null; + + // COF should be in the root folder. Request update to get the latest versio number + if (root != null) + { + foreach (InventoryBase baseItem in root) + { + if (baseItem is InventoryFolder && ((InventoryFolder)baseItem).PreferredType == AssetType.CurrentOutfitFolder) + { + COF = (InventoryFolder)baseItem; + break; + } + } + } + + return COF; + } + + /// + /// Create an AgentSetAppearance packet from Wearables data and the + /// Textures array and send it + /// + private void RequestAgentSetAppearance() + { + AgentSetAppearancePacket set = MakeAppearancePacket(); + Client.Network.SendPacket(set); + Logger.DebugLog("Send AgentSetAppearance packet"); + } + + public AgentSetAppearancePacket MakeAppearancePacket() + { + AgentSetAppearancePacket set = new AgentSetAppearancePacket(); + set.AgentData.AgentID = Client.Self.AgentID; + set.AgentData.SessionID = Client.Self.SessionID; + set.AgentData.SerialNum = (uint)Interlocked.Increment(ref SetAppearanceSerialNum); + + // Visual params used in the agent height calculation + float agentSizeVPHeight = 0.0f; + float agentSizeVPHeelHeight = 0.0f; + float agentSizeVPPlatformHeight = 0.0f; + float agentSizeVPHeadSize = 0.5f; + float agentSizeVPLegLength = 0.0f; + float agentSizeVPNeckLength = 0.0f; + float agentSizeVPHipLength = 0.0f; + + lock (Wearables) + { + #region VisualParam + + int vpIndex = 0; + int nrParams; + bool wearingPhysics = false; + + foreach (WearableData wearable in Wearables.Values) + { + if (wearable.WearableType == WearableType.Physics) + { + wearingPhysics = true; + break; + } + } + + if (wearingPhysics) + { + nrParams = 251; + } + else + { + nrParams = 218; + } + + set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[nrParams]; + + foreach (KeyValuePair kvp in VisualParams.Params) + { + VisualParam vp = kvp.Value; + float paramValue = 0f; + bool found = false; + + // Try and find this value in our collection of downloaded wearables + foreach (WearableData data in Wearables.Values) + { + if (data.Asset != null && data.Asset.Params.TryGetValue(vp.ParamID, out paramValue)) + { + found = true; + break; + } + } + + // Use a default value if we don't have one set for it + if (!found) + paramValue = vp.DefaultValue; + + // Only Group-0 parameters are sent in AgentSetAppearance packets + if (kvp.Value.Group == 0) + { + set.VisualParam[vpIndex] = new AgentSetAppearancePacket.VisualParamBlock(); + set.VisualParam[vpIndex].ParamValue = Utils.FloatToByte(paramValue, vp.MinValue, vp.MaxValue); + ++vpIndex; + } + + // Check if this is one of the visual params used in the agent height calculation + switch (vp.ParamID) + { + case 33: + agentSizeVPHeight = paramValue; + break; + case 198: + agentSizeVPHeelHeight = paramValue; + break; + case 503: + agentSizeVPPlatformHeight = paramValue; + break; + case 682: + agentSizeVPHeadSize = paramValue; + break; + case 692: + agentSizeVPLegLength = paramValue; + break; + case 756: + agentSizeVPNeckLength = paramValue; + break; + case 842: + agentSizeVPHipLength = paramValue; + break; + } + + if (vpIndex == nrParams) break; + } + + MyVisualParameters = new byte[set.VisualParam.Length]; + for (int i = 0; i < set.VisualParam.Length; i++) + { + MyVisualParameters[i] = set.VisualParam[i].ParamValue; + } + + #endregion VisualParam + + #region TextureEntry + + Primitive.TextureEntry te = new Primitive.TextureEntry(DEFAULT_AVATAR_TEXTURE); + + for (uint i = 0; i < Textures.Length; i++) + { + if ((i == 0 || i == 5 || i == 6) && Client.Settings.CLIENT_IDENTIFICATION_TAG != UUID.Zero) + { + Primitive.TextureEntryFace face = te.CreateFace(i); + face.TextureID = Client.Settings.CLIENT_IDENTIFICATION_TAG; + Logger.DebugLog("Sending client identification tag: " + Client.Settings.CLIENT_IDENTIFICATION_TAG, Client); + } + else if (Textures[i].TextureID != UUID.Zero) + { + Primitive.TextureEntryFace face = te.CreateFace(i); + face.TextureID = Textures[i].TextureID; + Logger.DebugLog("Sending texture entry for " + (AvatarTextureIndex)i + " to " + Textures[i].TextureID, Client); + } + } + + set.ObjectData.TextureEntry = te.GetBytes(); + MyTextures = te; + + #endregion TextureEntry + + #region WearableData + + set.WearableData = new AgentSetAppearancePacket.WearableDataBlock[BAKED_TEXTURE_COUNT]; + + // Build hashes for each of the bake layers from the individual components + for (int bakedIndex = 0; bakedIndex < BAKED_TEXTURE_COUNT; bakedIndex++) + { + UUID hash = UUID.Zero; + + for (int wearableIndex = 0; wearableIndex < WEARABLES_PER_LAYER; wearableIndex++) + { + WearableType type = WEARABLE_BAKE_MAP[bakedIndex][wearableIndex]; + + WearableData wearable; + if (type != WearableType.Invalid && Wearables.TryGetValue(type, out wearable)) + hash ^= wearable.AssetID; + } + + if (hash != UUID.Zero) + { + // Hash with our magic value for this baked layer + hash ^= BAKED_TEXTURE_HASH[bakedIndex]; + } + + // Tell the server what cached texture assetID to use for each bake layer + set.WearableData[bakedIndex] = new AgentSetAppearancePacket.WearableDataBlock(); + set.WearableData[bakedIndex].TextureIndex = BakeIndexToTextureIndex[bakedIndex]; + set.WearableData[bakedIndex].CacheID = hash; + Logger.DebugLog("Sending TextureIndex " + (BakeType)bakedIndex + " with CacheID " + hash, Client); + } + + #endregion WearableData + + #region Agent Size + + // Takes into account the Shoe Heel/Platform offsets but not the HeadSize offset. Seems to work. + double agentSizeBase = 1.706; + + // The calculation for the HeadSize scalar may be incorrect, but it seems to work + double agentHeight = agentSizeBase + (agentSizeVPLegLength * .1918) + (agentSizeVPHipLength * .0375) + + (agentSizeVPHeight * .12022) + (agentSizeVPHeadSize * .01117) + (agentSizeVPNeckLength * .038) + + (agentSizeVPHeelHeight * .08) + (agentSizeVPPlatformHeight * .07); + + set.AgentData.Size = new Vector3(0.45f, 0.6f, (float)agentHeight); + + #endregion Agent Size + + if (Client.Settings.AVATAR_TRACKING) + { + Avatar me; + if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.LocalID, out me)) + { + me.Textures = MyTextures; + me.VisualParameters = MyVisualParameters; + } + } + } + return set; + } + + private void DelayedRequestSetAppearance() + { + if (RebakeScheduleTimer == null) + { + RebakeScheduleTimer = new Timer(RebakeScheduleTimerTick); + } + try { RebakeScheduleTimer.Change(REBAKE_DELAY, Timeout.Infinite); } + catch { } + } + + private void RebakeScheduleTimerTick(Object state) + { + RequestSetAppearance(true); + } + #endregion Appearance Helpers + + #region Inventory Helpers + + private bool GetFolderWearables(string[] folderPath, out List wearables, out List attachments) + { + UUID folder = Client.Inventory.FindObjectByPath( + Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID, String.Join("/", folderPath), INVENTORY_TIMEOUT); + + if (folder != UUID.Zero) + { + return GetFolderWearables(folder, out wearables, out attachments); + } + else + { + Logger.Log("Failed to resolve outfit folder path " + folderPath, Helpers.LogLevel.Error, Client); + wearables = null; + attachments = null; + return false; + } + } + + private bool GetFolderWearables(UUID folder, out List wearables, out List attachments) + { + wearables = new List(); + attachments = new List(); + List objects = Client.Inventory.FolderContents(folder, Client.Self.AgentID, false, true, + InventorySortOrder.ByName, INVENTORY_TIMEOUT); + + if (objects != null) + { + foreach (InventoryBase ib in objects) + { + if (ib is InventoryWearable) + { + Logger.DebugLog("Adding wearable " + ib.Name, Client); + wearables.Add((InventoryWearable)ib); + } + else if (ib is InventoryAttachment) + { + Logger.DebugLog("Adding attachment (attachment) " + ib.Name, Client); + attachments.Add((InventoryItem)ib); + } + else if (ib is InventoryObject) + { + Logger.DebugLog("Adding attachment (object) " + ib.Name, Client); + attachments.Add((InventoryItem)ib); + } + else + { + Logger.DebugLog("Ignoring inventory item " + ib.Name, Client); + } + } + } + else + { + Logger.Log("Failed to download folder contents of + " + folder, Helpers.LogLevel.Error, Client); + return false; + } + + return true; + } + + #endregion Inventory Helpers + + #region Callbacks + + protected void AgentWearablesUpdateHandler(object sender, PacketReceivedEventArgs e) + { + bool changed = false; + AgentWearablesUpdatePacket update = (AgentWearablesUpdatePacket)e.Packet; + + lock (Wearables) + { + #region Test if anything changed in this update + + for (int i = 0; i < update.WearableData.Length; i++) + { + AgentWearablesUpdatePacket.WearableDataBlock block = update.WearableData[i]; + + if (block.AssetID != UUID.Zero) + { + WearableData wearable; + if (Wearables.TryGetValue((WearableType)block.WearableType, out wearable)) + { + if (wearable.AssetID != block.AssetID || wearable.ItemID != block.ItemID) + { + // A different wearable is now set for this index + changed = true; + break; + } + } + else + { + // A wearable is now set for this index + changed = true; + break; + } + } + else if (Wearables.ContainsKey((WearableType)block.WearableType)) + { + // This index is now empty + changed = true; + break; + } + } + + #endregion Test if anything changed in this update + + if (changed) + { + Logger.DebugLog("New wearables received in AgentWearablesUpdate"); + Wearables.Clear(); + + for (int i = 0; i < update.WearableData.Length; i++) + { + AgentWearablesUpdatePacket.WearableDataBlock block = update.WearableData[i]; + + if (block.AssetID != UUID.Zero) + { + WearableType type = (WearableType)block.WearableType; + + WearableData data = new WearableData(); + data.Asset = null; + data.AssetID = block.AssetID; + data.AssetType = WearableTypeToAssetType(type); + data.ItemID = block.ItemID; + data.WearableType = type; + + // Add this wearable to our collection + Wearables[type] = data; + } + } + } + else + { + Logger.DebugLog("Duplicate AgentWearablesUpdate received, discarding"); + } + } + + if (changed) + { + // Fire the callback + OnAgentWearables(new AgentWearablesReplyEventArgs()); + } + } + + protected void RebakeAvatarTexturesHandler(object sender, PacketReceivedEventArgs e) + { + RebakeAvatarTexturesPacket rebake = (RebakeAvatarTexturesPacket)e.Packet; + + // allow the library to do the rebake + if (Client.Settings.SEND_AGENT_APPEARANCE) + { + RequestSetAppearance(true); + } + + OnRebakeAvatar(new RebakeAvatarTexturesEventArgs(rebake.TextureData.TextureID)); + } + + protected void AgentCachedTextureResponseHandler(object sender, PacketReceivedEventArgs e) + { + AgentCachedTextureResponsePacket response = (AgentCachedTextureResponsePacket)e.Packet; + + for (int i = 0; i < response.WearableData.Length; i++) + { + AgentCachedTextureResponsePacket.WearableDataBlock block = response.WearableData[i]; + BakeType bakeType = (BakeType)block.TextureIndex; + AvatarTextureIndex index = BakeTypeToAgentTextureIndex(bakeType); + + Logger.DebugLog("Cache response for " + bakeType + ", TextureID=" + block.TextureID, Client); + + if (block.TextureID != UUID.Zero) + { + // A simulator has a cache of this bake layer + + // FIXME: Use this. Right now we don't bother to check if this is a foreign host + string host = Utils.BytesToString(block.HostName); + + Textures[(int)index].TextureID = block.TextureID; + } + else + { + // The server does not have a cache of this bake layer + // FIXME: + } + } + + OnAgentCachedBakes(new AgentCachedBakesReplyEventArgs()); + } + + private void Network_OnEventQueueRunning(object sender, EventQueueRunningEventArgs e) + { + if (e.Simulator == Client.Network.CurrentSim && Client.Settings.SEND_AGENT_APPEARANCE) + { + // Update appearance each time we enter a new sim and capabilities have been retrieved + Client.Appearance.RequestSetAppearance(); + } + } + + private void Network_OnDisconnected(object sender, DisconnectedEventArgs e) + { + if (RebakeScheduleTimer != null) + { + RebakeScheduleTimer.Dispose(); + RebakeScheduleTimer = null; + } + + if (AppearanceThread != null) + { + if (AppearanceThread.IsAlive) + { + AppearanceThread.Abort(); + } + AppearanceThread = null; + AppearanceThreadRunning = 0; + } + } + + #endregion Callbacks + + #region Static Helpers + + /// + /// Converts a WearableType to a bodypart or clothing WearableType + /// + /// A WearableType + /// AssetType.Bodypart or AssetType.Clothing or AssetType.Unknown + public static AssetType WearableTypeToAssetType(WearableType type) + { + switch (type) + { + case WearableType.Shape: + case WearableType.Skin: + case WearableType.Hair: + case WearableType.Eyes: + return AssetType.Bodypart; + case WearableType.Shirt: + case WearableType.Pants: + case WearableType.Shoes: + case WearableType.Socks: + case WearableType.Jacket: + case WearableType.Gloves: + case WearableType.Undershirt: + case WearableType.Underpants: + case WearableType.Skirt: + case WearableType.Tattoo: + case WearableType.Alpha: + case WearableType.Physics: + return AssetType.Clothing; + default: + return AssetType.Unknown; + } + } + + /// + /// Converts a BakeType to the corresponding baked texture slot in AvatarTextureIndex + /// + /// A BakeType + /// The AvatarTextureIndex slot that holds the given BakeType + public static AvatarTextureIndex BakeTypeToAgentTextureIndex(BakeType index) + { + switch (index) + { + case BakeType.Head: + return AvatarTextureIndex.HeadBaked; + case BakeType.UpperBody: + return AvatarTextureIndex.UpperBaked; + case BakeType.LowerBody: + return AvatarTextureIndex.LowerBaked; + case BakeType.Eyes: + return AvatarTextureIndex.EyesBaked; + case BakeType.Skirt: + return AvatarTextureIndex.SkirtBaked; + case BakeType.Hair: + return AvatarTextureIndex.HairBaked; + default: + return AvatarTextureIndex.Unknown; + } + } + + /// + /// Gives the layer number that is used for morph mask + /// + /// >A BakeType + /// Which layer number as defined in BakeTypeToTextures is used for morph mask + public static AvatarTextureIndex MorphLayerForBakeType(BakeType bakeType) + { + // Indexes return here correspond to those returned + // in BakeTypeToTextures(), those two need to be in sync. + // Which wearable layer is used for morph is defined in avatar_lad.xml + // by looking for that has defined in it, and + // looking up which wearable is defined in that layer. Morph mask + // is never combined, it's always a straight copy of one single clothing + // item's alpha channel per bake. + switch (bakeType) + { + case BakeType.Head: + return AvatarTextureIndex.Hair; // hair + case BakeType.UpperBody: + return AvatarTextureIndex.UpperShirt; // shirt + case BakeType.LowerBody: + return AvatarTextureIndex.LowerPants; // lower pants + case BakeType.Skirt: + return AvatarTextureIndex.Skirt; // skirt + case BakeType.Hair: + return AvatarTextureIndex.Hair; // hair + default: + return AvatarTextureIndex.Unknown; + } + } + + /// + /// Converts a BakeType to a list of the texture slots that make up that bake + /// + /// A BakeType + /// A list of texture slots that are inputs for the given bake + public static List BakeTypeToTextures(BakeType bakeType) + { + List textures = new List(); + + switch (bakeType) + { + case BakeType.Head: + textures.Add(AvatarTextureIndex.HeadBodypaint); + textures.Add(AvatarTextureIndex.HeadTattoo); + textures.Add(AvatarTextureIndex.Hair); + textures.Add(AvatarTextureIndex.HeadAlpha); + break; + case BakeType.UpperBody: + textures.Add(AvatarTextureIndex.UpperBodypaint); + textures.Add(AvatarTextureIndex.UpperTattoo); + textures.Add(AvatarTextureIndex.UpperGloves); + textures.Add(AvatarTextureIndex.UpperUndershirt); + textures.Add(AvatarTextureIndex.UpperShirt); + textures.Add(AvatarTextureIndex.UpperJacket); + textures.Add(AvatarTextureIndex.UpperAlpha); + break; + case BakeType.LowerBody: + textures.Add(AvatarTextureIndex.LowerBodypaint); + textures.Add(AvatarTextureIndex.LowerTattoo); + textures.Add(AvatarTextureIndex.LowerUnderpants); + textures.Add(AvatarTextureIndex.LowerSocks); + textures.Add(AvatarTextureIndex.LowerShoes); + textures.Add(AvatarTextureIndex.LowerPants); + textures.Add(AvatarTextureIndex.LowerJacket); + textures.Add(AvatarTextureIndex.LowerAlpha); + break; + case BakeType.Eyes: + textures.Add(AvatarTextureIndex.EyesIris); + textures.Add(AvatarTextureIndex.EyesAlpha); + break; + case BakeType.Skirt: + textures.Add(AvatarTextureIndex.Skirt); + break; + case BakeType.Hair: + textures.Add(AvatarTextureIndex.Hair); + textures.Add(AvatarTextureIndex.HairAlpha); + break; + } + + return textures; + } + + #endregion Static Helpers + } + + #region AppearanceManager EventArgs Classes + + /// Contains the Event data returned from the data server from an AgentWearablesRequest + public class AgentWearablesReplyEventArgs : EventArgs + { + /// Construct a new instance of the AgentWearablesReplyEventArgs class + public AgentWearablesReplyEventArgs() + { + } + } + + /// Contains the Event data returned from the data server from an AgentCachedTextureResponse + public class AgentCachedBakesReplyEventArgs : EventArgs + { + /// Construct a new instance of the AgentCachedBakesReplyEventArgs class + public AgentCachedBakesReplyEventArgs() + { + } + } + + /// Contains the Event data returned from an AppearanceSetRequest + public class AppearanceSetEventArgs : EventArgs + { + private readonly bool m_success; + + /// Indicates whether appearance setting was successful + public bool Success { get { return m_success; } } + /// + /// Triggered when appearance data is sent to the sim and + /// the main appearance thread is done. + /// Indicates whether appearance setting was successful + public AppearanceSetEventArgs(bool success) + { + this.m_success = success; + } + } + + /// Contains the Event data returned from the data server from an RebakeAvatarTextures + public class RebakeAvatarTexturesEventArgs : EventArgs + { + private readonly UUID m_textureID; + + /// The ID of the Texture Layer to bake + public UUID TextureID { get { return m_textureID; } } + + /// + /// Triggered when the simulator sends a request for this agent to rebake + /// its appearance + /// + /// The ID of the Texture Layer to bake + public RebakeAvatarTexturesEventArgs(UUID textureID) + { + this.m_textureID = textureID; + } + + } + #endregion +} \ No newline at end of file diff --git a/OpenMetaverse/AssemblyInfo.cs b/OpenMetaverse/AssemblyInfo.cs new file mode 100644 index 0000000..26a55f9 --- /dev/null +++ b/OpenMetaverse/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMetaverse")] +[assembly: AssemblyDescription("OpenMetaverse library")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("openmetaverse.org")] +[assembly: AssemblyProduct("OpenMetaverse")] +[assembly: AssemblyCopyright("Copyright © openmetaverse.org 2006-2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("0.9.3.0")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] +[assembly: AssemblyFileVersionAttribute("0.9.3.0")] diff --git a/OpenMetaverse/AssetCache.cs b/OpenMetaverse/AssetCache.cs new file mode 100644 index 0000000..ad8b5b8 --- /dev/null +++ b/OpenMetaverse/AssetCache.cs @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +namespace OpenMetaverse +{ + /// + /// Class that handles the local asset cache + /// + public class AssetCache + { + // User can plug in a routine to compute the asset cache location + public delegate string ComputeAssetCacheFilenameDelegate(string cacheDir, UUID assetID); + + public ComputeAssetCacheFilenameDelegate ComputeAssetCacheFilename = null; + + private GridClient Client; + private Thread cleanerThread; + private System.Timers.Timer cleanerTimer; + private double pruneInterval = 1000 * 60 * 5; + private bool autoPruneEnabled = true; + + /// + /// Allows setting weather to periodicale prune the cache if it grows too big + /// Default is enabled, when caching is enabled + /// + public bool AutoPruneEnabled + { + set + { + autoPruneEnabled = value; + + if (autoPruneEnabled) + { + SetupTimer(); + } + else + { + DestroyTimer(); + } + } + get { return autoPruneEnabled; } + } + + /// + /// How long (in ms) between cache checks (default is 5 min.) + /// + public double AutoPruneInterval + { + set + { + pruneInterval = value; + SetupTimer(); + } + get { return pruneInterval; } + } + + /// + /// Default constructor + /// + /// A reference to the GridClient object + public AssetCache(GridClient client) + { + Client = client; + Client.Network.LoginProgress += delegate(object sender, LoginProgressEventArgs e) + { + if (e.Status == LoginStatus.Success) + { + SetupTimer(); + } + }; + + Client.Network.Disconnected += delegate(object sender, DisconnectedEventArgs e) { DestroyTimer(); }; + } + + + /// + /// Disposes cleanup timer + /// + private void DestroyTimer() + { + if (cleanerTimer != null) + { + cleanerTimer.Dispose(); + cleanerTimer = null; + } + } + + /// + /// Only create timer when needed + /// + private void SetupTimer() + { + if (Operational() && autoPruneEnabled && Client.Network.Connected) + { + if (cleanerTimer == null) + { + cleanerTimer = new System.Timers.Timer(pruneInterval); + cleanerTimer.Elapsed += new System.Timers.ElapsedEventHandler(cleanerTimer_Elapsed); + } + cleanerTimer.Interval = pruneInterval; + cleanerTimer.Enabled = true; + } + } + + /// + /// Return bytes read from the local asset cache, null if it does not exist + /// + /// UUID of the asset we want to get + /// Raw bytes of the asset, or null on failure + public byte[] GetCachedAssetBytes(UUID assetID) + { + if (!Operational()) + { + return null; + } + try + { + byte[] data; + + if (File.Exists(FileName(assetID))) + { + DebugLog("Reading " + FileName(assetID) + " from asset cache."); + data = File.ReadAllBytes(FileName(assetID)); + } + else + { + DebugLog("Reading " + StaticFileName(assetID) + " from static asset cache."); + data = File.ReadAllBytes(StaticFileName(assetID)); + + } + return data; + } + catch (Exception ex) + { + DebugLog("Failed reading asset from cache (" + ex.Message + ")"); + return null; + } + } + + /// + /// Returns ImageDownload object of the + /// image from the local image cache, null if it does not exist + /// + /// UUID of the image we want to get + /// ImageDownload object containing the image, or null on failure + public ImageDownload GetCachedImage(UUID imageID) + { + if (!Operational()) + return null; + + byte[] imageData = GetCachedAssetBytes(imageID); + if (imageData == null) + return null; + ImageDownload transfer = new ImageDownload(); + transfer.AssetType = AssetType.Texture; + transfer.ID = imageID; + transfer.Simulator = Client.Network.CurrentSim; + transfer.Size = imageData.Length; + transfer.Success = true; + transfer.Transferred = imageData.Length; + transfer.AssetData = imageData; + return transfer; + } + + /// + /// Constructs a file name of the cached asset + /// + /// UUID of the asset + /// String with the file name of the cahced asset + private string FileName(UUID assetID) + { + if (ComputeAssetCacheFilename != null) + { + return ComputeAssetCacheFilename(Client.Settings.ASSET_CACHE_DIR, assetID); + } + return Client.Settings.ASSET_CACHE_DIR + Path.DirectorySeparatorChar + assetID.ToString(); + } + + /// + /// Constructs a file name of the static cached asset + /// + /// UUID of the asset + /// String with the file name of the static cached asset + private string StaticFileName(UUID assetID) + { + return Settings.RESOURCE_DIR + Path.DirectorySeparatorChar + "static_assets" + Path.DirectorySeparatorChar + assetID.ToString(); + } + + /// + /// Saves an asset to the local cache + /// + /// UUID of the asset + /// Raw bytes the asset consists of + /// Weather the operation was successfull + public bool SaveAssetToCache(UUID assetID, byte[] assetData) + { + if (!Operational()) + { + return false; + } + + try + { + DebugLog("Saving " + FileName(assetID) + " to asset cache."); + + if (!Directory.Exists(Client.Settings.ASSET_CACHE_DIR)) + { + Directory.CreateDirectory(Client.Settings.ASSET_CACHE_DIR); + } + + File.WriteAllBytes(FileName(assetID), assetData); + } + catch (Exception ex) + { + Logger.Log("Failed saving asset to cache (" + ex.Message + ")", Helpers.LogLevel.Warning, Client); + return false; + } + + return true; + } + + private void DebugLog(string message) + { + if (Client.Settings.LOG_DISKCACHE) Logger.DebugLog(message, Client); + } + + /// + /// Get the file name of the asset stored with gived UUID + /// + /// UUID of the asset + /// Null if we don't have that UUID cached on disk, file name if found in the cache folder + public string AssetFileName(UUID assetID) + { + if (!Operational()) + { + return null; + } + + string fileName = FileName(assetID); + + if (File.Exists(fileName)) + return fileName; + else + return null; + } + + /// + /// Checks if the asset exists in the local cache + /// + /// UUID of the asset + /// True is the asset is stored in the cache, otherwise false + public bool HasAsset(UUID assetID) + { + if (!Operational()) + return false; + else + if (File.Exists(FileName(assetID))) + return true; + else + return File.Exists(StaticFileName(assetID)); + + } + + /// + /// Wipes out entire cache + /// + public void Clear() + { + string cacheDir = Client.Settings.ASSET_CACHE_DIR; + if (!Directory.Exists(cacheDir)) + { + return; + } + + DirectoryInfo di = new DirectoryInfo(cacheDir); + // We save file with UUID as file name, only delete those + FileInfo[] files = di.GetFiles("????????-????-????-????-????????????", SearchOption.TopDirectoryOnly); + + int num = 0; + foreach (FileInfo file in files) + { + file.Delete(); + ++num; + } + + DebugLog("Wiped out " + num + " files from the cache directory."); + } + + /// + /// Brings cache size to the 90% of the max size + /// + public void Prune() + { + string cacheDir = Client.Settings.ASSET_CACHE_DIR; + if (!Directory.Exists(cacheDir)) + { + return; + } + DirectoryInfo di = new DirectoryInfo(cacheDir); + // We save file with UUID as file name, only count those + FileInfo[] files = di.GetFiles("????????-????-????-????-????????????", SearchOption.TopDirectoryOnly); + + long size = GetFileSize(files); + + if (size > Client.Settings.ASSET_CACHE_MAX_SIZE) + { + Array.Sort(files, new SortFilesByAccesTimeHelper()); + long targetSize = (long)(Client.Settings.ASSET_CACHE_MAX_SIZE * 0.9); + int num = 0; + foreach (FileInfo file in files) + { + ++num; + size -= file.Length; + file.Delete(); + if (size < targetSize) + { + break; + } + } + DebugLog(num + " files deleted from the cache, cache size now: " + NiceFileSize(size)); + } + else + { + DebugLog("Cache size is " + NiceFileSize(size) + ", file deletion not needed"); + } + + } + + /// + /// Asynchronously brings cache size to the 90% of the max size + /// + public void BeginPrune() + { + // Check if the background cache cleaning thread is active first + if (cleanerThread != null && cleanerThread.IsAlive) + { + return; + } + + lock (this) + { + cleanerThread = new Thread(new ThreadStart(this.Prune)); + cleanerThread.IsBackground = true; + cleanerThread.Start(); + } + } + + /// + /// Adds up file sizes passes in a FileInfo array + /// + long GetFileSize(FileInfo[] files) + { + long ret = 0; + foreach (FileInfo file in files) + { + ret += file.Length; + } + return ret; + } + + /// + /// Checks whether caching is enabled + /// + private bool Operational() + { + return Client.Settings.USE_ASSET_CACHE; + } + + /// + /// Periodically prune the cache + /// + private void cleanerTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + BeginPrune(); + } + + /// + /// Nicely formats file sizes + /// + /// Byte size we want to output + /// String with humanly readable file size + private string NiceFileSize(long byteCount) + { + string size = "0 Bytes"; + if (byteCount >= 1073741824) + size = String.Format("{0:##.##}", byteCount / 1073741824) + " GB"; + else if (byteCount >= 1048576) + size = String.Format("{0:##.##}", byteCount / 1048576) + " MB"; + else if (byteCount >= 1024) + size = String.Format("{0:##.##}", byteCount / 1024) + " KB"; + else if (byteCount > 0 && byteCount < 1024) + size = byteCount.ToString() + " Bytes"; + + return size; + } + + /// + /// Helper class for sorting files by their last accessed time + /// + private class SortFilesByAccesTimeHelper : IComparer + { + int IComparer.Compare(FileInfo f1, FileInfo f2) + { + if (f1.LastAccessTime > f2.LastAccessTime) + return 1; + if (f1.LastAccessTime < f2.LastAccessTime) + return -1; + else + return 0; + } + } + } +} diff --git a/OpenMetaverse/AssetManager.cs b/OpenMetaverse/AssetManager.cs new file mode 100644 index 0000000..9dd97d5 --- /dev/null +++ b/OpenMetaverse/AssetManager.cs @@ -0,0 +1,1942 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using System.IO; +using System.Net; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.Assets; +using OpenMetaverse.Http; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse +{ + #region Enums + + public enum EstateAssetType : int + { + None = -1, + Covenant = 0 + } + + /// + /// + /// + public enum StatusCode + { + /// OK + OK = 0, + /// Transfer completed + Done = 1, + /// + Skip = 2, + /// + Abort = 3, + /// Unknown error occurred + Error = -1, + /// Equivalent to a 404 error + UnknownSource = -2, + /// Client does not have permission for that resource + InsufficientPermissions = -3, + /// Unknown status + Unknown = -4 + } + + /// + /// + /// + public enum ChannelType : int + { + /// + Unknown = 0, + /// Unknown + Misc = 1, + /// Virtually all asset transfers use this channel + Asset = 2 + } + + /// + /// + /// + public enum SourceType : int + { + /// + Unknown = 0, + /// Asset from the asset server + Asset = 2, + /// Inventory item + SimInventoryItem = 3, + /// Estate asset, such as an estate covenant + SimEstate = 4 + } + + /// + /// + /// + public enum TargetType : int + { + /// + Unknown = 0, + /// + File = 1, + /// + VFile = 2 + } + + /// + /// When requesting image download, type of the image requested + /// + public enum ImageType : byte + { + /// Normal in-world object texture + Normal = 0, + /// Avatar texture + Baked = 1, + /// Server baked avatar texture + ServerBaked = 2 + } + + /// + /// Image file format + /// + public enum ImageCodec : byte + { + Invalid = 0, + RGB = 1, + J2C = 2, + BMP = 3, + TGA = 4, + JPEG = 5, + DXT = 6, + PNG = 7 + } + + public enum TransferError : int + { + None = 0, + Failed = -1, + AssetNotFound = -3, + AssetNotFoundInDatabase = -4, + InsufficientPermissions = -5, + EOF = -39, + CannotOpenFile = -42, + FileNotFound = -43, + FileIsEmpty = -44, + TCPTimeout = -23016, + CircuitGone = -23017 + } + + #endregion Enums + + #region Transfer Classes + + /// + /// + /// + public class Transfer + { + public UUID ID; + public int Size; + public byte[] AssetData = Utils.EmptyBytes; + public int Transferred; + public bool Success; + public AssetType AssetType; + + private int transferStart; + + /// Number of milliseconds passed since the last transfer + /// packet was received + public int TimeSinceLastPacket + { + get { return Environment.TickCount - transferStart; } + internal set { transferStart = Environment.TickCount + value; } + } + + public Transfer() + { + AssetData = Utils.EmptyBytes; + transferStart = Environment.TickCount; + } + } + + /// + /// + /// + public class AssetDownload : Transfer + { + public UUID AssetID; + public ChannelType Channel; + public SourceType Source; + public TargetType Target; + public StatusCode Status; + public float Priority; + public Simulator Simulator; + public AssetManager.AssetReceivedCallback Callback; + + public int nextPacket; + public InternalDictionary outOfOrderPackets; + internal ManualResetEvent HeaderReceivedEvent = new ManualResetEvent(false); + + public AssetDownload() + : base() + { + nextPacket = 0; + outOfOrderPackets = new InternalDictionary(); + } + } + + /// + /// + /// + public class XferDownload : Transfer + { + public ulong XferID; + public UUID VFileID; + public uint PacketNum; + public string Filename = String.Empty; + public TransferError Error = TransferError.None; + + public XferDownload() + : base() + { + } + } + + /// + /// + /// + public class ImageDownload : Transfer + { + public ushort PacketCount; + public ImageCodec Codec; + public Simulator Simulator; + public SortedList PacketsSeen; + public ImageType ImageType; + public int DiscardLevel; + public float Priority; + internal int InitialDataSize; + internal ManualResetEvent HeaderReceivedEvent = new ManualResetEvent(false); + + public ImageDownload() + : base() + { + } + } + + /// + /// + /// + public class AssetUpload : Transfer + { + public UUID AssetID; + public AssetType Type; + public ulong XferID; + public uint PacketNum; + + public AssetUpload() + : base() + { + } + } + + /// + /// + /// + public class ImageRequest + { + public UUID ImageID; + public ImageType Type; + public float Priority; + public int DiscardLevel; + + /// + /// + /// + /// + /// + /// + /// + public ImageRequest(UUID imageid, ImageType type, float priority, int discardLevel) + { + ImageID = imageid; + Type = type; + Priority = priority; + DiscardLevel = discardLevel; + } + + } + #endregion Transfer Classes + + /// + /// + /// + public class AssetManager + { + /// Number of milliseconds to wait for a transfer header packet if out of order data was received + const int TRANSFER_HEADER_TIMEOUT = 1000 * 15; + + #region Delegates + /// + /// Callback used for various asset download requests + /// + /// Transfer information + /// Downloaded asset, null on fail + public delegate void AssetReceivedCallback(AssetDownload transfer, Asset asset); + /// + /// Callback used upon competition of baked texture upload + /// + /// Asset UUID of the newly uploaded baked texture + public delegate void BakedTextureUploadedCallback(UUID newAssetID); + /// + /// A callback that fires upon the completition of the RequestMesh call + /// + /// Was the download successfull + /// Resulting mesh or null on problems + public delegate void MeshDownloadCallback(bool success, AssetMesh assetMesh); + + #endregion Delegates + + #region Events + + #region XferReceived + /// The event subscribers. null if no subcribers + private EventHandler m_XferReceivedEvent; + + /// Raises the XferReceived event + /// A XferReceivedEventArgs object containing the + /// data returned from the simulator + protected virtual void OnXferReceived(XferReceivedEventArgs e) + { + EventHandler handler = m_XferReceivedEvent; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_XferReceivedLock = new object(); + + /// Raised when the simulator responds sends + public event EventHandler XferReceived + { + add { lock (m_XferReceivedLock) { m_XferReceivedEvent += value; } } + remove { lock (m_XferReceivedLock) { m_XferReceivedEvent -= value; } } + } + #endregion + + #region AssetUploaded + /// The event subscribers. null if no subcribers + private EventHandler m_AssetUploadedEvent; + + /// Raises the AssetUploaded event + /// A AssetUploadedEventArgs object containing the + /// data returned from the simulator + protected virtual void OnAssetUploaded(AssetUploadEventArgs e) + { + EventHandler handler = m_AssetUploadedEvent; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AssetUploadedLock = new object(); + + /// Raised during upload completes + public event EventHandler AssetUploaded + { + add { lock (m_AssetUploadedLock) { m_AssetUploadedEvent += value; } } + remove { lock (m_AssetUploadedLock) { m_AssetUploadedEvent -= value; } } + } + #endregion + + #region UploadProgress + /// The event subscribers. null if no subcribers + private EventHandler m_UploadProgressEvent; + + /// Raises the UploadProgress event + /// A UploadProgressEventArgs object containing the + /// data returned from the simulator + protected virtual void OnUploadProgress(AssetUploadEventArgs e) + { + EventHandler handler = m_UploadProgressEvent; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_UploadProgressLock = new object(); + + /// Raised during upload with progres update + public event EventHandler UploadProgress + { + add { lock (m_UploadProgressLock) { m_UploadProgressEvent += value; } } + remove { lock (m_UploadProgressLock) { m_UploadProgressEvent -= value; } } + } + #endregion UploadProgress + + #region InitiateDownload + /// The event subscribers. null if no subcribers + private EventHandler m_InitiateDownloadEvent; + + /// Raises the InitiateDownload event + /// A InitiateDownloadEventArgs object containing the + /// data returned from the simulator + protected virtual void OnInitiateDownload(InitiateDownloadEventArgs e) + { + EventHandler handler = m_InitiateDownloadEvent; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InitiateDownloadLock = new object(); + + /// Fired when the simulator sends an InitiateDownloadPacket, used to download terrain .raw files + public event EventHandler InitiateDownload + { + add { lock (m_InitiateDownloadLock) { m_InitiateDownloadEvent += value; } } + remove { lock (m_InitiateDownloadLock) { m_InitiateDownloadEvent -= value; } } + } + #endregion InitiateDownload + + #region ImageReceiveProgress + /// The event subscribers. null if no subcribers + private EventHandler m_ImageReceiveProgressEvent; + + /// Raises the ImageReceiveProgress event + /// A ImageReceiveProgressEventArgs object containing the + /// data returned from the simulator + protected virtual void OnImageReceiveProgress(ImageReceiveProgressEventArgs e) + { + EventHandler handler = m_ImageReceiveProgressEvent; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ImageReceiveProgressLock = new object(); + + /// Fired when a texture is in the process of being downloaded by the TexturePipeline class + public event EventHandler ImageReceiveProgress + { + add { lock (m_ImageReceiveProgressLock) { m_ImageReceiveProgressEvent += value; } } + remove { lock (m_ImageReceiveProgressLock) { m_ImageReceiveProgressEvent -= value; } } + } + #endregion ImageReceiveProgress + + #endregion Events + + /// Texture download cache + public AssetCache Cache; + + private TexturePipeline Texture; + + private DownloadManager HttpDownloads; + + private GridClient Client; + + private Dictionary Transfers = new Dictionary(); + + private AssetUpload PendingUpload; + private object PendingUploadLock = new object(); + private volatile bool WaitingForUploadConfirm = false; + + /// + /// Default constructor + /// + /// A reference to the GridClient object + public AssetManager(GridClient client) + { + Client = client; + Cache = new AssetCache(client); + Texture = new TexturePipeline(client); + HttpDownloads = new DownloadManager(); + + // Transfer packets for downloading large assets + Client.Network.RegisterCallback(PacketType.TransferInfo, TransferInfoHandler); + Client.Network.RegisterCallback(PacketType.TransferPacket, TransferPacketHandler); + + // Xfer packets for uploading large assets + Client.Network.RegisterCallback(PacketType.RequestXfer, RequestXferHandler); + Client.Network.RegisterCallback(PacketType.ConfirmXferPacket, ConfirmXferPacketHandler); + Client.Network.RegisterCallback(PacketType.AssetUploadComplete, AssetUploadCompleteHandler); + + // Xfer packets for downloading misc assets + Client.Network.RegisterCallback(PacketType.SendXferPacket, SendXferPacketHandler); + Client.Network.RegisterCallback(PacketType.AbortXfer, AbortXferHandler); + + // Simulator is responding to a request to download a file + Client.Network.RegisterCallback(PacketType.InitiateDownload, InitiateDownloadPacketHandler); + + } + + /// + /// Request an asset download + /// + /// Asset UUID + /// Asset type, must be correct for the transfer to succeed + /// Whether to give this transfer an elevated priority + /// The callback to fire when the simulator responds with the asset data + public void RequestAsset(UUID assetID, AssetType type, bool priority, AssetReceivedCallback callback) + { + RequestAsset(assetID, type, priority, SourceType.Asset, UUID.Random(), callback); + } + + /// + /// Request an asset download + /// + /// Asset UUID + /// Asset type, must be correct for the transfer to succeed + /// Whether to give this transfer an elevated priority + /// Source location of the requested asset + /// The callback to fire when the simulator responds with the asset data + public void RequestAsset(UUID assetID, AssetType type, bool priority, SourceType sourceType, AssetReceivedCallback callback) + { + RequestAsset(assetID, type, priority, sourceType, UUID.Random(), callback); + } + + /// + /// Request an asset download + /// + /// Asset UUID + /// Asset type, must be correct for the transfer to succeed + /// Whether to give this transfer an elevated priority + /// Source location of the requested asset + /// UUID of the transaction + /// The callback to fire when the simulator responds with the asset data + public void RequestAsset(UUID assetID, AssetType type, bool priority, SourceType sourceType, UUID transactionID, AssetReceivedCallback callback) + { + RequestAsset(assetID, UUID.Zero, UUID.Zero, type, priority, sourceType, transactionID, callback); + } + + /// + /// Request an asset download + /// + /// Asset UUID + /// Asset type, must be correct for the transfer to succeed + /// Whether to give this transfer an elevated priority + /// Source location of the requested asset + /// UUID of the transaction + /// The callback to fire when the simulator responds with the asset data + public void RequestAsset(UUID assetID, UUID itemID, UUID taskID, AssetType type, bool priority, SourceType sourceType, UUID transactionID, AssetReceivedCallback callback) + { + AssetDownload transfer = new AssetDownload(); + transfer.ID = transactionID; + transfer.AssetID = assetID; + //transfer.AssetType = type; // Set in TransferInfoHandler. + transfer.Priority = 100.0f + (priority ? 1.0f : 0.0f); + transfer.Channel = ChannelType.Asset; + transfer.Source = sourceType; + transfer.Simulator = Client.Network.CurrentSim; + transfer.Callback = callback; + + // Check asset cache first + if (callback != null && Cache.HasAsset(assetID)) + { + byte[] data = Cache.GetCachedAssetBytes(assetID); + transfer.AssetData = data; + transfer.Success = true; + transfer.Status = StatusCode.OK; + + Asset asset = CreateAssetWrapper(type); + asset.AssetData = data; + asset.AssetID = assetID; + + try { callback(transfer, asset); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + + return; + } + + // Add this transfer to the dictionary + lock (Transfers) Transfers[transfer.ID] = transfer; + + // Build the request packet and send it + TransferRequestPacket request = new TransferRequestPacket(); + request.TransferInfo.ChannelType = (int)transfer.Channel; + request.TransferInfo.Priority = transfer.Priority; + request.TransferInfo.SourceType = (int)transfer.Source; + request.TransferInfo.TransferID = transfer.ID; + + byte[] paramField = taskID == UUID.Zero ? new byte[20] : new byte[96]; + Buffer.BlockCopy(assetID.GetBytes(), 0, paramField, 0, 16); + Buffer.BlockCopy(Utils.IntToBytes((int)type), 0, paramField, 16, 4); + + if (taskID != UUID.Zero) + { + Buffer.BlockCopy(taskID.GetBytes(), 0, paramField, 48, 16); + Buffer.BlockCopy(itemID.GetBytes(), 0, paramField, 64, 16); + Buffer.BlockCopy(assetID.GetBytes(), 0, paramField, 80, 16); + } + request.TransferInfo.Params = paramField; + + Client.Network.SendPacket(request, transfer.Simulator); + } + + /// + /// Request an asset download through the almost deprecated Xfer system + /// + /// Filename of the asset to request + /// Whether or not to delete the asset + /// off the server after it is retrieved + /// Use large transfer packets or not + /// UUID of the file to request, if filename is + /// left empty + /// Asset type of vFileID, or + /// AssetType.Unknown if filename is not empty + /// Sets the FilePath in the request to Cache + /// (4) if true, otherwise Unknown (0) is used + /// + public ulong RequestAssetXfer(string filename, bool deleteOnCompletion, bool useBigPackets, UUID vFileID, AssetType vFileType, + bool fromCache) + { + UUID uuid = UUID.Random(); + ulong id = uuid.GetULong(); + + XferDownload transfer = new XferDownload(); + transfer.XferID = id; + transfer.ID = new UUID(id); // Our dictionary tracks transfers with UUIDs, so convert the ulong back + transfer.Filename = filename; + transfer.VFileID = vFileID; + transfer.AssetType = vFileType; + + // Add this transfer to the dictionary + lock (Transfers) Transfers[transfer.ID] = transfer; + + RequestXferPacket request = new RequestXferPacket(); + request.XferID.ID = id; + request.XferID.Filename = Utils.StringToBytes(filename); + request.XferID.FilePath = fromCache ? (byte)4 : (byte)0; + request.XferID.DeleteOnCompletion = deleteOnCompletion; + request.XferID.UseBigPackets = useBigPackets; + request.XferID.VFileID = vFileID; + request.XferID.VFileType = (short)vFileType; + + Client.Network.SendPacket(request); + + return id; + } + + /// + /// + /// + /// Use UUID.Zero if you do not have the + /// asset ID but have all the necessary permissions + /// The item ID of this asset in the inventory + /// Use UUID.Zero if you are not requesting an + /// asset from an object inventory + /// The owner of this asset + /// Asset type + /// Whether to prioritize this asset download or not + /// + public void RequestInventoryAsset(UUID assetID, UUID itemID, UUID taskID, UUID ownerID, AssetType type, bool priority, AssetReceivedCallback callback) + { + AssetDownload transfer = new AssetDownload(); + transfer.ID = UUID.Random(); + transfer.AssetID = assetID; + //transfer.AssetType = type; // Set in TransferInfoHandler. + transfer.Priority = 100.0f + (priority ? 1.0f : 0.0f); + transfer.Channel = ChannelType.Asset; + transfer.Source = SourceType.SimInventoryItem; + transfer.Simulator = Client.Network.CurrentSim; + transfer.Callback = callback; + + // Check asset cache first + if (callback != null && Cache.HasAsset(assetID)) + { + byte[] data = Cache.GetCachedAssetBytes(assetID); + transfer.AssetData = data; + transfer.Success = true; + transfer.Status = StatusCode.OK; + + Asset asset = CreateAssetWrapper(type); + asset.AssetData = data; + asset.AssetID = assetID; + + try { callback(transfer, asset); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + + return; + } + + // Add this transfer to the dictionary + lock (Transfers) Transfers[transfer.ID] = transfer; + + // Build the request packet and send it + TransferRequestPacket request = new TransferRequestPacket(); + request.TransferInfo.ChannelType = (int)transfer.Channel; + request.TransferInfo.Priority = transfer.Priority; + request.TransferInfo.SourceType = (int)transfer.Source; + request.TransferInfo.TransferID = transfer.ID; + + byte[] paramField = new byte[100]; + Buffer.BlockCopy(Client.Self.AgentID.GetBytes(), 0, paramField, 0, 16); + Buffer.BlockCopy(Client.Self.SessionID.GetBytes(), 0, paramField, 16, 16); + Buffer.BlockCopy(ownerID.GetBytes(), 0, paramField, 32, 16); + Buffer.BlockCopy(taskID.GetBytes(), 0, paramField, 48, 16); + Buffer.BlockCopy(itemID.GetBytes(), 0, paramField, 64, 16); + Buffer.BlockCopy(assetID.GetBytes(), 0, paramField, 80, 16); + Buffer.BlockCopy(Utils.IntToBytes((int)type), 0, paramField, 96, 4); + request.TransferInfo.Params = paramField; + + Client.Network.SendPacket(request, transfer.Simulator); + } + + public void RequestInventoryAsset(InventoryItem item, bool priority, AssetReceivedCallback callback) + { + RequestInventoryAsset(item.AssetUUID, item.UUID, UUID.Zero, item.OwnerID, item.AssetType, priority, callback); + } + + public void RequestEstateAsset() + { + throw new Exception("This function is not implemented yet!"); + } + + /// + /// Used to force asset data into the PendingUpload property, ie: for raw terrain uploads + /// + /// An AssetUpload object containing the data to upload to the simulator + internal void SetPendingAssetUploadData(AssetUpload assetData) + { + lock (PendingUploadLock) + PendingUpload = assetData; + } + + /// + /// Request an asset be uploaded to the simulator + /// + /// The Object containing the asset data + /// If True, the asset once uploaded will be stored on the simulator + /// in which the client was connected in addition to being stored on the asset server + /// The of the transfer, can be used to correlate the upload with + /// events being fired + public UUID RequestUpload(Asset asset, bool storeLocal) + { + if (asset.AssetData == null) + throw new ArgumentException("Can't upload an asset with no data (did you forget to call Encode?)"); + + UUID assetID; + UUID transferID = RequestUpload(out assetID, asset.AssetType, asset.AssetData, storeLocal); + asset.AssetID = assetID; + return transferID; + } + + /// + /// Request an asset be uploaded to the simulator + /// + /// The of the asset being uploaded + /// A byte array containing the encoded asset data + /// If True, the asset once uploaded will be stored on the simulator + /// in which the client was connected in addition to being stored on the asset server + /// The of the transfer, can be used to correlate the upload with + /// events being fired + public UUID RequestUpload(AssetType type, byte[] data, bool storeLocal) + { + UUID assetID; + return RequestUpload(out assetID, type, data, storeLocal); + } + + /// + /// Request an asset be uploaded to the simulator + /// + /// + /// Asset type to upload this data as + /// A byte array containing the encoded asset data + /// If True, the asset once uploaded will be stored on the simulator + /// in which the client was connected in addition to being stored on the asset server + /// The of the transfer, can be used to correlate the upload with + /// events being fired + public UUID RequestUpload(out UUID assetID, AssetType type, byte[] data, bool storeLocal) + { + return RequestUpload(out assetID, type, data, storeLocal, UUID.Random()); + } + + /// + /// Initiate an asset upload + /// + /// The ID this asset will have if the + /// upload succeeds + /// Asset type to upload this data as + /// Raw asset data to upload + /// Whether to store this asset on the local + /// simulator or the grid-wide asset server + /// The tranaction id for the upload + /// The transaction ID of this transfer + public UUID RequestUpload(out UUID assetID, AssetType type, byte[] data, bool storeLocal, UUID transactionID) + { + AssetUpload upload = new AssetUpload(); + upload.AssetData = data; + upload.AssetType = type; + assetID = UUID.Combine(transactionID, Client.Self.SecureSessionID); + upload.AssetID = assetID; + upload.Size = data.Length; + upload.XferID = 0; + upload.ID = transactionID; + + // Build and send the upload packet + AssetUploadRequestPacket request = new AssetUploadRequestPacket(); + request.AssetBlock.StoreLocal = storeLocal; + request.AssetBlock.Tempfile = false; // This field is deprecated + request.AssetBlock.TransactionID = transactionID; + request.AssetBlock.Type = (sbyte)type; + + bool isMultiPacketUpload; + if (data.Length + 100 < Settings.MAX_PACKET_SIZE) + { + isMultiPacketUpload = false; + Logger.Log( + String.Format("Beginning asset upload [Single Packet], ID: {0}, AssetID: {1}, Size: {2}", + upload.ID.ToString(), upload.AssetID.ToString(), upload.Size), Helpers.LogLevel.Info, Client); + + Transfers[upload.ID] = upload; + + // The whole asset will fit in this packet, makes things easy + request.AssetBlock.AssetData = data; + upload.Transferred = data.Length; + } + else + { + isMultiPacketUpload = true; + Logger.Log( + String.Format("Beginning asset upload [Multiple Packets], ID: {0}, AssetID: {1}, Size: {2}", + upload.ID.ToString(), upload.AssetID.ToString(), upload.Size), Helpers.LogLevel.Info, Client); + + // Asset is too big, send in multiple packets + request.AssetBlock.AssetData = Utils.EmptyBytes; + } + + // Wait for the previous upload to receive a RequestXferPacket + lock (PendingUploadLock) + { + const int UPLOAD_CONFIRM_TIMEOUT = 20 * 1000; + const int SLEEP_INTERVAL = 50; + int t = 0; + while (WaitingForUploadConfirm && t < UPLOAD_CONFIRM_TIMEOUT) + { + System.Threading.Thread.Sleep(SLEEP_INTERVAL); + t += SLEEP_INTERVAL; + } + + if (t < UPLOAD_CONFIRM_TIMEOUT) + { + if (isMultiPacketUpload) + { + WaitingForUploadConfirm = true; + } + PendingUpload = upload; + Client.Network.SendPacket(request); + + return upload.ID; + } + else + { + throw new Exception("Timeout waiting for previous asset upload to begin"); + } + } + } + + public void RequestUploadBakedTexture(byte[] textureData, BakedTextureUploadedCallback callback) + { + Uri url = null; + + Caps caps = Client.Network.CurrentSim.Caps; + if (caps != null) + url = caps.CapabilityURI("UploadBakedTexture"); + + if (url != null) + { + // Fetch the uploader capability + CapsClient request = new CapsClient(url); + request.OnComplete += + delegate(CapsClient client, OSD result, Exception error) + { + if (error == null && result is OSDMap) + { + UploadBakedTextureMessage message = new UploadBakedTextureMessage(); + message.Deserialize((OSDMap)result); + + if (message.Request.State == "upload") + { + Uri uploadUrl = ((UploaderRequestUpload)message.Request).Url; + + if (uploadUrl != null) + { + // POST the asset data + CapsClient upload = new CapsClient(uploadUrl); + upload.OnComplete += + delegate(CapsClient client2, OSD result2, Exception error2) + { + if (error2 == null && result2 is OSDMap) + { + UploadBakedTextureMessage message2 = new UploadBakedTextureMessage(); + message2.Deserialize((OSDMap)result2); + + if (message2.Request.State == "complete") + { + callback(((UploaderRequestComplete)message2.Request).AssetID); + return; + } + } + + Logger.Log("Bake upload failed during asset upload", Helpers.LogLevel.Warning, Client); + callback(UUID.Zero); + }; + upload.BeginGetResponse(textureData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); + return; + } + } + } + + Logger.Log("Bake upload failed during uploader retrieval", Helpers.LogLevel.Warning, Client); + callback(UUID.Zero); + }; + request.BeginGetResponse(new OSDMap(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + Logger.Log("UploadBakedTexture not available, falling back to UDP method", Helpers.LogLevel.Info, Client); + + WorkPool.QueueUserWorkItem( + delegate(object o) + { + UUID transactionID = UUID.Random(); + BakedTextureUploadedCallback uploadCallback = (BakedTextureUploadedCallback)o; + AutoResetEvent uploadEvent = new AutoResetEvent(false); + EventHandler udpCallback = + delegate(object sender, AssetUploadEventArgs e) + { + if (e.Upload.ID == transactionID) + { + uploadEvent.Set(); + uploadCallback(e.Upload.Success ? e.Upload.AssetID : UUID.Zero); + } + }; + + AssetUploaded += udpCallback; + + UUID assetID; + bool success; + + try + { + RequestUpload(out assetID, AssetType.Texture, textureData, true, transactionID); + success = uploadEvent.WaitOne(Client.Settings.TRANSFER_TIMEOUT, false); + } + catch (Exception) + { + success = false; + } + + AssetUploaded -= udpCallback; + + if (!success) + uploadCallback(UUID.Zero); + }, callback + ); + } + } + + #region Texture Downloads + + /// + /// Request a texture asset from the simulator using the system to + /// manage the requests and re-assemble the image from the packets received from the simulator + /// + /// The of the texture asset to download + /// The of the texture asset. + /// Use for most textures, or for baked layer texture assets + /// A float indicating the requested priority for the transfer. Higher priority values tell the simulator + /// to prioritize the request before lower valued requests. An image already being transferred using the can have + /// its priority changed by resending the request with the new priority value + /// Number of quality layers to discard. + /// This controls the end marker of the data sent. Sending with value -1 combined with priority of 0 cancels an in-progress + /// transfer. + /// A bug exists in the Linden Simulator where a -1 will occasionally be sent with a non-zero priority + /// indicating an off-by-one error. + /// The packet number to begin the request at. A value of 0 begins the request + /// from the start of the asset texture + /// The callback to fire when the image is retrieved. The callback + /// will contain the result of the request and the texture asset data + /// If true, the callback will be fired for each chunk of the downloaded image. + /// The callback asset parameter will contain all previously received chunks of the texture asset starting + /// from the beginning of the request + /// + /// Request an image and fire a callback when the request is complete + /// + /// Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); + /// + /// private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) + /// { + /// if(state == TextureRequestState.Finished) + /// { + /// Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", + /// asset.AssetID, + /// asset.AssetData.Length); + /// } + /// } + /// + /// Request an image and use an inline anonymous method to handle the downloaded texture data + /// + /// Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, delegate(TextureRequestState state, AssetTexture asset) + /// { + /// if(state == TextureRequestState.Finished) + /// { + /// Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", + /// asset.AssetID, + /// asset.AssetData.Length); + /// } + /// } + /// ); + /// + /// Request a texture, decode the texture to a bitmap image and apply it to a imagebox + /// + /// Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); + /// + /// private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) + /// { + /// if(state == TextureRequestState.Finished) + /// { + /// ManagedImage imgData; + /// Image bitmap; + /// + /// if (state == TextureRequestState.Finished) + /// { + /// OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData, out bitmap); + /// picInsignia.Image = bitmap; + /// } + /// } + /// } + /// + /// + public void RequestImage(UUID textureID, ImageType imageType, float priority, int discardLevel, + uint packetStart, TextureDownloadCallback callback, bool progress) + { + if (Client.Settings.USE_HTTP_TEXTURES && + Client.Network.CurrentSim.Caps != null && + Client.Network.CurrentSim.Caps.CapabilityURI("GetTexture") != null) + { + HttpRequestTexture(textureID, imageType, priority, discardLevel, packetStart, callback, progress); + } + else + { + Texture.RequestTexture(textureID, imageType, priority, discardLevel, packetStart, callback, progress); + } + } + + /// + /// Overload: Request a texture asset from the simulator using the system to + /// manage the requests and re-assemble the image from the packets received from the simulator + /// + /// The of the texture asset to download + /// The callback to fire when the image is retrieved. The callback + /// will contain the result of the request and the texture asset data + public void RequestImage(UUID textureID, TextureDownloadCallback callback) + { + RequestImage(textureID, ImageType.Normal, 101300.0f, 0, 0, callback, false); + } + + /// + /// Overload: Request a texture asset from the simulator using the system to + /// manage the requests and re-assemble the image from the packets received from the simulator + /// + /// The of the texture asset to download + /// The of the texture asset. + /// Use for most textures, or for baked layer texture assets + /// The callback to fire when the image is retrieved. The callback + /// will contain the result of the request and the texture asset data + public void RequestImage(UUID textureID, ImageType imageType, TextureDownloadCallback callback) + { + RequestImage(textureID, imageType, 101300.0f, 0, 0, callback, false); + } + + /// + /// Overload: Request a texture asset from the simulator using the system to + /// manage the requests and re-assemble the image from the packets received from the simulator + /// + /// The of the texture asset to download + /// The of the texture asset. + /// Use for most textures, or for baked layer texture assets + /// The callback to fire when the image is retrieved. The callback + /// will contain the result of the request and the texture asset data + /// If true, the callback will be fired for each chunk of the downloaded image. + /// The callback asset parameter will contain all previously received chunks of the texture asset starting + /// from the beginning of the request + public void RequestImage(UUID textureID, ImageType imageType, TextureDownloadCallback callback, bool progress) + { + RequestImage(textureID, imageType, 101300.0f, 0, 0, callback, progress); + } + + /// + /// Cancel a texture request + /// + /// The texture assets + public void RequestImageCancel(UUID textureID) + { + Texture.AbortTextureRequest(textureID); + } + + /// + /// Requests download of a mesh asset + /// + /// UUID of the mesh asset + /// Callback when the request completes + public void RequestMesh(UUID meshID, MeshDownloadCallback callback) + { + if (meshID == UUID.Zero || callback == null) + return; + + if (Client.Network.CurrentSim.Caps != null && + Client.Network.CurrentSim.Caps.CapabilityURI("GetMesh") != null) + { + // Do we have this mesh asset in the cache? + if (Client.Assets.Cache.HasAsset(meshID)) + { + callback(true, new AssetMesh(meshID, Client.Assets.Cache.GetCachedAssetBytes(meshID))); + return; + } + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("GetMesh"); + + DownloadRequest req = new DownloadRequest( + new Uri(string.Format("{0}/?mesh_id={1}", url.ToString(), meshID.ToString())), + Client.Settings.CAPS_TIMEOUT, + null, + null, + (HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) => + { + if (error == null && responseData != null) // success + { + callback(true, new AssetMesh(meshID, responseData)); + Client.Assets.Cache.SaveAssetToCache(meshID, responseData); + } + else // download failed + { + Logger.Log( + string.Format("Failed to fetch mesh asset {0}: {1}", + meshID, + (error == null) ? "" : error.Message + ), + Helpers.LogLevel.Warning, Client); + } + } + ); + + HttpDownloads.QueueDownload(req); + } + else + { + Logger.Log("GetMesh capability not available", Helpers.LogLevel.Error, Client); + callback(false, null); + } + } + + /// + /// Fetach avatar texture on a grid capable of server side baking + /// + /// ID of the avatar + /// ID of the texture + /// Name of the part of the avatar texture applies to + /// Callback invoked on operation completion + public void RequestServerBakedImage(UUID avatarID, UUID textureID, string bakeName, TextureDownloadCallback callback) + { + if (avatarID == UUID.Zero || textureID == UUID.Zero || callback == null) + return; + + if (string.IsNullOrEmpty(Client.Network.AgentAppearanceServiceURL)) + { + callback(TextureRequestState.NotFound, null); + return; + } + + byte[] assetData; + // Do we have this image in the cache? + if (Client.Assets.Cache.HasAsset(textureID) + && (assetData = Client.Assets.Cache.GetCachedAssetBytes(textureID)) != null) + { + ImageDownload image = new ImageDownload(); + image.ID = textureID; + image.AssetData = assetData; + image.Size = image.AssetData.Length; + image.Transferred = image.AssetData.Length; + image.ImageType = ImageType.ServerBaked; + image.AssetType = AssetType.Texture; + image.Success = true; + + callback(TextureRequestState.Finished, new AssetTexture(image.ID, image.AssetData)); + FireImageProgressEvent(image.ID, image.Transferred, image.Size); + return; + } + + CapsBase.DownloadProgressEventHandler progressHandler = null; + + Uri url = new Uri(string.Format("{0}texture/{1}/{2}/{3}", Client.Network.AgentAppearanceServiceURL, avatarID, bakeName, textureID)); + + DownloadRequest req = new DownloadRequest( + url, + Client.Settings.CAPS_TIMEOUT, + "image/x-j2c", + progressHandler, + (HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) => + { + if (error == null && responseData != null) // success + { + ImageDownload image = new ImageDownload(); + image.ID = textureID; + image.AssetData = responseData; + image.Size = image.AssetData.Length; + image.Transferred = image.AssetData.Length; + image.ImageType = ImageType.ServerBaked; + image.AssetType = AssetType.Texture; + image.Success = true; + + callback(TextureRequestState.Finished, new AssetTexture(image.ID, image.AssetData)); + + Client.Assets.Cache.SaveAssetToCache(textureID, responseData); + } + else // download failed + { + Logger.Log( + string.Format("Failed to fetch server bake {0}: {1}", + textureID, + (error == null) ? "" : error.Message + ), + Helpers.LogLevel.Warning, Client); + + callback(TextureRequestState.Timeout, null); + } + } + ); + + HttpDownloads.QueueDownload(req); + + } + + /// + /// Lets TexturePipeline class fire the progress event + /// + /// The texture ID currently being downloaded + /// the number of bytes transferred + /// the total number of bytes expected + internal void FireImageProgressEvent(UUID texureID, int transferredBytes, int totalBytes) + { + try { OnImageReceiveProgress(new ImageReceiveProgressEventArgs(texureID, transferredBytes, totalBytes)); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + + // Helper method for downloading textures via GetTexture cap + // Same signature as the UDP variant since we need all the params to + // pass to the UDP TexturePipeline in case we need to fall back to it + // (Linden servers currently (1.42) don't support bakes downloads via HTTP) + private void HttpRequestTexture(UUID textureID, ImageType imageType, float priority, int discardLevel, + uint packetStart, TextureDownloadCallback callback, bool progress) + { + if (textureID == UUID.Zero || callback == null) + return; + + byte[] assetData; + // Do we have this image in the cache? + if (Client.Assets.Cache.HasAsset(textureID) + && (assetData = Client.Assets.Cache.GetCachedAssetBytes(textureID)) != null) + { + ImageDownload image = new ImageDownload(); + image.ID = textureID; + image.AssetData = assetData; + image.Size = image.AssetData.Length; + image.Transferred = image.AssetData.Length; + image.ImageType = imageType; + image.AssetType = AssetType.Texture; + image.Success = true; + + callback(TextureRequestState.Finished, new AssetTexture(image.ID, image.AssetData)); + FireImageProgressEvent(image.ID, image.Transferred, image.Size); + return; + } + + CapsBase.DownloadProgressEventHandler progressHandler = null; + + if (progress) + { + progressHandler = (HttpWebRequest request, HttpWebResponse response, int bytesReceived, int totalBytesToReceive) => + { + FireImageProgressEvent(textureID, bytesReceived, totalBytesToReceive); + }; + } + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("GetTexture"); + + DownloadRequest req = new DownloadRequest( + new Uri(string.Format("{0}/?texture_id={1}", url.ToString(), textureID.ToString())), + Client.Settings.CAPS_TIMEOUT, + "image/x-j2c", + progressHandler, + (HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) => + { + if (error == null && responseData != null) // success + { + ImageDownload image = new ImageDownload(); + image.ID = textureID; + image.AssetData = responseData; + image.Size = image.AssetData.Length; + image.Transferred = image.AssetData.Length; + image.ImageType = imageType; + image.AssetType = AssetType.Texture; + image.Success = true; + + callback(TextureRequestState.Finished, new AssetTexture(image.ID, image.AssetData)); + FireImageProgressEvent(image.ID, image.Transferred, image.Size); + + Client.Assets.Cache.SaveAssetToCache(textureID, responseData); + } + else // download failed + { + Logger.Log( + string.Format("Failed to fetch texture {0} over HTTP, falling back to UDP: {1}", + textureID, + (error == null) ? "" : error.Message + ), + Helpers.LogLevel.Warning, Client); + + Texture.RequestTexture(textureID, imageType, priority, discardLevel, packetStart, callback, progress); + } + } + ); + + HttpDownloads.QueueDownload(req); + } + + #endregion Texture Downloads + + #region Helpers + + public Asset CreateAssetWrapper(AssetType type) + { + Asset asset; + + switch (type) + { + case AssetType.Notecard: + asset = new AssetNotecard(); + break; + case AssetType.LSLText: + asset = new AssetScriptText(); + break; + case AssetType.LSLBytecode: + asset = new AssetScriptBinary(); + break; + case AssetType.Texture: + asset = new AssetTexture(); + break; + case AssetType.Object: + asset = new AssetPrim(); + break; + case AssetType.Clothing: + asset = new AssetClothing(); + break; + case AssetType.Bodypart: + asset = new AssetBodypart(); + break; + case AssetType.Animation: + asset = new AssetAnimation(); + break; + case AssetType.Sound: + asset = new AssetSound(); + break; + case AssetType.Landmark: + asset = new AssetLandmark(); + break; + case AssetType.Gesture: + asset = new AssetGesture(); + break; + case AssetType.CallingCard: + asset = new AssetCallingCard(); + break; + default: + asset = new AssetMutable(type); + Logger.Log("Unimplemented asset type: " + type, Helpers.LogLevel.Error); + break; + } + + return asset; + } + + private Asset WrapAsset(AssetDownload download) + { + Asset asset = CreateAssetWrapper(download.AssetType); + if (asset != null) + { + asset.AssetID = download.AssetID; + asset.AssetData = download.AssetData; + return asset; + } + else + { + return null; + } + } + + private void SendNextUploadPacket(AssetUpload upload) + { + SendXferPacketPacket send = new SendXferPacketPacket(); + + send.XferID.ID = upload.XferID; + send.XferID.Packet = upload.PacketNum++; + + if (send.XferID.Packet == 0) + { + // The first packet reserves the first four bytes of the data for the + // total length of the asset and appends 1000 bytes of data after that + send.DataPacket.Data = new byte[1004]; + Buffer.BlockCopy(Utils.IntToBytes(upload.Size), 0, send.DataPacket.Data, 0, 4); + Buffer.BlockCopy(upload.AssetData, 0, send.DataPacket.Data, 4, 1000); + upload.Transferred += 1000; + + lock (Transfers) + { + Transfers.Remove(upload.AssetID); + Transfers[upload.ID] = upload; + } + } + else if ((send.XferID.Packet + 1) * 1000 < upload.Size) + { + // This packet is somewhere in the middle of the transfer, or a perfectly + // aligned packet at the end of the transfer + send.DataPacket.Data = new byte[1000]; + Buffer.BlockCopy(upload.AssetData, upload.Transferred, send.DataPacket.Data, 0, 1000); + upload.Transferred += 1000; + } + else + { + // Special handler for the last packet which will be less than 1000 bytes + int lastlen = upload.Size - ((int)send.XferID.Packet * 1000); + send.DataPacket.Data = new byte[lastlen]; + Buffer.BlockCopy(upload.AssetData, (int)send.XferID.Packet * 1000, send.DataPacket.Data, 0, lastlen); + send.XferID.Packet |= (uint)0x80000000; // This signals the final packet + upload.Transferred += lastlen; + } + + Client.Network.SendPacket(send); + } + + private void SendConfirmXferPacket(ulong xferID, uint packetNum) + { + ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket(); + confirm.XferID.ID = xferID; + confirm.XferID.Packet = packetNum; + + Client.Network.SendPacket(confirm); + } + + #endregion Helpers + + #region Transfer Callbacks + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void TransferInfoHandler(object sender, PacketReceivedEventArgs e) + { + TransferInfoPacket info = (TransferInfoPacket)e.Packet; + Transfer transfer; + AssetDownload download; + + if (Transfers.TryGetValue(info.TransferInfo.TransferID, out transfer)) + { + download = (AssetDownload)transfer; + + if (download.Callback == null) return; + + download.Channel = (ChannelType)info.TransferInfo.ChannelType; + download.Status = (StatusCode)info.TransferInfo.Status; + download.Target = (TargetType)info.TransferInfo.TargetType; + download.Size = info.TransferInfo.Size; + + // TODO: Once we support mid-transfer status checking and aborting this + // will need to become smarter + if (download.Status != StatusCode.OK) + { + Logger.Log("Transfer failed with status code " + download.Status, Helpers.LogLevel.Warning, Client); + + lock (Transfers) Transfers.Remove(download.ID); + + // No data could have been received before the TransferInfo packet + download.AssetData = null; + + // Fire the event with our transfer that contains Success = false; + try { download.Callback(download, null); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + else + { + download.AssetData = new byte[download.Size]; + + if (download.Source == SourceType.Asset && info.TransferInfo.Params.Length == 20) + { + download.AssetID = new UUID(info.TransferInfo.Params, 0); + download.AssetType = (AssetType)(sbyte)info.TransferInfo.Params[16]; + + //Client.DebugLog(String.Format("TransferInfo packet received. AssetID: {0} Type: {1}", + // transfer.AssetID, type)); + } + else if (download.Source == SourceType.SimInventoryItem && info.TransferInfo.Params.Length == 100) + { + // TODO: Can we use these? + //UUID agentID = new UUID(info.TransferInfo.Params, 0); + //UUID sessionID = new UUID(info.TransferInfo.Params, 16); + //UUID ownerID = new UUID(info.TransferInfo.Params, 32); + //UUID taskID = new UUID(info.TransferInfo.Params, 48); + //UUID itemID = new UUID(info.TransferInfo.Params, 64); + download.AssetID = new UUID(info.TransferInfo.Params, 80); + download.AssetType = (AssetType)(sbyte)info.TransferInfo.Params[96]; + + //Client.DebugLog(String.Format("TransferInfo packet received. AgentID: {0} SessionID: {1} " + + // "OwnerID: {2} TaskID: {3} ItemID: {4} AssetID: {5} Type: {6}", agentID, sessionID, + // ownerID, taskID, itemID, transfer.AssetID, type)); + } + else + { + Logger.Log("Received a TransferInfo packet with a SourceType of " + download.Source.ToString() + + " and a Params field length of " + info.TransferInfo.Params.Length, + Helpers.LogLevel.Warning, Client); + } + } + download.HeaderReceivedEvent.Set(); + } + else + { + Logger.Log("Received a TransferInfo packet for an asset we didn't request, TransferID: " + + info.TransferInfo.TransferID, Helpers.LogLevel.Warning, Client); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void TransferPacketHandler(object sender, PacketReceivedEventArgs e) + { + TransferPacketPacket asset = (TransferPacketPacket)e.Packet; + Transfer transfer; + + if (Transfers.TryGetValue(asset.TransferData.TransferID, out transfer)) + { + AssetDownload download = (AssetDownload)transfer; + + if (download.Size == 0) + { + Logger.DebugLog("TransferPacket received ahead of the transfer header, blocking...", Client); + + // We haven't received the header yet, block until it's received or times out + download.HeaderReceivedEvent.WaitOne(TRANSFER_HEADER_TIMEOUT, false); + + if (download.Size == 0) + { + Logger.Log("Timed out while waiting for the asset header to download for " + + download.ID.ToString(), Helpers.LogLevel.Warning, Client); + + // Abort the transfer + TransferAbortPacket abort = new TransferAbortPacket(); + abort.TransferInfo.ChannelType = (int)download.Channel; + abort.TransferInfo.TransferID = download.ID; + Client.Network.SendPacket(abort, download.Simulator); + + download.Success = false; + lock (Transfers) Transfers.Remove(download.ID); + + // Fire the event with our transfer that contains Success = false + if (download.Callback != null) + { + try { download.Callback(download, null); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + return; + } + } + + // If packets arrive out of order, we add them to the out of order packet directory + // until all previous packets have arrived + try + { + if (download.nextPacket == asset.TransferData.Packet) + { + byte[] data = asset.TransferData.Data; + do + { + Buffer.BlockCopy(data, 0, download.AssetData, download.Transferred, data.Length); + download.Transferred += data.Length; + download.nextPacket++; + } while (download.outOfOrderPackets.TryGetValue(download.nextPacket, out data)); + } + else + { + //Logger.Log(string.Format("Fixing out of order packet {0} when expecting {1}!", asset.TransferData.Packet, download.nextPacket), Helpers.LogLevel.Debug); + download.outOfOrderPackets.Add(asset.TransferData.Packet, asset.TransferData.Data); + } + } + catch (ArgumentException) + { + Logger.Log(String.Format("TransferPacket handling failed. TransferData.Data.Length={0}, AssetData.Length={1}, TransferData.Packet={2}", + asset.TransferData.Data.Length, download.AssetData.Length, asset.TransferData.Packet), Helpers.LogLevel.Error); + return; + } + + //Client.DebugLog(String.Format("Transfer packet {0}, received {1}/{2}/{3} bytes for asset {4}", + // asset.TransferData.Packet, asset.TransferData.Data.Length, transfer.Transferred, transfer.Size, + // transfer.AssetID.ToString())); + + // Check if we downloaded the full asset + if (download.Transferred >= download.Size) + { + Logger.DebugLog("Transfer for asset " + download.AssetID.ToString() + " completed", Client); + + download.Success = true; + lock (Transfers) Transfers.Remove(download.ID); + + // Cache successful asset download + Cache.SaveAssetToCache(download.AssetID, download.AssetData); + + if (download.Callback != null) + { + try { download.Callback(download, WrapAsset(download)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + } + } + } + + #endregion Transfer Callbacks + + #region Xfer Callbacks + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void InitiateDownloadPacketHandler(object sender, PacketReceivedEventArgs e) + { + InitiateDownloadPacket request = (InitiateDownloadPacket)e.Packet; + try + { + OnInitiateDownload(new InitiateDownloadEventArgs(Utils.BytesToString(request.FileData.SimFilename), + Utils.BytesToString(request.FileData.ViewerFilename))); + } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void RequestXferHandler(object sender, PacketReceivedEventArgs e) + { + if (PendingUpload == null) + Logger.Log("Received a RequestXferPacket for an unknown asset upload", Helpers.LogLevel.Warning, Client); + else + { + AssetUpload upload = PendingUpload; + PendingUpload = null; + WaitingForUploadConfirm = false; + RequestXferPacket request = (RequestXferPacket)e.Packet; + + upload.XferID = request.XferID.ID; + upload.Type = (AssetType)request.XferID.VFileType; + + UUID transferID = new UUID(upload.XferID); + Transfers[transferID] = upload; + + // Send the first packet containing actual asset data + SendNextUploadPacket(upload); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ConfirmXferPacketHandler(object sender, PacketReceivedEventArgs e) + { + ConfirmXferPacketPacket confirm = (ConfirmXferPacketPacket)e.Packet; + + // Building a new UUID every time an ACK is received for an upload is a horrible + // thing, but this whole Xfer system is horrible + UUID transferID = new UUID(confirm.XferID.ID); + Transfer transfer; + AssetUpload upload = null; + + if (Transfers.TryGetValue(transferID, out transfer)) + { + upload = (AssetUpload)transfer; + + //Client.DebugLog(String.Format("ACK for upload {0} of asset type {1} ({2}/{3})", + // upload.AssetID.ToString(), upload.Type, upload.Transferred, upload.Size)); + + try { OnUploadProgress(new AssetUploadEventArgs(upload)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + + if (upload.Transferred < upload.Size) + SendNextUploadPacket(upload); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AssetUploadCompleteHandler(object sender, PacketReceivedEventArgs e) + { + AssetUploadCompletePacket complete = (AssetUploadCompletePacket)e.Packet; + + // If we uploaded an asset in a single packet, RequestXferHandler() + // will never be called so we need to set this here as well + WaitingForUploadConfirm = false; + + if (m_AssetUploadedEvent != null) + { + bool found = false; + KeyValuePair foundTransfer = new KeyValuePair(); + + // Xfer system sucks really really bad. Where is the damn XferID? + lock (Transfers) + { + foreach (KeyValuePair transfer in Transfers) + { + if (transfer.Value.GetType() == typeof(AssetUpload)) + { + AssetUpload upload = (AssetUpload)transfer.Value; + + if ((upload).AssetID == complete.AssetBlock.UUID) + { + found = true; + foundTransfer = transfer; + upload.Success = complete.AssetBlock.Success; + upload.Type = (AssetType)complete.AssetBlock.Type; + break; + } + } + } + } + + if (found) + { + lock (Transfers) Transfers.Remove(foundTransfer.Key); + + try { OnAssetUploaded(new AssetUploadEventArgs((AssetUpload)foundTransfer.Value)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + else + { + Logger.Log(String.Format( + "Got an AssetUploadComplete on an unrecognized asset, AssetID: {0}, Type: {1}, Success: {2}", + complete.AssetBlock.UUID, (AssetType)complete.AssetBlock.Type, complete.AssetBlock.Success), + Helpers.LogLevel.Warning); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void SendXferPacketHandler(object sender, PacketReceivedEventArgs e) + { + SendXferPacketPacket xfer = (SendXferPacketPacket)e.Packet; + + // Lame ulong to UUID conversion, please go away Xfer system + UUID transferID = new UUID(xfer.XferID.ID); + Transfer transfer; + XferDownload download = null; + + if (Transfers.TryGetValue(transferID, out transfer)) + { + download = (XferDownload)transfer; + + // Apply a mask to get rid of the "end of transfer" bit + uint packetNum = xfer.XferID.Packet & 0x0FFFFFFF; + + // Check for out of order packets, possibly indicating a resend + if (packetNum != download.PacketNum) + { + if (packetNum == download.PacketNum - 1) + { + Logger.DebugLog("Resending Xfer download confirmation for packet " + packetNum, Client); + SendConfirmXferPacket(download.XferID, packetNum); + } + else + { + Logger.Log("Out of order Xfer packet in a download, got " + packetNum + " expecting " + download.PacketNum, + Helpers.LogLevel.Warning, Client); + // Re-confirm the last packet we actually received + SendConfirmXferPacket(download.XferID, download.PacketNum - 1); + } + + return; + } + + if (packetNum == 0) + { + // This is the first packet received in the download, the first four bytes are a size integer + // in little endian ordering + byte[] bytes = xfer.DataPacket.Data; + download.Size = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)); + download.AssetData = new byte[download.Size]; + + Logger.DebugLog("Received first packet in an Xfer download of size " + download.Size); + + Buffer.BlockCopy(xfer.DataPacket.Data, 4, download.AssetData, 0, xfer.DataPacket.Data.Length - 4); + download.Transferred += xfer.DataPacket.Data.Length - 4; + } + else + { + Buffer.BlockCopy(xfer.DataPacket.Data, 0, download.AssetData, 1000 * (int)packetNum, xfer.DataPacket.Data.Length); + download.Transferred += xfer.DataPacket.Data.Length; + } + + // Increment the packet number to the packet we are expecting next + download.PacketNum++; + + // Confirm receiving this packet + SendConfirmXferPacket(download.XferID, packetNum); + + if ((xfer.XferID.Packet & 0x80000000) != 0) + { + // This is the last packet in the transfer + if (!String.IsNullOrEmpty(download.Filename)) + Logger.DebugLog("Xfer download for asset " + download.Filename + " completed", Client); + else + Logger.DebugLog("Xfer download for asset " + download.VFileID.ToString() + " completed", Client); + + download.Success = true; + lock (Transfers) Transfers.Remove(download.ID); + + try { OnXferReceived(new XferReceivedEventArgs(download)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AbortXferHandler(object sender, PacketReceivedEventArgs e) + { + AbortXferPacket abort = (AbortXferPacket)e.Packet; + XferDownload download = null; + + // Lame ulong to UUID conversion, please go away Xfer system + UUID transferID = new UUID(abort.XferID.ID); + + lock (Transfers) + { + Transfer transfer; + if (Transfers.TryGetValue(transferID, out transfer)) + { + download = (XferDownload)transfer; + Transfers.Remove(transferID); + } + } + + if (download != null && m_XferReceivedEvent != null) + { + download.Success = false; + download.Error = (TransferError)abort.XferID.Result; + + try { OnXferReceived(new XferReceivedEventArgs(download)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + } + + #endregion Xfer Callbacks + } + #region EventArg classes + // Provides data for XferReceived event + public class XferReceivedEventArgs : EventArgs + { + private readonly XferDownload m_Xfer; + + /// Xfer data + public XferDownload Xfer { get { return m_Xfer; } } + + public XferReceivedEventArgs(XferDownload xfer) + { + this.m_Xfer = xfer; + } + } + + // Provides data for AssetUploaded event + public class AssetUploadEventArgs : EventArgs + { + private readonly AssetUpload m_Upload; + + /// Upload data + public AssetUpload Upload { get { return m_Upload; } } + + public AssetUploadEventArgs(AssetUpload upload) + { + this.m_Upload = upload; + } + } + + // Provides data for InitiateDownloaded event + public class InitiateDownloadEventArgs : EventArgs + { + private readonly string m_SimFileName; + private readonly string m_ViewerFileName; + + /// Filename used on the simulator + public string SimFileName { get { return m_SimFileName; } } + + /// Filename used by the client + public string ViewerFileName { get { return m_ViewerFileName; } } + + public InitiateDownloadEventArgs(string simFilename, string viewerFilename) + { + this.m_SimFileName = simFilename; + this.m_ViewerFileName = viewerFilename; + } + } + + // Provides data for ImageReceiveProgress event + public class ImageReceiveProgressEventArgs : EventArgs + { + private readonly UUID m_ImageID; + private readonly int m_Received; + private readonly int m_Total; + + /// UUID of the image that is in progress + public UUID ImageID { get { return m_ImageID; } } + + /// Number of bytes received so far + public int Received { get { return m_Received; } } + + /// Image size in bytes + public int Total { get { return m_Total; } } + + public ImageReceiveProgressEventArgs(UUID imageID, int received, int total) + { + this.m_ImageID = imageID; + this.m_Received = received; + this.m_Total = total; + } + } + #endregion +} diff --git a/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs b/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs new file mode 100644 index 0000000..1f1f075 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Constants for the archiving module + /// + public class ArchiveConstants + { + /// + /// The location of the archive control file + /// + public static readonly string CONTROL_FILE_PATH = "archive.xml"; + + /// + /// Path for the assets held in an archive + /// + public static readonly string ASSETS_PATH = "assets/"; + + /// + /// Path for the prims file + /// + public static readonly string OBJECTS_PATH = "objects/"; + + /// + /// Path for terrains. Technically these may be assets, but I think it's quite nice to split them out. + /// + public static readonly string TERRAINS_PATH = "terrains/"; + + /// + /// Path for region settings. + /// + public static readonly string SETTINGS_PATH = "settings/"; + + /// + /// Path for region settings. + /// + public const string LANDDATA_PATH = "landdata/"; + + /// + /// The character the separates the uuid from extension information in an archived asset filename + /// + public static readonly string ASSET_EXTENSION_SEPARATOR = "_"; + + /// + /// Extensions used for asset types in the archive + /// + public static readonly IDictionary ASSET_TYPE_TO_EXTENSION = new Dictionary(); + public static readonly IDictionary EXTENSION_TO_ASSET_TYPE = new Dictionary(); + + static ArchiveConstants() + { + ASSET_TYPE_TO_EXTENSION[AssetType.Animation] = ASSET_EXTENSION_SEPARATOR + "animation.bvh"; + ASSET_TYPE_TO_EXTENSION[AssetType.Bodypart] = ASSET_EXTENSION_SEPARATOR + "bodypart.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.CallingCard] = ASSET_EXTENSION_SEPARATOR + "callingcard.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.Clothing] = ASSET_EXTENSION_SEPARATOR + "clothing.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.Folder] = ASSET_EXTENSION_SEPARATOR + "folder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.Gesture] = ASSET_EXTENSION_SEPARATOR + "gesture.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg"; + ASSET_TYPE_TO_EXTENSION[AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga"; + ASSET_TYPE_TO_EXTENSION[AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso"; + ASSET_TYPE_TO_EXTENSION[AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl"; + ASSET_TYPE_TO_EXTENSION[AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml"; + ASSET_TYPE_TO_EXTENSION[AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg"; + ASSET_TYPE_TO_EXTENSION[AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav"; + ASSET_TYPE_TO_EXTENSION[AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2"; + ASSET_TYPE_TO_EXTENSION[AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga"; + ASSET_TYPE_TO_EXTENSION[AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this + + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = AssetType.Animation; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = AssetType.Bodypart; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "callingcard.txt"] = AssetType.CallingCard; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "clothing.txt"] = AssetType.Clothing; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "folder.txt"] = AssetType.Folder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "gesture.txt"] = AssetType.Gesture; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = AssetType.ImageJPEG; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = AssetType.ImageTGA; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = AssetType.Landmark; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = AssetType.LostAndFoundFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = AssetType.LSLBytecode; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = AssetType.LSLText; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = AssetType.Notecard; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = AssetType.Object; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = AssetType.RootFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = AssetType.Simstate; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = AssetType.SnapshotFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = AssetType.Sound; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = AssetType.SoundWAV; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = AssetType.Texture; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = AssetType.TextureTGA; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = AssetType.TrashFolder; + } + } +} diff --git a/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs b/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs new file mode 100644 index 0000000..82a41e9 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Xml; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Archives assets + /// + public class AssetsArchiver + { + ///// + ///// Post a message to the log every x assets as a progress bar + ///// + //static int LOG_ASSET_LOAD_NOTIFICATION_INTERVAL = 50; + + /// + /// Archive assets + /// + protected IDictionary m_assets; + + public AssetsArchiver(IDictionary assets) + { + m_assets = assets; + } + + /// + /// Archive the assets given to this archiver to the given archive. + /// + /// + public void Archive(TarArchiveWriter archive) + { + //WriteMetadata(archive); + WriteData(archive); + } + + /// + /// Write an assets metadata file to the given archive + /// + /// + protected void WriteMetadata(TarArchiveWriter archive) + { + StringWriter sw = new StringWriter(); + using (XmlTextWriter xtw = new XmlTextWriter(sw)) + { + xtw.Formatting = Formatting.Indented; + xtw.WriteStartDocument(); + + xtw.WriteStartElement("assets"); + + foreach (UUID uuid in m_assets.Keys) + { + Asset asset = m_assets[uuid]; + + if (asset != null) + { + xtw.WriteStartElement("asset"); + + string extension = string.Empty; + + if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.AssetType)) + { + extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.AssetType]; + } + + xtw.WriteElementString("filename", uuid.ToString() + extension); + + xtw.WriteElementString("name", uuid.ToString()); + xtw.WriteElementString("description", String.Empty); + xtw.WriteElementString("asset-type", asset.AssetType.ToString()); + + xtw.WriteEndElement(); + } + } + + xtw.WriteEndElement(); + xtw.WriteEndDocument(); + archive.WriteFile("assets.xml", sw.ToString()); + } + } + + /// + /// Write asset data files to the given archive + /// + /// + protected void WriteData(TarArchiveWriter archive) + { + // It appears that gtar, at least, doesn't need the intermediate directory entries in the tar + //archive.AddDir("assets"); + + int assetsAdded = 0; + + foreach (UUID uuid in m_assets.Keys) + { + Asset asset = m_assets[uuid]; + + string extension = string.Empty; + + if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.AssetType)) + { + extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.AssetType]; + } + else + { + Logger.Log(String.Format( + "Unrecognized asset type {0} with uuid {1}. This asset will be saved but not reloaded", + asset.AssetType, asset.AssetID), Helpers.LogLevel.Warning); + } + + asset.Encode(); + + archive.WriteFile( + ArchiveConstants.ASSETS_PATH + uuid.ToString() + extension, + asset.AssetData); + + assetsAdded++; + } + } + } +} diff --git a/OpenMetaverse/Assets/Archiving/OarFile.cs b/OpenMetaverse/Assets/Archiving/OarFile.cs new file mode 100644 index 0000000..76dbf19 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/OarFile.cs @@ -0,0 +1,879 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Xml; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + public static class OarFile + { + public delegate void AssetLoadedCallback(Asset asset, long bytesRead, long totalBytes); + public delegate void TerrainLoadedCallback(float[,] terrain, long bytesRead, long totalBytes); + public delegate void SceneObjectLoadedCallback(AssetPrim linkset, long bytesRead, long totalBytes); + public delegate void SettingsLoadedCallback(string regionName, RegionSettings settings); + + #region Archive Loading + + public static void UnpackageArchive(string filename, AssetLoadedCallback assetCallback, TerrainLoadedCallback terrainCallback, + SceneObjectLoadedCallback objectCallback, SettingsLoadedCallback settingsCallback) + { + int successfulAssetRestores = 0; + int failedAssetRestores = 0; + + try + { + using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) + { + using (GZipStream loadStream = new GZipStream(fileStream, CompressionMode.Decompress)) + { + TarArchiveReader archive = new TarArchiveReader(loadStream); + + string filePath; + byte[] data; + TarArchiveReader.TarEntryType entryType; + + while ((data = archive.ReadEntry(out filePath, out entryType)) != null) + { + if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) + { + // Deserialize the XML bytes + if (objectCallback != null) + LoadObjects(data, objectCallback, fileStream.Position, fileStream.Length); + } + else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + { + if (assetCallback != null) + { + if (LoadAsset(filePath, data, assetCallback, fileStream.Position, fileStream.Length)) + successfulAssetRestores++; + else + failedAssetRestores++; + } + } + else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) + { + if (terrainCallback != null) + LoadTerrain(filePath, data, terrainCallback, fileStream.Position, fileStream.Length); + } + else if (filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) + { + if (settingsCallback != null) + LoadRegionSettings(filePath, data, settingsCallback); + } + } + + archive.Close(); + } + } + } + catch (Exception e) + { + Logger.Log("[OarFile] Error loading OAR file: " + e.Message, Helpers.LogLevel.Error); + return; + } + + if (failedAssetRestores > 0) + Logger.Log(String.Format("[OarFile]: Failed to load {0} assets", failedAssetRestores), Helpers.LogLevel.Warning); + } + + private static bool LoadAsset(string assetPath, byte[] data, AssetLoadedCallback assetCallback, long bytesRead, long totalBytes) + { + // Right now we're nastily obtaining the UUID from the filename + string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); + int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR); + + if (i == -1) + { + Logger.Log(String.Format( + "[OarFile]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping", + assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR), Helpers.LogLevel.Warning); + return false; + } + + string extension = filename.Substring(i); + UUID uuid; + UUID.TryParse(filename.Remove(filename.Length - extension.Length), out uuid); + + if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) + { + AssetType assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; + Asset asset = null; + + switch (assetType) + { + case AssetType.Animation: + asset = new AssetAnimation(uuid, data); + break; + case AssetType.Bodypart: + asset = new AssetBodypart(uuid, data); + break; + case AssetType.Clothing: + asset = new AssetClothing(uuid, data); + break; + case AssetType.Gesture: + asset = new AssetGesture(uuid, data); + break; + case AssetType.Landmark: + asset = new AssetLandmark(uuid, data); + break; + case AssetType.LSLBytecode: + asset = new AssetScriptBinary(uuid, data); + break; + case AssetType.LSLText: + asset = new AssetScriptText(uuid, data); + break; + case AssetType.Notecard: + asset = new AssetNotecard(uuid, data); + break; + case AssetType.Object: + asset = new AssetPrim(uuid, data); + break; + case AssetType.Sound: + asset = new AssetSound(uuid, data); + break; + case AssetType.Texture: + asset = new AssetTexture(uuid, data); + break; + default: + Logger.Log("[OarFile] Unhandled asset type " + assetType, Helpers.LogLevel.Error); + break; + } + + if (asset != null) + { + assetCallback(asset, bytesRead, totalBytes); + return true; + } + } + + Logger.Log("[OarFile] Failed to load asset", Helpers.LogLevel.Warning); + return false; + } + + private static bool LoadRegionSettings(string filePath, byte[] data, SettingsLoadedCallback settingsCallback) + { + RegionSettings settings = null; + bool loaded = false; + + try + { + using (MemoryStream stream = new MemoryStream(data)) + settings = RegionSettings.FromStream(stream); + loaded = true; + } + catch (Exception ex) + { + Logger.Log("[OarFile] Failed to parse region settings file " + filePath + ": " + ex.Message, Helpers.LogLevel.Warning); + } + + // Parse the region name out of the filename + string regionName = Path.GetFileNameWithoutExtension(filePath); + + if (loaded) + settingsCallback(regionName, settings); + + return loaded; + } + + private static bool LoadTerrain(string filePath, byte[] data, TerrainLoadedCallback terrainCallback, long bytesRead, long totalBytes) + { + float[,] terrain = new float[256, 256]; + bool loaded = false; + + switch (Path.GetExtension(filePath)) + { + case ".r32": + case ".f32": + // RAW32 + if (data.Length == 256 * 256 * 4) + { + int pos = 0; + for (int y = 0; y < 256; y++) + { + for (int x = 0; x < 256; x++) + { + terrain[y, x] = Utils.Clamp(Utils.BytesToFloat(data, pos), 0.0f, 255.0f); + pos += 4; + } + } + + loaded = true; + } + else + { + Logger.Log("[OarFile] RAW32 terrain file " + filePath + " has the wrong number of bytes: " + data.Length, + Helpers.LogLevel.Warning); + } + break; + case ".ter": + // Terragen + case ".raw": + // LLRAW + case ".jpg": + case ".jpeg": + // JPG + case ".bmp": + // BMP + case ".png": + // PNG + case ".gif": + // GIF + case ".tif": + case ".tiff": + // TIFF + default: + Logger.Log("[OarFile] Unrecognized terrain format in " + filePath, Helpers.LogLevel.Warning); + break; + } + + if (loaded) + terrainCallback(terrain, bytesRead, totalBytes); + + return loaded; + } + + public static void LoadObjects(byte[] objectData, SceneObjectLoadedCallback objectCallback, long bytesRead, long totalBytes) + { + XmlDocument doc = new XmlDocument(); + + using (XmlTextReader reader = new XmlTextReader(new MemoryStream(objectData))) + { + reader.WhitespaceHandling = WhitespaceHandling.None; + doc.Load(reader); + } + + XmlNode rootNode = doc.FirstChild; + + if (rootNode.LocalName.Equals("scene")) + { + foreach (XmlNode node in rootNode.ChildNodes) + { + AssetPrim linkset = new AssetPrim(node.OuterXml); + if (linkset != null) + objectCallback(linkset, bytesRead, totalBytes); + } + } + else + { + AssetPrim linkset = new AssetPrim(rootNode.OuterXml); + if (linkset != null) + objectCallback(linkset, bytesRead, totalBytes); + } + } + + #endregion Archive Loading + + #region Archive Saving + + public static void PackageArchive(string directoryName, string filename) + { + const string ARCHIVE_XML = "\n"; + + TarArchiveWriter archive = new TarArchiveWriter(new GZipStream(new FileStream(filename, FileMode.Create), CompressionMode.Compress)); + + // Create the archive.xml file + archive.WriteFile("archive.xml", ARCHIVE_XML); + + // Add the assets + string[] files = Directory.GetFiles(directoryName + "/" + ArchiveConstants.ASSETS_PATH); + foreach (string file in files) + archive.WriteFile(ArchiveConstants.ASSETS_PATH + Path.GetFileName(file), File.ReadAllBytes(file)); + + // Add the objects + files = Directory.GetFiles(directoryName + "/" + ArchiveConstants.OBJECTS_PATH); + foreach (string file in files) + archive.WriteFile(ArchiveConstants.OBJECTS_PATH + Path.GetFileName(file), File.ReadAllBytes(file)); + + // Add the terrain(s) + files = Directory.GetFiles(directoryName + "/" + ArchiveConstants.TERRAINS_PATH); + foreach (string file in files) + archive.WriteFile(ArchiveConstants.TERRAINS_PATH + Path.GetFileName(file), File.ReadAllBytes(file)); + + // Add the parcels(s) + files = Directory.GetFiles(directoryName + "/" + ArchiveConstants.LANDDATA_PATH); + foreach (string file in files) + archive.WriteFile(ArchiveConstants.LANDDATA_PATH + Path.GetFileName(file), File.ReadAllBytes(file)); + + // Add the setting(s) + files = Directory.GetFiles(directoryName + "/" + ArchiveConstants.SETTINGS_PATH); + foreach (string file in files) + archive.WriteFile(ArchiveConstants.SETTINGS_PATH + Path.GetFileName(file), File.ReadAllBytes(file)); + + archive.Close(); + } + + public static void SaveTerrain(Simulator sim, string terrainPath) + { + if (Directory.Exists(terrainPath)) + Directory.Delete(terrainPath, true); + Thread.Sleep(100); + Directory.CreateDirectory(terrainPath); + Thread.Sleep(100); + FileInfo file = new FileInfo(Path.Combine(terrainPath, sim.Name + ".r32")); + FileStream s = file.Open(FileMode.Create, FileAccess.Write); + SaveTerrainStream(s, sim); + + s.Close(); + } + + private static void SaveTerrainStream(Stream s, Simulator sim) + { + BinaryWriter bs = new BinaryWriter(s); + + int y; + for (y = 0; y < 256; y++) + { + int x; + for (x = 0; x < 256; x++) + { + float height; + sim.TerrainHeightAtPoint(x, y, out height); + bs.Write(height); + } + } + + bs.Close(); + } + + public static void SaveParcels(Simulator sim, string parcelPath) + { + if (Directory.Exists(parcelPath)) + Directory.Delete(parcelPath, true); + Thread.Sleep(100); + Directory.CreateDirectory(parcelPath); + Thread.Sleep(100); + sim.Parcels.ForEach((Parcel parcel) => + { + UUID globalID = UUID.Random(); + SerializeParcel(parcel, globalID, Path.Combine(parcelPath, globalID + ".xml")); + }); + } + + private static void SerializeParcel(Parcel parcel, UUID globalID, string filename) + { + StringWriter sw = new StringWriter(); + XmlTextWriter xtw = new XmlTextWriter(sw) { Formatting = Formatting.Indented }; + + xtw.WriteStartDocument(); + xtw.WriteStartElement("LandData"); + + xtw.WriteElementString("Area", Convert.ToString(parcel.Area)); + xtw.WriteElementString("AuctionID", Convert.ToString(parcel.AuctionID)); + xtw.WriteElementString("AuthBuyerID", parcel.AuthBuyerID.ToString()); + xtw.WriteElementString("Category", Convert.ToString((sbyte)parcel.Category)); + TimeSpan t = parcel.ClaimDate.ToUniversalTime() - Utils.Epoch; + xtw.WriteElementString("ClaimDate", Convert.ToString((int)t.TotalSeconds)); + xtw.WriteElementString("ClaimPrice", Convert.ToString(parcel.ClaimPrice)); + xtw.WriteElementString("GlobalID", globalID.ToString()); + xtw.WriteElementString("GroupID", parcel.GroupID.ToString()); + xtw.WriteElementString("IsGroupOwned", Convert.ToString(parcel.IsGroupOwned)); + xtw.WriteElementString("Bitmap", Convert.ToBase64String(parcel.Bitmap)); + xtw.WriteElementString("Description", parcel.Desc); + xtw.WriteElementString("Flags", Convert.ToString((uint)parcel.Flags)); + xtw.WriteElementString("LandingType", Convert.ToString((byte)parcel.Landing)); + xtw.WriteElementString("Name", parcel.Name); + xtw.WriteElementString("Status", Convert.ToString((sbyte)parcel.Status)); + xtw.WriteElementString("LocalID", parcel.LocalID.ToString()); + xtw.WriteElementString("MediaAutoScale", Convert.ToString(parcel.Media.MediaAutoScale ? 1 : 0)); + xtw.WriteElementString("MediaID", parcel.Media.MediaID.ToString()); + xtw.WriteElementString("MediaURL", parcel.Media.MediaURL); + xtw.WriteElementString("MusicURL", parcel.MusicURL); + xtw.WriteElementString("OwnerID", parcel.OwnerID.ToString()); + + xtw.WriteStartElement("ParcelAccessList"); + foreach (ParcelManager.ParcelAccessEntry pal in parcel.AccessBlackList) + { + xtw.WriteStartElement("ParcelAccessEntry"); + xtw.WriteElementString("AgentID", pal.AgentID.ToString()); + xtw.WriteElementString("Time", pal.Time.ToString("s")); + xtw.WriteElementString("AccessList", Convert.ToString((uint)pal.Flags)); + xtw.WriteEndElement(); + } + foreach (ParcelManager.ParcelAccessEntry pal in parcel.AccessWhiteList) + { + xtw.WriteStartElement("ParcelAccessEntry"); + xtw.WriteElementString("AgentID", pal.AgentID.ToString()); + xtw.WriteElementString("Time", pal.Time.ToString("s")); + xtw.WriteElementString("AccessList", Convert.ToString((uint)pal.Flags)); + xtw.WriteEndElement(); + } + xtw.WriteEndElement(); + + xtw.WriteElementString("PassHours", Convert.ToString(parcel.PassHours)); + xtw.WriteElementString("PassPrice", Convert.ToString(parcel.PassPrice)); + xtw.WriteElementString("SalePrice", Convert.ToString(parcel.SalePrice)); + xtw.WriteElementString("SnapshotID", parcel.SnapshotID.ToString()); + xtw.WriteElementString("UserLocation", parcel.UserLocation.ToString()); + xtw.WriteElementString("UserLookAt", parcel.UserLookAt.ToString()); + xtw.WriteElementString("Dwell", "0"); + xtw.WriteElementString("OtherCleanTime", Convert.ToString(parcel.OtherCleanTime)); + + xtw.WriteEndElement(); + + xtw.Close(); + sw.Close(); + File.WriteAllText(filename, sw.ToString()); + } + + public static void SaveRegionSettings(Simulator sim, string settingsPath) + { + if (Directory.Exists(settingsPath)) + Directory.Delete(settingsPath, true); + Thread.Sleep(100); + Directory.CreateDirectory(settingsPath); + Thread.Sleep(100); + + RegionSettings settings = new RegionSettings(); + //settings.AgentLimit; + settings.AllowDamage = (sim.Flags & RegionFlags.AllowDamage) == RegionFlags.AllowDamage; + //settings.AllowLandJoinDivide; + settings.AllowLandResell = (sim.Flags & RegionFlags.BlockLandResell) != RegionFlags.BlockLandResell; + settings.BlockFly = (sim.Flags & RegionFlags.NoFly) == RegionFlags.NoFly; + settings.BlockLandShowInSearch = (sim.Flags & RegionFlags.BlockParcelSearch) == RegionFlags.BlockParcelSearch; + settings.BlockTerraform = (sim.Flags & RegionFlags.BlockTerraform) == RegionFlags.BlockTerraform; + settings.DisableCollisions = (sim.Flags & RegionFlags.SkipCollisions) == RegionFlags.SkipCollisions; + settings.DisablePhysics = (sim.Flags & RegionFlags.SkipPhysics) == RegionFlags.SkipPhysics; + settings.DisableScripts = (sim.Flags & RegionFlags.SkipScripts) == RegionFlags.SkipScripts; + settings.FixedSun = (sim.Flags & RegionFlags.SunFixed) == RegionFlags.SunFixed; + settings.MaturityRating = (int)(sim.Access & SimAccess.Mature & SimAccess.Adult & SimAccess.PG); + //settings.ObjectBonus; + settings.RestrictPushing = (sim.Flags & RegionFlags.RestrictPushObject) == RegionFlags.RestrictPushObject; + settings.TerrainDetail0 = sim.TerrainDetail0; + settings.TerrainDetail1 = sim.TerrainDetail1; + settings.TerrainDetail2 = sim.TerrainDetail2; + settings.TerrainDetail3 = sim.TerrainDetail3; + settings.TerrainHeightRange00 = sim.TerrainHeightRange00; + settings.TerrainHeightRange01 = sim.TerrainHeightRange01; + settings.TerrainHeightRange10 = sim.TerrainHeightRange10; + settings.TerrainHeightRange11 = sim.TerrainHeightRange11; + settings.TerrainStartHeight00 = sim.TerrainStartHeight00; + settings.TerrainStartHeight01 = sim.TerrainStartHeight01; + settings.TerrainStartHeight10 = sim.TerrainStartHeight10; + settings.TerrainStartHeight11 = sim.TerrainStartHeight11; + //settings.UseEstateSun; + settings.WaterHeight = sim.WaterHeight; + + settings.ToXML(Path.Combine(settingsPath, sim.Name + ".xml")); + } + + public static void SavePrims(AssetManager manager, IList prims, string primsPath, string assetsPath) + { + Dictionary textureList = new Dictionary(); + + // Delete all of the old linkset files + try { Directory.Delete(primsPath, true); } + catch (Exception) { } + + Thread.Sleep(100); + // Create a new folder for the linkset files + try { Directory.CreateDirectory(primsPath); } + catch (Exception ex) + { + Logger.Log("Failed saving prims: " + ex.Message, Helpers.LogLevel.Error); + return; + } + Thread.Sleep(100); + try + { + foreach (AssetPrim assetPrim in prims) + { + SavePrim(assetPrim, Path.Combine(primsPath, "Primitive_" + assetPrim.Parent.ID + ".xml")); + + CollectTextures(assetPrim.Parent, textureList); + if (assetPrim.Children != null) + { + foreach (PrimObject child in assetPrim.Children) + CollectTextures(child, textureList); + } + } + + SaveAssets(manager, AssetType.Texture, new List(textureList.Keys), assetsPath); + } + catch + { + } + } + + static void CollectTextures(PrimObject prim, Dictionary textureList) + { + if (prim.Textures != null) + { + // Add all of the textures on this prim to the save list + if (prim.Textures.DefaultTexture != null) + textureList[prim.Textures.DefaultTexture.TextureID] = prim.Textures.DefaultTexture.TextureID; + + if (prim.Textures.FaceTextures != null) + { + for (int i = 0; i < prim.Textures.FaceTextures.Length; i++) + { + Primitive.TextureEntryFace face = prim.Textures.FaceTextures[i]; + if (face != null) + textureList[face.TextureID] = face.TextureID; + } + } + if(prim.Sculpt != null && prim.Sculpt.Texture != UUID.Zero) + textureList[prim.Sculpt.Texture] = prim.Sculpt.Texture; + } + } + + public static void ClearAssetFolder(string assetsPath) + { + // Delete the assets folder + try { Directory.Delete(assetsPath, true); } + catch (Exception) { } + Thread.Sleep(100); + + // Create a new assets folder + try { Directory.CreateDirectory(assetsPath); } + catch (Exception ex) + { + Logger.Log("Failed saving assets: " + ex.Message, Helpers.LogLevel.Error); + return; + } + Thread.Sleep(100); + } + + public static void SaveAssets(AssetManager assetManager, AssetType assetType, IList assets, string assetsPath) + { + int count = 0; + + List remainingTextures = new List(assets); + AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); + for (int i = 0; i < assets.Count; i++) + { + UUID texture = assets[i]; + if(assetType == AssetType.Texture) + { + assetManager.RequestImage(texture, (state, assetTexture) => + { + string extension = string.Empty; + + if (assetTexture == null) + { + Console.WriteLine("Missing asset " + texture); + return; + } + + if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(assetType)) + extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[assetType]; + + File.WriteAllBytes(Path.Combine(assetsPath, texture.ToString() + extension), assetTexture.AssetData); + remainingTextures.Remove(assetTexture.AssetID); + if (remainingTextures.Count == 0) + AllPropertiesReceived.Set(); + ++count; + }); + } + else + { + assetManager.RequestAsset(texture, assetType, false, (transfer, asset) => + { + string extension = string.Empty; + + if (asset == null) + { + Console.WriteLine("Missing asset " + texture); + return; + } + + if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(assetType)) + extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[assetType]; + + File.WriteAllBytes(Path.Combine(assetsPath, texture.ToString() + extension), asset.AssetData); + remainingTextures.Remove(asset.AssetID); + if (remainingTextures.Count == 0) + AllPropertiesReceived.Set(); + ++count; + }); + } + + Thread.Sleep(200); + if (i % 5 == 0) + Thread.Sleep(250); + } + AllPropertiesReceived.WaitOne(5000 + 350 * assets.Count); + + Logger.Log("Copied " + count + " textures to the asset archive folder", Helpers.LogLevel.Info); + } + + public static void SaveSimAssets(AssetManager assetManager, AssetType assetType, UUID assetID, UUID itemID, UUID primID, string assetsPath) + { + int count = 0; + + AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); + assetManager.RequestAsset(assetID, itemID, primID, assetType, false, SourceType.SimInventoryItem, UUID.Random(), (transfer, asset) => + { + string extension = string.Empty; + + if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(assetType)) + extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[assetType]; + + if (asset == null) + { + AllPropertiesReceived.Set(); + return; + } + File.WriteAllBytes(Path.Combine(assetsPath, assetID.ToString() + extension), asset.AssetData); + ++count; + AllPropertiesReceived.Set(); + }); + AllPropertiesReceived.WaitOne(5000); + + Logger.Log("Copied " + count + " textures to the asset archive folder", Helpers.LogLevel.Info); + } + + static void SavePrim(AssetPrim prim, string filename) + { + try + { + using (StreamWriter stream = new StreamWriter(filename)) + { + XmlTextWriter writer = new XmlTextWriter(stream); + writer.Formatting = Formatting.Indented; + writer.Indentation = 4; + writer.IndentChar = ' '; + SOGToXml2(writer, prim); + writer.Flush(); + } + } + catch (Exception ex) + { + Logger.Log("Failed saving linkset: " + ex.Message, Helpers.LogLevel.Error); + } + } + + public static void SOGToXml2(XmlTextWriter writer, AssetPrim prim) + { + writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); + SOPToXml(writer, prim.Parent, null); + writer.WriteStartElement(String.Empty, "OtherParts", String.Empty); + + foreach (PrimObject child in prim.Children) + SOPToXml(writer, child, prim.Parent); + + writer.WriteEndElement(); + writer.WriteEndElement(); + } + + static void SOPToXml(XmlTextWriter writer, PrimObject prim, PrimObject parent) + { + writer.WriteStartElement("SceneObjectPart"); + writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + writer.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); + + WriteUUID(writer, "CreatorID", prim.CreatorID); + WriteUUID(writer, "FolderID", prim.FolderID); + writer.WriteElementString("InventorySerial", (prim.Inventory != null) ? prim.Inventory.Serial.ToString() : "0"); + + // FIXME: Task inventory + writer.WriteStartElement("TaskInventory"); + if (prim.Inventory != null) + { + foreach (PrimObject.InventoryBlock.ItemBlock item in prim.Inventory.Items) + { + writer.WriteStartElement("", "TaskInventoryItem", ""); + + WriteUUID(writer, "AssetID", item.AssetID); + writer.WriteElementString("BasePermissions", item.PermsBase.ToString()); + writer.WriteElementString("CreationDate", (item.CreationDate.ToUniversalTime() - Utils.Epoch).TotalSeconds.ToString()); + WriteUUID(writer, "CreatorID", item.CreatorID); + writer.WriteElementString("Description", item.Description); + writer.WriteElementString("EveryonePermissions", item.PermsEveryone.ToString()); + writer.WriteElementString("Flags", item.Flags.ToString()); + WriteUUID(writer, "GroupID", item.GroupID); + writer.WriteElementString("GroupPermissions", item.PermsGroup.ToString()); + writer.WriteElementString("InvType", ((int)item.InvType).ToString()); + WriteUUID(writer, "ItemID", item.ID); + WriteUUID(writer, "OldItemID", UUID.Zero); + WriteUUID(writer, "LastOwnerID", item.LastOwnerID); + writer.WriteElementString("Name", item.Name); + writer.WriteElementString("NextPermissions", item.PermsNextOwner.ToString()); + WriteUUID(writer, "OwnerID", item.OwnerID); + writer.WriteElementString("CurrentPermissions", item.PermsOwner.ToString()); + WriteUUID(writer, "ParentID", prim.ID); + WriteUUID(writer, "ParentPartID", prim.ID); + WriteUUID(writer, "PermsGranter", item.PermsGranterID); + writer.WriteElementString("PermsMask", "0"); + writer.WriteElementString("Type", ((int)item.Type).ToString()); + writer.WriteElementString("OwnerChanged", "false"); + + writer.WriteEndElement(); + } + } + writer.WriteEndElement(); + + PrimFlags flags = PrimFlags.None; + if (prim.UsePhysics) flags |= PrimFlags.Physics; + if (prim.Phantom) flags |= PrimFlags.Phantom; + if (prim.DieAtEdge) flags |= PrimFlags.DieAtEdge; + if (prim.ReturnAtEdge) flags |= PrimFlags.ReturnAtEdge; + if (prim.Temporary) flags |= PrimFlags.Temporary; + if (prim.Sandbox) flags |= PrimFlags.Sandbox; + writer.WriteElementString("ObjectFlags", ((int)flags).ToString()); + + WriteUUID(writer, "UUID", prim.ID); + writer.WriteElementString("LocalId", prim.LocalID.ToString()); + writer.WriteElementString("Name", prim.Name); + writer.WriteElementString("Material", ((int)prim.Material).ToString()); + writer.WriteElementString("RegionHandle", prim.RegionHandle.ToString()); + writer.WriteElementString("ScriptAccessPin", prim.RemoteScriptAccessPIN.ToString()); + + Vector3 groupPosition; + if (parent == null) + groupPosition = prim.Position; + else + groupPosition = parent.Position; + + WriteVector(writer, "GroupPosition", groupPosition); + if (prim.ParentID == 0) + WriteVector(writer, "OffsetPosition", Vector3.Zero); + else + WriteVector(writer, "OffsetPosition", prim.Position); + WriteQuaternion(writer, "RotationOffset", prim.Rotation); + WriteVector(writer, "Velocity", prim.Velocity); + WriteVector(writer, "RotationalVelocity", Vector3.Zero); + WriteVector(writer, "AngularVelocity", prim.AngularVelocity); + WriteVector(writer, "Acceleration", prim.Acceleration); + writer.WriteElementString("Description", prim.Description); + writer.WriteStartElement("Color"); + writer.WriteElementString("R", prim.TextColor.R.ToString(Utils.EnUsCulture)); + writer.WriteElementString("G", prim.TextColor.G.ToString(Utils.EnUsCulture)); + writer.WriteElementString("B", prim.TextColor.B.ToString(Utils.EnUsCulture)); + writer.WriteElementString("A", prim.TextColor.G.ToString(Utils.EnUsCulture)); + writer.WriteEndElement(); + writer.WriteElementString("Text", prim.Text); + writer.WriteElementString("SitName", prim.SitName); + writer.WriteElementString("TouchName", prim.TouchName); + + writer.WriteElementString("LinkNum", prim.LinkNumber.ToString()); + writer.WriteElementString("ClickAction", prim.ClickAction.ToString()); + writer.WriteStartElement("Shape"); + + writer.WriteElementString("PathBegin", Primitive.PackBeginCut(prim.Shape.PathBegin).ToString()); + writer.WriteElementString("PathCurve", prim.Shape.PathCurve.ToString()); + writer.WriteElementString("PathEnd", Primitive.PackEndCut(prim.Shape.PathEnd).ToString()); + writer.WriteElementString("PathRadiusOffset", Primitive.PackPathTwist(prim.Shape.PathRadiusOffset).ToString()); + writer.WriteElementString("PathRevolutions", Primitive.PackPathRevolutions(prim.Shape.PathRevolutions).ToString()); + writer.WriteElementString("PathScaleX", Primitive.PackPathScale(prim.Shape.PathScaleX).ToString()); + writer.WriteElementString("PathScaleY", Primitive.PackPathScale(prim.Shape.PathScaleY).ToString()); + writer.WriteElementString("PathShearX", ((byte)Primitive.PackPathShear(prim.Shape.PathShearX)).ToString()); + writer.WriteElementString("PathShearY", ((byte)Primitive.PackPathShear(prim.Shape.PathShearY)).ToString()); + writer.WriteElementString("PathSkew", Primitive.PackPathTwist(prim.Shape.PathSkew).ToString()); + writer.WriteElementString("PathTaperX", Primitive.PackPathTaper(prim.Shape.PathTaperX).ToString()); + writer.WriteElementString("PathTaperY", Primitive.PackPathTaper(prim.Shape.PathTaperY).ToString()); + writer.WriteElementString("PathTwist", Primitive.PackPathTwist(prim.Shape.PathTwist).ToString()); + writer.WriteElementString("PathTwistBegin", Primitive.PackPathTwist(prim.Shape.PathTwistBegin).ToString()); + writer.WriteElementString("PCode", prim.PCode.ToString()); + writer.WriteElementString("ProfileBegin", Primitive.PackBeginCut(prim.Shape.ProfileBegin).ToString()); + writer.WriteElementString("ProfileEnd", Primitive.PackEndCut(prim.Shape.ProfileEnd).ToString()); + writer.WriteElementString("ProfileHollow", Primitive.PackProfileHollow(prim.Shape.ProfileHollow).ToString()); + WriteVector(writer, "Scale", prim.Scale); + writer.WriteElementString("State", prim.State.ToString()); + + AssetPrim.ProfileShape shape = (AssetPrim.ProfileShape)(prim.Shape.ProfileCurve & 0x0F); + HoleType hole = (HoleType)(prim.Shape.ProfileCurve & 0xF0); + writer.WriteElementString("ProfileShape", shape.ToString()); + writer.WriteElementString("HollowShape", hole.ToString()); + writer.WriteElementString("ProfileCurve", prim.Shape.ProfileCurve.ToString()); + + writer.WriteStartElement("TextureEntry"); + + byte[] te; + if (prim.Textures != null) + te = prim.Textures.GetBytes(); + else + te = Utils.EmptyBytes; + + writer.WriteBase64(te, 0, te.Length); + writer.WriteEndElement(); + + // FIXME: ExtraParams + writer.WriteStartElement("ExtraParams"); writer.WriteEndElement(); + + writer.WriteEndElement(); + + WriteVector(writer, "Scale", prim.Scale); + writer.WriteElementString("UpdateFlag", "0"); + WriteVector(writer, "SitTargetOrientation", Vector3.UnitZ); // TODO: Is this really a vector and not a quaternion? + WriteVector(writer, "SitTargetPosition", prim.SitOffset); + WriteVector(writer, "SitTargetPositionLL", prim.SitOffset); + WriteQuaternion(writer, "SitTargetOrientationLL", prim.SitRotation); + writer.WriteElementString("ParentID", prim.ParentID.ToString()); + writer.WriteElementString("CreationDate", ((int)Utils.DateTimeToUnixTime(prim.CreationDate)).ToString()); + writer.WriteElementString("Category", "0"); + writer.WriteElementString("SalePrice", prim.SalePrice.ToString()); + writer.WriteElementString("ObjectSaleType", ((int)prim.SaleType).ToString()); + writer.WriteElementString("OwnershipCost", "0"); + WriteUUID(writer, "GroupID", prim.GroupID); + WriteUUID(writer, "OwnerID", prim.OwnerID); + WriteUUID(writer, "LastOwnerID", prim.LastOwnerID); + writer.WriteElementString("BaseMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("OwnerMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("GroupMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("EveryoneMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("NextOwnerMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("Flags", "None"); + WriteUUID(writer, "SitTargetAvatar", UUID.Zero); + + writer.WriteEndElement(); + } + + static void WriteUUID(XmlTextWriter writer, string name, UUID id) + { + writer.WriteStartElement(name); + writer.WriteElementString("UUID", id.ToString()); + writer.WriteEndElement(); + } + + static void WriteVector(XmlTextWriter writer, string name, Vector3 vec) + { + writer.WriteStartElement(name); + writer.WriteElementString("X", vec.X.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Y", vec.Y.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Z", vec.Z.ToString(Utils.EnUsCulture)); + writer.WriteEndElement(); + } + + static void WriteQuaternion(XmlTextWriter writer, string name, Quaternion quat) + { + writer.WriteStartElement(name); + writer.WriteElementString("X", quat.X.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Y", quat.Y.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Z", quat.Z.ToString(Utils.EnUsCulture)); + writer.WriteElementString("W", quat.W.ToString(Utils.EnUsCulture)); + writer.WriteEndElement(); + } + + #endregion Archive Saving + } +} diff --git a/OpenMetaverse/Assets/Archiving/RegionSettings.cs b/OpenMetaverse/Assets/Archiving/RegionSettings.cs new file mode 100644 index 0000000..24a976b --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/RegionSettings.cs @@ -0,0 +1,233 @@ +using System; +using System.IO; +using System.Xml; + +namespace OpenMetaverse.Assets +{ + public class RegionSettings + { + public bool AllowDamage; + public bool AllowLandResell; + public bool AllowLandJoinDivide; + public bool BlockFly; + public bool BlockLandShowInSearch; + public bool BlockTerraform; + public bool DisableCollisions; + public bool DisablePhysics; + public bool DisableScripts; + public int MaturityRating; + public bool RestrictPushing; + public int AgentLimit; + public float ObjectBonus; + + public UUID TerrainDetail0; + public UUID TerrainDetail1; + public UUID TerrainDetail2; + public UUID TerrainDetail3; + public float TerrainHeightRange00; + public float TerrainHeightRange01; + public float TerrainHeightRange10; + public float TerrainHeightRange11; + public float TerrainStartHeight00; + public float TerrainStartHeight01; + public float TerrainStartHeight10; + public float TerrainStartHeight11; + + public float WaterHeight; + public float TerrainRaiseLimit; + public float TerrainLowerLimit; + public bool UseEstateSun; + public bool FixedSun; + + public static RegionSettings FromStream(Stream stream) + { + RegionSettings settings = new RegionSettings(); + System.Globalization.NumberFormatInfo nfi = Utils.EnUsCulture.NumberFormat; + + using (XmlTextReader xtr = new XmlTextReader(stream)) + { + xtr.ReadStartElement("RegionSettings"); + xtr.ReadStartElement("General"); + + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) + { + switch (xtr.Name) + { + case "AllowDamage": + settings.AllowDamage = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "AllowLandResell": + settings.AllowLandResell = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "AllowLandJoinDivide": + settings.AllowLandJoinDivide = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "BlockFly": + settings.BlockFly = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "BlockLandShowInSearch": + settings.BlockLandShowInSearch = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "BlockTerraform": + settings.BlockTerraform = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "DisableCollisions": + settings.DisableCollisions = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "DisablePhysics": + settings.DisablePhysics = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "DisableScripts": + settings.DisableScripts = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "MaturityRating": + settings.MaturityRating = Int32.Parse(xtr.ReadElementContentAsString()); + break; + case "RestrictPushing": + settings.RestrictPushing = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "AgentLimit": + settings.AgentLimit = Int32.Parse(xtr.ReadElementContentAsString()); + break; + case "ObjectBonus": + settings.ObjectBonus = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + } + } + + xtr.ReadEndElement(); + xtr.ReadStartElement("GroundTextures"); + + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) + { + switch (xtr.Name) + { + case "Texture1": + settings.TerrainDetail0 = UUID.Parse(xtr.ReadElementContentAsString()); + break; + case "Texture2": + settings.TerrainDetail1 = UUID.Parse(xtr.ReadElementContentAsString()); + break; + case "Texture3": + settings.TerrainDetail2 = UUID.Parse(xtr.ReadElementContentAsString()); + break; + case "Texture4": + settings.TerrainDetail3 = UUID.Parse(xtr.ReadElementContentAsString()); + break; + case "ElevationLowSW": + settings.TerrainStartHeight00 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "ElevationLowNW": + settings.TerrainStartHeight01 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "ElevationLowSE": + settings.TerrainStartHeight10 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "ElevationLowNE": + settings.TerrainStartHeight11 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "ElevationHighSW": + settings.TerrainHeightRange00 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "ElevationHighNW": + settings.TerrainHeightRange01 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "ElevationHighSE": + settings.TerrainHeightRange10 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "ElevationHighNE": + settings.TerrainHeightRange11 = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + } + } + + xtr.ReadEndElement(); + xtr.ReadStartElement("Terrain"); + + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) + { + switch (xtr.Name) + { + case "WaterHeight": + settings.WaterHeight = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "TerrainRaiseLimit": + settings.TerrainRaiseLimit = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "TerrainLowerLimit": + settings.TerrainLowerLimit = Single.Parse(xtr.ReadElementContentAsString(), nfi); + break; + case "UseEstateSun": + settings.UseEstateSun = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + case "FixedSun": + settings.FixedSun = Boolean.Parse(xtr.ReadElementContentAsString()); + break; + } + } + } + + return settings; + } + + public void ToXML(string filename) + { + StringWriter sw = new StringWriter(); + XmlTextWriter writer = new XmlTextWriter(sw) { Formatting = Formatting.Indented }; + writer.WriteStartDocument(); + + writer.WriteStartElement(String.Empty, "RegionSettings", String.Empty); + writer.WriteStartElement(String.Empty, "General", String.Empty); + + WriteBoolean(writer, "AllowDamage", AllowDamage); + WriteBoolean(writer, "AllowLandResell", AllowLandResell); + WriteBoolean(writer, "AllowLandJoinDivide", AllowLandJoinDivide); + WriteBoolean(writer, "BlockFly", BlockFly); + WriteBoolean(writer, "BlockLandShowInSearch", BlockLandShowInSearch); + WriteBoolean(writer, "BlockTerraform", BlockTerraform); + WriteBoolean(writer, "DisableCollisions", DisableCollisions); + WriteBoolean(writer, "DisablePhysics", DisablePhysics); + WriteBoolean(writer, "DisableScripts", DisableScripts); + writer.WriteElementString("MaturityRating", MaturityRating.ToString()); + WriteBoolean(writer, "RestrictPushing", RestrictPushing); + writer.WriteElementString("AgentLimit", AgentLimit.ToString()); + writer.WriteElementString("ObjectBonus", ObjectBonus.ToString()); + writer.WriteEndElement(); + + writer.WriteStartElement(String.Empty, "GroundTextures", String.Empty); + + writer.WriteElementString("Texture1", TerrainDetail0.ToString()); + writer.WriteElementString("Texture2", TerrainDetail1.ToString()); + writer.WriteElementString("Texture3", TerrainDetail2.ToString()); + writer.WriteElementString("Texture4", TerrainDetail3.ToString()); + writer.WriteElementString("ElevationLowSW", TerrainStartHeight00.ToString()); + writer.WriteElementString("ElevationLowNW", TerrainStartHeight01.ToString()); + writer.WriteElementString("ElevationLowSE", TerrainStartHeight10.ToString()); + writer.WriteElementString("ElevationLowNE", TerrainStartHeight11.ToString()); + writer.WriteElementString("ElevationHighSW", TerrainHeightRange00.ToString()); + writer.WriteElementString("ElevationHighNW", TerrainHeightRange01.ToString()); + writer.WriteElementString("ElevationHighSE", TerrainHeightRange10.ToString()); + writer.WriteElementString("ElevationHighNE", TerrainHeightRange11.ToString()); + writer.WriteEndElement(); + + writer.WriteStartElement(String.Empty, "Terrain", String.Empty); + + writer.WriteElementString("WaterHeight", WaterHeight.ToString()); + writer.WriteElementString("TerrainRaiseLimit", TerrainRaiseLimit.ToString()); + writer.WriteElementString("TerrainLowerLimit", TerrainLowerLimit.ToString()); + WriteBoolean(writer, "UseEstateSun", UseEstateSun); + WriteBoolean(writer, "FixedSun", FixedSun); + + writer.WriteEndElement(); + writer.WriteEndElement(); + writer.Close(); + sw.Close(); + File.WriteAllText(filename, sw.ToString()); + } + + private void WriteBoolean(XmlTextWriter writer, string name, bool value) + { + writer.WriteElementString(name, value ? "True" : "False"); + } + } +} diff --git a/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs b/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs new file mode 100644 index 0000000..698749a --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Text; + +namespace OpenMetaverse.Assets +{ + /// + /// Temporary code to do the bare minimum required to read a tar archive for our purposes + /// + public class TarArchiveReader + { + public enum TarEntryType + { + TYPE_UNKNOWN = 0, + TYPE_NORMAL_FILE = 1, + TYPE_HARD_LINK = 2, + TYPE_SYMBOLIC_LINK = 3, + TYPE_CHAR_SPECIAL = 4, + TYPE_BLOCK_SPECIAL = 5, + TYPE_DIRECTORY = 6, + TYPE_FIFO = 7, + TYPE_CONTIGUOUS_FILE = 8, + } + + protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); + + /// + /// Binary reader for the underlying stream + /// + protected BinaryReader m_br; + + /// + /// Used to trim off null chars + /// + protected static readonly char[] m_nullCharArray = new char[] { '\0' }; + + /// + /// Used to trim off space chars + /// + protected static readonly char[] m_spaceCharArray = new char[] { ' ' }; + + /// + /// Generate a tar reader which reads from the given stream. + /// + /// + public TarArchiveReader(Stream s) + { + m_br = new BinaryReader(s); + } + + /// + /// Read the next entry in the tar file. + /// + /// + /// + /// the data for the entry. Returns null if there are no more entries + public byte[] ReadEntry(out string filePath, out TarEntryType entryType) + { + filePath = String.Empty; + entryType = TarEntryType.TYPE_UNKNOWN; + TarHeader header = ReadHeader(); + + if (null == header) + return null; + + entryType = header.EntryType; + filePath = header.FilePath; + return ReadData(header.FileSize); + } + + /// + /// Read the next 512 byte chunk of data as a tar header. + /// + /// A tar header struct. null if we have reached the end of the archive. + protected TarHeader ReadHeader() + { + byte[] header = m_br.ReadBytes(512); + + // If we've reached the end of the archive we'll be in null block territory, which means + // the next byte will be 0 + if (header[0] == 0) + return null; + + TarHeader tarHeader = new TarHeader(); + + // If we're looking at a GNU tar long link then extract the long name and pull up the next header + if (header[156] == (byte)'L') + { + int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11); + tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength)); + //m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath); + header = m_br.ReadBytes(512); + } + else + { + tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100); + tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray); + //m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath); + } + + tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11); + + switch (header[156]) + { + case 0: + tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE; + break; + case (byte)'0': + tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE; + break; + case (byte)'1': + tarHeader.EntryType = TarEntryType.TYPE_HARD_LINK; + break; + case (byte)'2': + tarHeader.EntryType = TarEntryType.TYPE_SYMBOLIC_LINK; + break; + case (byte)'3': + tarHeader.EntryType = TarEntryType.TYPE_CHAR_SPECIAL; + break; + case (byte)'4': + tarHeader.EntryType = TarEntryType.TYPE_BLOCK_SPECIAL; + break; + case (byte)'5': + tarHeader.EntryType = TarEntryType.TYPE_DIRECTORY; + break; + case (byte)'6': + tarHeader.EntryType = TarEntryType.TYPE_FIFO; + break; + case (byte)'7': + tarHeader.EntryType = TarEntryType.TYPE_CONTIGUOUS_FILE; + break; + } + + return tarHeader; + } + + /// + /// Read data following a header + /// + /// + /// + protected byte[] ReadData(int fileSize) + { + byte[] data = m_br.ReadBytes(fileSize); + + //m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize); + + // Read the rest of the empty padding in the 512 byte block + if (fileSize % 512 != 0) + { + int paddingLeft = 512 - (fileSize % 512); + + //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft); + + m_br.ReadBytes(paddingLeft); + } + + return data; + } + + public void Close() + { + m_br.Close(); + } + + /// + /// Convert octal bytes to a decimal representation + /// + /// + /// + /// + /// + public static int ConvertOctalBytesToDecimal(byte[] bytes, int startIndex, int count) + { + // Trim leading white space: ancient tars do that instead + // of leading 0s :-( don't ask. really. + string oString = m_asciiEncoding.GetString(bytes, startIndex, count).TrimStart(m_spaceCharArray); + + int d = 0; + + foreach (char c in oString) + { + d <<= 3; + d |= c - '0'; + } + + return d; + } + } + + public class TarHeader + { + public string FilePath; + public int FileSize; + public TarArchiveReader.TarEntryType EntryType; + } +} diff --git a/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs b/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs new file mode 100644 index 0000000..8bb9f72 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace OpenMetaverse.Assets +{ + /// + /// Temporary code to produce a tar archive in tar v7 format + /// + public class TarArchiveWriter + { + protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); + + /// + /// Binary writer for the underlying stream + /// + protected BinaryWriter m_bw; + + public TarArchiveWriter(Stream s) + { + m_bw = new BinaryWriter(s); + } + + /// + /// Write a directory entry to the tar archive. We can only handle one path level right now! + /// + /// + public void WriteDir(string dirName) + { + // Directories are signalled by a final / + if (!dirName.EndsWith("/")) + dirName += "/"; + + WriteFile(dirName, new byte[0]); + } + + /// + /// Write a file to the tar archive + /// + /// + /// + public void WriteFile(string filePath, string data) + { + WriteFile(filePath, m_asciiEncoding.GetBytes(data)); + } + + /// + /// Write a file to the tar archive + /// + /// + /// + public void WriteFile(string filePath, byte[] data) + { + if (filePath.Length > 100) + WriteEntry("././@LongLink", m_asciiEncoding.GetBytes(filePath), 'L'); + + char fileType; + + if (filePath.EndsWith("/")) + { + fileType = '5'; + } + else + { + fileType = '0'; + } + + WriteEntry(filePath, data, fileType); + } + + /// + /// Finish writing the raw tar archive data to a stream. The stream will be closed on completion. + /// + public void Close() + { + //m_log.Debug("[TAR ARCHIVE WRITER]: Writing final consecutive 0 blocks"); + + // Write two consecutive 0 blocks to end the archive + byte[] finalZeroPadding = new byte[1024]; + m_bw.Write(finalZeroPadding); + + m_bw.Flush(); + m_bw.Close(); + } + + public static byte[] ConvertDecimalToPaddedOctalBytes(int d, int padding) + { + string oString = ""; + + while (d > 0) + { + oString = Convert.ToString((byte)'0' + d & 7) + oString; + d >>= 3; + } + + while (oString.Length < padding) + { + oString = "0" + oString; + } + + byte[] oBytes = m_asciiEncoding.GetBytes(oString); + + return oBytes; + } + + /// + /// Write a particular entry + /// + /// + /// + /// + protected void WriteEntry(string filePath, byte[] data, char fileType) + { + byte[] header = new byte[512]; + + // file path field (100) + byte[] nameBytes = m_asciiEncoding.GetBytes(filePath); + int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length; + Array.Copy(nameBytes, header, nameSize); + + // file mode (8) + byte[] modeBytes = m_asciiEncoding.GetBytes("0000777"); + Array.Copy(modeBytes, 0, header, 100, 7); + + // owner user id (8) + byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764"); + Array.Copy(ownerIdBytes, 0, header, 108, 7); + + // group user id (8) + byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764"); + Array.Copy(groupIdBytes, 0, header, 116, 7); + + // file size in bytes (12) + int fileSize = data.Length; + //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize); + + byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11); + + Array.Copy(fileSizeBytes, 0, header, 124, 11); + + // last modification time (12) + byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332"); + Array.Copy(lastModTimeBytes, 0, header, 136, 11); + + // entry type indicator (1) + header[156] = m_asciiEncoding.GetBytes(new char[] { fileType })[0]; + + Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7); + Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7); + + // check sum for header block (8) [calculated last] + Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8); + + int checksum = 0; + foreach (byte b in header) + { + checksum += b; + } + + //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum); + + byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6); + + Array.Copy(checkSumBytes, 0, header, 148, 6); + + header[154] = 0; + + // Write out header + m_bw.Write(header); + + // Write out data + m_bw.Write(data); + + if (data.Length % 512 != 0) + { + int paddingRequired = 512 - (data.Length % 512); + + //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired); + + byte[] padding = new byte[paddingRequired]; + m_bw.Write(padding); + } + } + } +} diff --git a/OpenMetaverse/Assets/Asset.cs b/OpenMetaverse/Assets/Asset.cs new file mode 100644 index 0000000..1a7315a --- /dev/null +++ b/OpenMetaverse/Assets/Asset.cs @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Base class for all Asset types + /// + public abstract class Asset + { + /// A byte array containing the raw asset data + public byte[] AssetData; + /// True if the asset it only stored on the server temporarily + public bool Temporary; + /// A unique ID + private UUID _AssetID; + /// The assets unique ID + public UUID AssetID + { + get { return _AssetID; } + internal set { _AssetID = value; } + } + + /// + /// The "type" of asset, Notecard, Animation, etc + /// + public abstract AssetType AssetType + { + get; + } + + /// + /// Construct a new Asset object + /// + public Asset() { } + + /// + /// Construct a new Asset object + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public Asset(UUID assetID, byte[] assetData) + { + _AssetID = assetID; + AssetData = assetData; + } + + /// + /// Regenerates the AssetData byte array from the properties + /// of the derived class. + /// + public abstract void Encode(); + + /// + /// Decodes the AssetData, placing it in appropriate properties of the derived + /// class. + /// + /// True if the asset decoding succeeded, otherwise false + public abstract bool Decode(); + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs b/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs new file mode 100644 index 0000000..a8bc886 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an Animation + /// + public class AssetAnimation : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Animation; } } + + /// Default Constructor + public AssetAnimation() { } + + /// + /// Construct an Asset object of type Animation + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetAnimation(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + } + + public override void Encode() { } + public override bool Decode() { return true; } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs b/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs new file mode 100644 index 0000000..a072528 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an that represents an avatars body ie: Hair, Etc. + /// + public class AssetBodypart : AssetWearable + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Bodypart; } } + + /// Initializes a new instance of an AssetBodyPart object + public AssetBodypart() { } + + /// Initializes a new instance of an AssetBodyPart object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetBodypart(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetCallingCard.cs b/OpenMetaverse/Assets/AssetTypes/AssetCallingCard.cs new file mode 100644 index 0000000..099d3ec --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetCallingCard.cs @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a Callingcard with AvatarID and Position vector + /// + public class AssetCallingCard : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.CallingCard; } } + + /// UUID of the Callingcard target avatar + public UUID AvatarID = UUID.Zero; + + /// Construct an Asset of type Callingcard + public AssetCallingCard() { } + + /// + /// Construct an Asset object of type Callingcard + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetCallingCard(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + Decode(); + } + + /// + /// Constuct an asset of type Callingcard + /// + /// UUID of the target avatar + public AssetCallingCard(UUID avatarID) + { + AvatarID = avatarID; + Encode(); + } + + /// + /// Encode the raw contents of a string with the specific Callingcard format + /// + public override void Encode() + { + string temp = "Callingcard version 2\n"; + temp += "avatar_id " + AvatarID + "\n"; + AssetData = Utils.StringToBytes(temp); + } + + /// + /// Decode the raw asset data, populating the AvatarID and Position + /// + /// true if the AssetData was successfully decoded to a UUID and Vector + public override bool Decode() + { + String text = Utils.BytesToString(AssetData); + if (text.ToLower().Contains("callingcard version 2")) + { + AvatarID = new UUID(text.Substring(text.IndexOf("avatar_id") + 10, 36)); + return true; + } + return false; + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs b/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs new file mode 100644 index 0000000..c911d1a --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an that can be worn on an avatar + /// such as a Shirt, Pants, etc. + /// + public class AssetClothing : AssetWearable + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Clothing; } } + + /// Initializes a new instance of an AssetScriptBinary object + public AssetClothing() { } + + /// Initializes a new instance of an AssetScriptBinary object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetClothing(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetGesture.cs b/OpenMetaverse/Assets/AssetTypes/AssetGesture.cs new file mode 100644 index 0000000..ea00923 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetGesture.cs @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + #region Enums + /// + /// Type of gesture step + /// + public enum GestureStepType : int + { + Animation = 0, + Sound, + Chat, + Wait, + EOF + } + #endregion + + #region Gesture step classes + /// + /// Base class for gesture steps + /// + public abstract class GestureStep + { + /// + /// Retururns what kind of gesture step this is + /// + public abstract GestureStepType GestureStepType { get; } + } + + /// + /// Describes animation step of a gesture + /// + public class GestureStepAnimation : GestureStep + { + /// + /// Returns what kind of gesture step this is + /// + public override GestureStepType GestureStepType + { + get { return GestureStepType.Animation; } + } + + /// + /// If true, this step represents start of animation, otherwise animation stop + /// + public bool AnimationStart = true; + + /// + /// Animation asset + /// + public UUID ID; + + /// + /// Animation inventory name + /// + public string Name; + + public override string ToString() + { + if (AnimationStart) + { + return "Start animation: " + Name; + } + else + { + return "Stop animation: " + Name; + } + } + } + + /// + /// Describes sound step of a gesture + /// + public class GestureStepSound : GestureStep + { + /// + /// Returns what kind of gesture step this is + /// + public override GestureStepType GestureStepType + { + get { return GestureStepType.Sound; } + } + + /// + /// Sound asset + /// + public UUID ID; + + /// + /// Sound inventory name + /// + public string Name; + + public override string ToString() + { + return "Sound: " + Name; + } + + } + + /// + /// Describes sound step of a gesture + /// + public class GestureStepChat : GestureStep + { + /// + /// Returns what kind of gesture step this is + /// + public override GestureStepType GestureStepType + { + get { return GestureStepType.Chat; } + } + + /// + /// Text to output in chat + /// + public string Text; + + public override string ToString() + { + return "Chat: " + Text; + } + } + + /// + /// Describes sound step of a gesture + /// + public class GestureStepWait : GestureStep + { + /// + /// Returns what kind of gesture step this is + /// + public override GestureStepType GestureStepType + { + get { return GestureStepType.Wait; } + } + + /// + /// If true in this step we wait for all animations to finish + /// + public bool WaitForAnimation; + + /// + /// If true gesture player should wait for the specified amount of time + /// + public bool WaitForTime; + + /// + /// Time in seconds to wait if WaitForAnimation is false + /// + public float WaitTime; + + public override string ToString() + { + StringBuilder ret = new StringBuilder("-- Wait for: "); + + if (WaitForAnimation) + { + ret.Append("(animations to finish) "); + } + + if (WaitForTime) + { + ret.AppendFormat("(time {0:0.0}s)", WaitTime); + } + + return ret.ToString(); + } + } + + /// + /// Describes the final step of a gesture + /// + public class GestureStepEOF : GestureStep + { + /// + /// Returns what kind of gesture step this is + /// + public override GestureStepType GestureStepType + { + get { return GestureStepType.EOF; } + } + + public override string ToString() + { + return "End of guesture sequence"; + } + } + + #endregion + + /// + /// Represents a sequence of animations, sounds, and chat actions + /// + public class AssetGesture : Asset + { + /// + /// Returns asset type + /// + public override AssetType AssetType + { + get { return AssetType.Gesture; } + } + + /// + /// Keyboard key that triggers the gestyre + /// + public byte TriggerKey; + + /// + /// Modifier to the trigger key + /// + public uint TriggerKeyMask; + + /// + /// String that triggers playing of the gesture sequence + /// + public string Trigger; + + /// + /// Text that replaces trigger in chat once gesture is triggered + /// + public string ReplaceWith; + + /// + /// Sequence of gesture steps + /// + public List Sequence; + + /// + /// Constructs guesture asset + /// + public AssetGesture() { } + + /// + /// Constructs guesture asset + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetGesture(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + } + + /// + /// Encodes gesture asset suitable for uplaod + /// + public override void Encode() + { + StringBuilder sb = new StringBuilder(); + sb.Append("2\n"); + sb.Append(TriggerKey + "\n"); + sb.Append(TriggerKeyMask + "\n"); + sb.Append(Trigger + "\n"); + sb.Append(ReplaceWith + "\n"); + + int count = 0; + if (Sequence != null) + { + count = Sequence.Count; + } + + sb.Append(count + "\n"); + + for (int i = 0; i < count; i++) + { + GestureStep step = Sequence[i]; + sb.Append((int)step.GestureStepType + "\n"); + + switch (step.GestureStepType) + { + case GestureStepType.EOF: + goto Finish; + + case GestureStepType.Animation: + GestureStepAnimation animstep = (GestureStepAnimation)step; + sb.Append(animstep.Name + "\n"); + sb.Append(animstep.ID + "\n"); + + if (animstep.AnimationStart) + { + sb.Append("0\n"); + } + else + { + sb.Append("1\n"); + } + break; + + case GestureStepType.Sound: + GestureStepSound soundstep = (GestureStepSound)step; + sb.Append(soundstep.Name + "\n"); + sb.Append(soundstep.ID + "\n"); + sb.Append("0\n"); + break; + + case GestureStepType.Chat: + GestureStepChat chatstep = (GestureStepChat)step; + sb.Append(chatstep.Text + "\n"); + sb.Append("0\n"); + break; + + case GestureStepType.Wait: + GestureStepWait waitstep = (GestureStepWait)step; + sb.AppendFormat("{0:0.000000}\n", waitstep.WaitTime); + int waitflags = 0; + + if (waitstep.WaitForTime) + { + waitflags |= 0x01; + } + + if (waitstep.WaitForAnimation) + { + waitflags |= 0x02; + } + + sb.Append(waitflags + "\n"); + break; + } + } + Finish: + + AssetData = Utils.StringToBytes(sb.ToString()); + } + + /// + /// Decodes gesture assset into play sequence + /// + /// true if the asset data was decoded successfully + public override bool Decode() + { + try + { + string[] lines = Utils.BytesToString(AssetData).Split('\n'); + Sequence = new List(); + + int i = 0; + + // version + int version = int.Parse(lines[i++]); + if (version != 2) + { + throw new Exception("Only know how to decode version 2 of gesture asset"); + } + + TriggerKey = byte.Parse(lines[i++]); + TriggerKeyMask = uint.Parse(lines[i++]); + Trigger = lines[i++]; + ReplaceWith = lines[i++]; + + int count = int.Parse(lines[i++]); + + if (count < 0) + { + throw new Exception("Wrong number of gesture steps"); + } + + for (int n = 0; n < count; n++) + { + GestureStepType type = (GestureStepType)int.Parse(lines[i++]); + + switch (type) + { + case GestureStepType.EOF: + goto Finish; + + case GestureStepType.Animation: + { + GestureStepAnimation step = new GestureStepAnimation(); + step.Name = lines[i++]; + step.ID = new UUID(lines[i++]); + int flags = int.Parse(lines[i++]); + + if (flags == 0) + { + step.AnimationStart = true; + } + else + { + step.AnimationStart = false; + } + + Sequence.Add(step); + break; + } + + case GestureStepType.Sound: + { + GestureStepSound step = new GestureStepSound(); + step.Name = lines[i++].Replace("\r", ""); + step.ID = new UUID(lines[i++]); + int flags = int.Parse(lines[i++]); + + Sequence.Add(step); + break; + } + + case GestureStepType.Chat: + { + GestureStepChat step = new GestureStepChat(); + step.Text = lines[i++]; + int flags = int.Parse(lines[i++]); + + Sequence.Add(step); + break; + } + + case GestureStepType.Wait: + { + GestureStepWait step = new GestureStepWait(); + step.WaitTime = float.Parse(lines[i++], Utils.EnUsCulture); + int flags = int.Parse(lines[i++]); + + step.WaitForTime = (flags & 0x01) != 0; + step.WaitForAnimation = (flags & 0x02) != 0; + Sequence.Add(step); + break; + } + + } + } + Finish: + + return true; + } + catch (Exception ex) + { + Logger.Log("Decoding gesture asset failed:" + ex.Message, Helpers.LogLevel.Error); + return false; + } + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs b/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs new file mode 100644 index 0000000..d753442 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a Landmark with RegionID and Position vector + /// + public class AssetLandmark : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Landmark; } } + + /// UUID of the Landmark target region + public UUID RegionID = UUID.Zero; + /// Local position of the target + public Vector3 Position = Vector3.Zero; + + /// Construct an Asset of type Landmark + public AssetLandmark() { } + + /// + /// Construct an Asset object of type Landmark + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetLandmark(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + } + + /// + /// Encode the raw contents of a string with the specific Landmark format + /// + public override void Encode() + { + string temp = "Landmark version 2\n"; + temp += "region_id " + RegionID + "\n"; + temp += String.Format(Utils.EnUsCulture, "local_pos {0:0.00} {1:0.00} {2:0.00}\n", Position.X, Position.Y, Position.Z); + AssetData = Utils.StringToBytes(temp); + } + + /// + /// Decode the raw asset data, populating the RegionID and Position + /// + /// true if the AssetData was successfully decoded to a UUID and Vector + public override bool Decode() + { + String text = Utils.BytesToString(AssetData); + if (text.ToLower().Contains("landmark version 2")) + { + RegionID = new UUID(text.Substring(text.IndexOf("region_id") + 10, 36)); + String vecDelim = " "; + String[] vecStrings = text.Substring(text.IndexOf("local_pos") + 10).Split(vecDelim.ToCharArray()); + if (vecStrings.Length == 3) + { + Position = new Vector3(float.Parse(vecStrings[0], System.Globalization.CultureInfo.InvariantCulture), float.Parse(vecStrings[1], System.Globalization.CultureInfo.InvariantCulture), float.Parse(vecStrings[2], System.Globalization.CultureInfo.InvariantCulture)); + return true; + } + } + return false; + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetMesh.cs b/OpenMetaverse/Assets/AssetTypes/AssetMesh.cs new file mode 100644 index 0000000..268b1d3 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetMesh.cs @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents Mesh asset + /// + public class AssetMesh : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Mesh; } } + + /// + /// Decoded mesh data + /// + public OSDMap MeshData; + + /// Initializes a new instance of an AssetMesh object + public AssetMesh() { } + + /// Initializes a new instance of an AssetMesh object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetMesh(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + } + + /// + /// TODO: Encodes Collada file into LLMesh format + /// + public override void Encode() { } + + /// + /// Decodes mesh asset. See + /// to furter decode it for rendering + /// true + public override bool Decode() + { + try + { + MeshData = new OSDMap(); + + using (MemoryStream data = new MemoryStream(AssetData)) + { + OSDMap header = (OSDMap)OSDParser.DeserializeLLSDBinary(data); + MeshData["asset_header"] = header; + long start = data.Position; + + foreach(string partName in header.Keys) + { + if (header[partName].Type != OSDType.Map) + { + MeshData[partName] = header[partName]; + continue; + } + + OSDMap partInfo = (OSDMap)header[partName]; + if (partInfo["offset"] < 0 || partInfo["size"] == 0) + { + MeshData[partName] = partInfo; + continue; + } + + byte[] part = new byte[partInfo["size"]]; + Buffer.BlockCopy(AssetData, partInfo["offset"] + (int)start, part, 0, part.Length); + MeshData[partName] = Helpers.ZDecompressOSD(part); + } + } + return true; + } + catch (Exception ex) + { + Logger.Log("Failed to decode mesh asset", Helpers.LogLevel.Error, ex); + return false; + } + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetMutable.cs b/OpenMetaverse/Assets/AssetTypes/AssetMutable.cs new file mode 100644 index 0000000..b0304ca --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetMutable.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an Animation + /// + public class AssetMutable : Asset + { + public AssetType currentType; + + /// Override the base classes AssetType + public override AssetType AssetType { get { return currentType; } } + + /// Default Constructor + public AssetMutable(AssetType type) + { + currentType = type; + } + + /// + /// Construct an Asset object of type Animation + /// + /// Asset type + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetMutable(AssetType type, UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + currentType = type; + } + + public override void Encode() { } + public override bool Decode() { return true; } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs b/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs new file mode 100644 index 0000000..58843a9 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a string of characters encoded with specific formatting properties + /// + public class AssetNotecard : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Notecard; } } + + /// A text string containing main text of the notecard + public string BodyText; + + /// List of s embedded on the notecard + public List EmbeddedItems; + + /// Construct an Asset of type Notecard + public AssetNotecard() { } + + /// + /// Construct an Asset object of type Notecard + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetNotecard(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + } + + /// + /// Encode the raw contents of a string with the specific Linden Text properties + /// + public override void Encode() + { + string body = BodyText ?? String.Empty; + + StringBuilder output = new StringBuilder(); + output.Append("Linden text version 2\n"); + output.Append("{\n"); + output.Append("LLEmbeddedItems version 1\n"); + output.Append("{\n"); + + int count = 0; + + if (EmbeddedItems != null) + { + count = EmbeddedItems.Count; + } + + output.Append("count " + count + "\n"); + + if (count > 0) + { + output.Append("{\n"); + + for (int i = 0; i < EmbeddedItems.Count; i++) + { + InventoryItem item = EmbeddedItems[i]; + + output.Append("ext char index " + i + "\n"); + + output.Append("\tinv_item\t0\n"); + output.Append("\t{\n"); + + output.Append("\t\titem_id\t" + item.UUID + "\n"); + output.Append("\t\tparent_id\t" + item.ParentUUID + "\n"); + + output.Append("\tpermissions 0\n"); + output.Append("\t{\n"); + output.Append("\t\tbase_mask\t" + ((uint)item.Permissions.BaseMask).ToString("x").PadLeft(8, '0') + "\n"); + output.Append("\t\towner_mask\t" + ((uint)item.Permissions.OwnerMask).ToString("x").PadLeft(8, '0') + "\n"); + output.Append("\t\tgroup_mask\t" + ((uint)item.Permissions.GroupMask).ToString("x").PadLeft(8, '0') + "\n"); + output.Append("\t\teveryone_mask\t" + ((uint)item.Permissions.EveryoneMask).ToString("x").PadLeft(8, '0') + "\n"); + output.Append("\t\tnext_owner_mask\t" + ((uint)item.Permissions.NextOwnerMask).ToString("x").PadLeft(8, '0') + "\n"); + output.Append("\t\tcreator_id\t" + item.CreatorID + "\n"); + output.Append("\t\towner_id\t" + item.OwnerID + "\n"); + output.Append("\t\tlast_owner_id\t" + item.LastOwnerID + "\n"); + output.Append("\t\tgroup_id\t" + item.GroupID + "\n"); + if (item.GroupOwned) output.Append("\t\tgroup_owned\t1\n"); + output.Append("\t}\n"); + + if (Permissions.HasPermissions(item.Permissions.BaseMask, PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Transfer) || + item.AssetUUID == UUID.Zero) + { + output.Append("\t\tasset_id\t" + item.AssetUUID + "\n"); + } + else + { + output.Append("\t\tshadow_id\t" + InventoryManager.EncryptAssetID(item.AssetUUID) + "\n"); + } + + output.Append("\t\ttype\t" + Utils.AssetTypeToString(item.AssetType) + "\n"); + output.Append("\t\tinv_type\t" + Utils.InventoryTypeToString(item.InventoryType) + "\n"); + output.Append("\t\tflags\t" + item.Flags.ToString().PadLeft(8, '0') + "\n"); + + output.Append("\tsale_info\t0\n"); + output.Append("\t{\n"); + output.Append("\t\tsale_type\t" + Utils.SaleTypeToString(item.SaleType) + "\n"); + output.Append("\t\tsale_price\t" + item.SalePrice + "\n"); + output.Append("\t}\n"); + + output.Append("\t\tname\t" + item.Name.Replace('|', '_') + "|\n"); + output.Append("\t\tdesc\t" + item.Description.Replace('|', '_') + "|\n"); + output.Append("\t\tcreation_date\t" + Utils.DateTimeToUnixTime(item.CreationDate) + "\n"); + + output.Append("\t}\n"); + + if (i != EmbeddedItems.Count - 1) + { + output.Append("}\n{\n"); + } + } + + output.Append("}\n"); + } + + output.Append("}\n"); + output.Append("Text length " + (Utils.StringToBytes(body).Length - 1).ToString() + "\n"); + output.Append(body + "}\n"); + + AssetData = Utils.StringToBytes(output.ToString()); + } + + /// + /// Decode the raw asset data including the Linden Text properties + /// + /// true if the AssetData was successfully decoded + public override bool Decode() + { + string data = Utils.BytesToString(AssetData); + EmbeddedItems = new List(); + BodyText = string.Empty; + + try + { + string[] lines = data.Split('\n'); + int i = 0; + Match m; + + // Version + if (!(m = Regex.Match(lines[i++], @"Linden text version\s+(\d+)")).Success) + throw new Exception("could not determine version"); + int notecardVersion = int.Parse(m.Groups[1].Value); + if (notecardVersion < 1 || notecardVersion > 2) + throw new Exception("unsuported version"); + if (!(m = Regex.Match(lines[i++], @"\s*{$")).Success) + throw new Exception("wrong format"); + + // Embedded items header + if (!(m = Regex.Match(lines[i++], @"LLEmbeddedItems version\s+(\d+)")).Success) + throw new Exception("could not determine embedded items version version"); + if (m.Groups[1].Value != "1") + throw new Exception("unsuported embedded item version"); + if (!(m = Regex.Match(lines[i++], @"\s*{$")).Success) + throw new Exception("wrong format"); + + // Item count + if (!(m = Regex.Match(lines[i++], @"count\s+(\d+)")).Success) + throw new Exception("wrong format"); + int count = int.Parse(m.Groups[1].Value); + + // Decode individual items + for (int n = 0; n < count; n++) + { + if (!(m = Regex.Match(lines[i++], @"\s*{$")).Success) + throw new Exception("wrong format"); + + // Index + if (!(m = Regex.Match(lines[i++], @"ext char index\s+(\d+)")).Success) + throw new Exception("missing ext char index"); + //warning CS0219: The variable `index' is assigned but its value is never used + //int index = int.Parse(m.Groups[1].Value); + + // Inventory item + if (!(m = Regex.Match(lines[i++], @"inv_item\s+0")).Success) + throw new Exception("missing inv item"); + + // Item itself + UUID uuid = UUID.Zero; + UUID creatorID = UUID.Zero; + UUID ownerID = UUID.Zero; + UUID lastOwnerID = UUID.Zero; + UUID groupID = UUID.Zero; + Permissions permissions = Permissions.NoPermissions; + int salePrice = 0; + SaleType saleType = SaleType.Not; + UUID parentUUID = UUID.Zero; + UUID assetUUID = UUID.Zero; + AssetType assetType = AssetType.Unknown; + InventoryType inventoryType = InventoryType.Unknown; + uint flags = 0; + string name = string.Empty; + string description = string.Empty; + DateTime creationDate = Utils.Epoch; + + while (true) + { + if (!(m = Regex.Match(lines[i++], @"([^\s]+)(\s+)?(.*)?")).Success) + throw new Exception("wrong format"); + string key = m.Groups[1].Value; + string val = m.Groups[3].Value; + if (key == "{") + continue; + if (key == "}") + break; + else if (key == "permissions") + { + uint baseMask = 0; + uint ownerMask = 0; + uint groupMask = 0; + uint everyoneMask = 0; + uint nextOwnerMask = 0; + + while (true) + { + if (!(m = Regex.Match(lines[i++], @"([^\s]+)(\s+)?([^\s]+)?")).Success) + throw new Exception("wrong format"); + string pkey = m.Groups[1].Value; + string pval = m.Groups[3].Value; + + if (pkey == "{") + continue; + if (pkey == "}") + break; + else if (pkey == "creator_id") + { + creatorID = new UUID(pval); + } + else if (pkey == "owner_id") + { + ownerID = new UUID(pval); + } + else if (pkey == "last_owner_id") + { + lastOwnerID = new UUID(pval); + } + else if (pkey == "group_id") + { + groupID = new UUID(pval); + } + else if (pkey == "base_mask") + { + baseMask = uint.Parse(pval, System.Globalization.NumberStyles.AllowHexSpecifier); + } + else if (pkey == "owner_mask") + { + ownerMask = uint.Parse(pval, System.Globalization.NumberStyles.AllowHexSpecifier); + } + else if (pkey == "group_mask") + { + groupMask = uint.Parse(pval, System.Globalization.NumberStyles.AllowHexSpecifier); + } + else if (pkey == "everyone_mask") + { + everyoneMask = uint.Parse(pval, System.Globalization.NumberStyles.AllowHexSpecifier); + } + else if (pkey == "next_owner_mask") + { + nextOwnerMask = uint.Parse(pval, System.Globalization.NumberStyles.AllowHexSpecifier); + } + } + permissions = new Permissions(baseMask, everyoneMask, groupMask, nextOwnerMask, ownerMask); + } + else if (key == "sale_info") + { + while (true) + { + if (!(m = Regex.Match(lines[i++], @"([^\s]+)(\s+)?([^\s]+)?")).Success) + throw new Exception("wrong format"); + string pkey = m.Groups[1].Value; + string pval = m.Groups[3].Value; + + if (pkey == "{") + continue; + if (pkey == "}") + break; + else if (pkey == "sale_price") + { + salePrice = int.Parse(pval); + } + else if (pkey == "sale_type") + { + saleType = Utils.StringToSaleType(pval); + } + } + } + else if (key == "item_id") + { + uuid = new UUID(val); + } + else if (key == "parent_id") + { + parentUUID = new UUID(val); + } + else if (key == "asset_id") + { + assetUUID = new UUID(val); + } + else if (key == "type") + { + assetType = Utils.StringToAssetType(val); + } + else if (key == "inv_type") + { + inventoryType = Utils.StringToInventoryType(val); + } + else if (key == "flags") + { + flags = uint.Parse(val, System.Globalization.NumberStyles.AllowHexSpecifier); + } + else if (key == "name") + { + name = val.Remove(val.LastIndexOf("|")); + } + else if (key == "desc") + { + description = val.Remove(val.LastIndexOf("|")); + } + else if (key == "creation_date") + { + creationDate = Utils.UnixTimeToDateTime(int.Parse(val)); + } + } + InventoryItem finalEmbedded = InventoryManager.CreateInventoryItem(inventoryType, uuid); + + finalEmbedded.CreatorID = creatorID; + finalEmbedded.OwnerID = ownerID; + finalEmbedded.LastOwnerID = lastOwnerID; + finalEmbedded.GroupID = groupID; + finalEmbedded.Permissions = permissions; + finalEmbedded.SalePrice = salePrice; + finalEmbedded.SaleType = saleType; + finalEmbedded.ParentUUID = parentUUID; + finalEmbedded.AssetUUID = assetUUID; + finalEmbedded.AssetType = assetType; + finalEmbedded.Flags = flags; + finalEmbedded.Name = name; + finalEmbedded.Description = description; + finalEmbedded.CreationDate = creationDate; + + EmbeddedItems.Add(finalEmbedded); + + if (!(m = Regex.Match(lines[i++], @"\s*}$")).Success) + throw new Exception("wrong format"); + + } + + // Text size + if (!(m = Regex.Match(lines[i++], @"\s*}$")).Success) + throw new Exception("wrong format"); + if (!(m = Regex.Match(lines[i++], @"Text length\s+(\d+)")).Success) + throw new Exception("could not determine text length"); + + // Read the rest of the notecard + while (i < lines.Length) + { + BodyText += lines[i++] + "\n"; + } + BodyText = BodyText.Remove(BodyText.LastIndexOf("}")); + return true; + } + catch (Exception ex) + { + Logger.Log("Decoding notecard asset failed: " + ex.Message, Helpers.LogLevel.Error); + return false; + } + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs b/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs new file mode 100644 index 0000000..1554bed --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs @@ -0,0 +1,1283 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Assets +{ + /// + /// A linkset asset, containing a parent primitive and zero or more children + /// + public class AssetPrim : Asset + { + /// + /// Only used internally for XML serialization/deserialization + /// + internal enum ProfileShape : byte + { + Circle = 0, + Square = 1, + IsometricTriangle = 2, + EquilateralTriangle = 3, + RightTriangle = 4, + HalfCircle = 5 + } + + public PrimObject Parent; + public List Children; + + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Object; } } + + /// Initializes a new instance of an AssetPrim object + public AssetPrim() { } + + /// + /// Initializes a new instance of an AssetPrim object + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetPrim(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + public AssetPrim(string xmlData) + { + DecodeXml(xmlData); + } + + public AssetPrim(PrimObject parent, List children) + { + Parent = parent; + if (children != null) + Children = children; + else + Children = new List(0); + } + + /// + /// + /// + public override void Encode() + { + AssetData = System.Text.Encoding.UTF8.GetBytes(EncodeXml()); + } + + /// + /// + /// + /// + public override bool Decode() + { + if (AssetData != null && AssetData.Length > 0) + { + try + { + string xmlData = System.Text.Encoding.UTF8.GetString(AssetData); + DecodeXml(xmlData); + return true; + } + catch { } + } + + return false; + } + + public string EncodeXml() + { + TextWriter textWriter = new StringWriter(); + using (XmlTextWriter xmlWriter = new XmlTextWriter(textWriter)) + { + OarFile.SOGToXml2(xmlWriter, this); + xmlWriter.Flush(); + return textWriter.ToString(); + } + } + + public bool DecodeXml(string xmlData) + { + using (XmlTextReader reader = new XmlTextReader(new StringReader(xmlData))) + { + reader.Read(); + reader.ReadStartElement("SceneObjectGroup"); + Parent = LoadPrim(reader); + + if (Parent != null) + { + if (this.AssetID == UUID.Zero) + this.AssetID = Parent.ID; + + List children = new List(); + + reader.Read(); + + while (!reader.EOF) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + if (reader.Name == "SceneObjectPart") + { + PrimObject child = LoadPrim(reader); + if (child != null) + children.Add(child); + } + else + { + //Logger.Log("Found unexpected prim XML element " + reader.Name, Helpers.LogLevel.Debug); + reader.Read(); + } + break; + case XmlNodeType.EndElement: + default: + reader.Read(); + break; + } + } + + Children = children; + return true; + } + else + { + Logger.Log("Failed to load root linkset prim", Helpers.LogLevel.Error); + return false; + } + } + } + + public static PrimObject LoadPrim(XmlTextReader reader) + { + PrimObject obj = new PrimObject(); + obj.Shape = new PrimObject.ShapeBlock(); + obj.Inventory = new PrimObject.InventoryBlock(); + + reader.ReadStartElement("SceneObjectPart"); + + if (reader.Name == "AllowedDrop") + obj.AllowedDrop = reader.ReadElementContentAsBoolean("AllowedDrop", String.Empty); + else + obj.AllowedDrop = true; + + obj.CreatorID = ReadUUID(reader, "CreatorID"); + obj.FolderID = ReadUUID(reader, "FolderID"); + obj.Inventory.Serial = reader.ReadElementContentAsInt("InventorySerial", String.Empty); + + #region Task Inventory + + List invItems = new List(); + + reader.ReadStartElement("TaskInventory", String.Empty); + while (reader.Name == "TaskInventoryItem") + { + PrimObject.InventoryBlock.ItemBlock item = new PrimObject.InventoryBlock.ItemBlock(); + reader.ReadStartElement("TaskInventoryItem", String.Empty); + + item.AssetID = ReadUUID(reader, "AssetID"); + item.PermsBase = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty); + item.CreationDate = Utils.UnixTimeToDateTime((uint)reader.ReadElementContentAsInt("CreationDate", String.Empty)); + item.CreatorID = ReadUUID(reader, "CreatorID"); + item.Description = reader.ReadElementContentAsString("Description", String.Empty); + item.PermsEveryone = (uint)reader.ReadElementContentAsInt("EveryonePermissions", String.Empty); + item.Flags = reader.ReadElementContentAsInt("Flags", String.Empty); + item.GroupID = ReadUUID(reader, "GroupID"); + item.PermsGroup = (uint)reader.ReadElementContentAsInt("GroupPermissions", String.Empty); + item.InvType = (InventoryType)reader.ReadElementContentAsInt("InvType", String.Empty); + item.ID = ReadUUID(reader, "ItemID"); + UUID oldItemID = ReadUUID(reader, "OldItemID"); // TODO: Is this useful? + item.LastOwnerID = ReadUUID(reader, "LastOwnerID"); + item.Name = reader.ReadElementContentAsString("Name", String.Empty); + item.PermsNextOwner = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty); + item.OwnerID = ReadUUID(reader, "OwnerID"); + item.PermsOwner = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty); + UUID parentID = ReadUUID(reader, "ParentID"); + UUID parentPartID = ReadUUID(reader, "ParentPartID"); + item.PermsGranterID = ReadUUID(reader, "PermsGranter"); + item.PermsBase = (uint)reader.ReadElementContentAsInt("PermsMask", String.Empty); + item.Type = (AssetType)reader.ReadElementContentAsInt("Type", String.Empty); + + reader.ReadEndElement(); + invItems.Add(item); + } + if (reader.NodeType == XmlNodeType.EndElement) + reader.ReadEndElement(); + + obj.Inventory.Items = invItems.ToArray(); + + #endregion Task Inventory + + PrimFlags flags = (PrimFlags)reader.ReadElementContentAsInt("ObjectFlags", String.Empty); + obj.UsePhysics = (flags & PrimFlags.Physics) != 0; + obj.Phantom = (flags & PrimFlags.Phantom) != 0; + obj.DieAtEdge = (flags & PrimFlags.DieAtEdge) != 0; + obj.ReturnAtEdge = (flags & PrimFlags.ReturnAtEdge) != 0; + obj.Temporary = (flags & PrimFlags.Temporary) != 0; + obj.Sandbox = (flags & PrimFlags.Sandbox) != 0; + + obj.ID = ReadUUID(reader, "UUID"); + obj.LocalID = (uint)reader.ReadElementContentAsLong("LocalId", String.Empty); + obj.Name = reader.ReadElementString("Name"); + obj.Material = reader.ReadElementContentAsInt("Material", String.Empty); + + if (reader.Name == "PassTouches") + obj.PassTouches = reader.ReadElementContentAsBoolean("PassTouches", String.Empty); + else + obj.PassTouches = false; + + obj.RegionHandle = (ulong)reader.ReadElementContentAsLong("RegionHandle", String.Empty); + obj.RemoteScriptAccessPIN = reader.ReadElementContentAsInt("ScriptAccessPin", String.Empty); + + if (reader.Name == "PlaySoundSlavePrims") + reader.ReadInnerXml(); + if (reader.Name == "LoopSoundSlavePrims") + reader.ReadInnerXml(); + + Vector3 groupPosition = ReadVector(reader, "GroupPosition"); + Vector3 offsetPosition = ReadVector(reader, "OffsetPosition"); + obj.Rotation = ReadQuaternion(reader, "RotationOffset"); + obj.Velocity = ReadVector(reader, "Velocity"); + if (reader.Name == "RotationalVelocity") + ReadVector(reader, "RotationalVelocity"); + obj.AngularVelocity = ReadVector(reader, "AngularVelocity"); + obj.Acceleration = ReadVector(reader, "Acceleration"); + obj.Description = reader.ReadElementString("Description"); + reader.ReadStartElement("Color"); + if (reader.Name == "R") + { + obj.TextColor.R = reader.ReadElementContentAsFloat("R", String.Empty); + obj.TextColor.G = reader.ReadElementContentAsFloat("G", String.Empty); + obj.TextColor.B = reader.ReadElementContentAsFloat("B", String.Empty); + obj.TextColor.A = reader.ReadElementContentAsFloat("A", String.Empty); + reader.ReadEndElement(); + } + obj.Text = reader.ReadElementString("Text", String.Empty); + obj.SitName = reader.ReadElementString("SitName", String.Empty); + obj.TouchName = reader.ReadElementString("TouchName", String.Empty); + + obj.LinkNumber = reader.ReadElementContentAsInt("LinkNum", String.Empty); + obj.ClickAction = reader.ReadElementContentAsInt("ClickAction", String.Empty); + + reader.ReadStartElement("Shape"); + obj.Shape.ProfileCurve = reader.ReadElementContentAsInt("ProfileCurve", String.Empty); + + byte[] teData = Convert.FromBase64String(reader.ReadElementString("TextureEntry")); + obj.Textures = new Primitive.TextureEntry(teData, 0, teData.Length); + + reader.ReadInnerXml(); // ExtraParams + + obj.Shape.PathBegin = Primitive.UnpackBeginCut((ushort)reader.ReadElementContentAsInt("PathBegin", String.Empty)); + obj.Shape.PathCurve = reader.ReadElementContentAsInt("PathCurve", String.Empty); + obj.Shape.PathEnd = Primitive.UnpackEndCut((ushort)reader.ReadElementContentAsInt("PathEnd", String.Empty)); + obj.Shape.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathRadiusOffset", String.Empty)); + obj.Shape.PathRevolutions = Primitive.UnpackPathRevolutions((byte)reader.ReadElementContentAsInt("PathRevolutions", String.Empty)); + obj.Shape.PathScaleX = Primitive.UnpackPathScale((byte)reader.ReadElementContentAsInt("PathScaleX", String.Empty)); + obj.Shape.PathScaleY = Primitive.UnpackPathScale((byte)reader.ReadElementContentAsInt("PathScaleY", String.Empty)); + obj.Shape.PathShearX = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathShearX", String.Empty)); + obj.Shape.PathShearY = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathShearY", String.Empty)); + obj.Shape.PathSkew = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathSkew", String.Empty)); + obj.Shape.PathTaperX = Primitive.UnpackPathTaper((sbyte)reader.ReadElementContentAsInt("PathTaperX", String.Empty)); + obj.Shape.PathTaperY = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathTaperY", String.Empty)); + obj.Shape.PathTwist = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathTwist", String.Empty)); + obj.Shape.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathTwistBegin", String.Empty)); + obj.PCode = reader.ReadElementContentAsInt("PCode", String.Empty); + obj.Shape.ProfileBegin = Primitive.UnpackBeginCut((ushort)reader.ReadElementContentAsInt("ProfileBegin", String.Empty)); + obj.Shape.ProfileEnd = Primitive.UnpackEndCut((ushort)reader.ReadElementContentAsInt("ProfileEnd", String.Empty)); + obj.Shape.ProfileHollow = Primitive.UnpackProfileHollow((ushort)reader.ReadElementContentAsInt("ProfileHollow", String.Empty)); + obj.Scale = ReadVector(reader, "Scale"); + obj.State = (byte)reader.ReadElementContentAsInt("State", String.Empty); + + ProfileShape profileShape = (ProfileShape)Enum.Parse(typeof(ProfileShape), reader.ReadElementString("ProfileShape")); + HoleType holeType = (HoleType)Enum.Parse(typeof(HoleType), reader.ReadElementString("HollowShape")); + obj.Shape.ProfileCurve = (int)profileShape | (int)holeType; + + UUID sculptTexture = ReadUUID(reader, "SculptTexture"); + SculptType sculptType = (SculptType)reader.ReadElementContentAsInt("SculptType", String.Empty); + if (sculptTexture != UUID.Zero) + { + obj.Sculpt = new PrimObject.SculptBlock(); + obj.Sculpt.Texture = sculptTexture; + obj.Sculpt.Type = (int)sculptType; + } + + PrimObject.FlexibleBlock flexible = new PrimObject.FlexibleBlock(); + PrimObject.LightBlock light = new PrimObject.LightBlock(); + + reader.ReadInnerXml(); // SculptData + + flexible.Softness = reader.ReadElementContentAsInt("FlexiSoftness", String.Empty); + flexible.Tension = reader.ReadElementContentAsFloat("FlexiTension", String.Empty); + flexible.Drag = reader.ReadElementContentAsFloat("FlexiDrag", String.Empty); + flexible.Gravity = reader.ReadElementContentAsFloat("FlexiGravity", String.Empty); + flexible.Wind = reader.ReadElementContentAsFloat("FlexiWind", String.Empty); + flexible.Force.X = reader.ReadElementContentAsFloat("FlexiForceX", String.Empty); + flexible.Force.Y = reader.ReadElementContentAsFloat("FlexiForceY", String.Empty); + flexible.Force.Z = reader.ReadElementContentAsFloat("FlexiForceZ", String.Empty); + + light.Color.R = reader.ReadElementContentAsFloat("LightColorR", String.Empty); + light.Color.G = reader.ReadElementContentAsFloat("LightColorG", String.Empty); + light.Color.B = reader.ReadElementContentAsFloat("LightColorB", String.Empty); + light.Color.A = reader.ReadElementContentAsFloat("LightColorA", String.Empty); + light.Radius = reader.ReadElementContentAsFloat("LightRadius", String.Empty); + light.Cutoff = reader.ReadElementContentAsFloat("LightCutoff", String.Empty); + light.Falloff = reader.ReadElementContentAsFloat("LightFalloff", String.Empty); + light.Intensity = reader.ReadElementContentAsFloat("LightIntensity", String.Empty); + + bool hasFlexi = reader.ReadElementContentAsBoolean("FlexiEntry", String.Empty); + bool hasLight = reader.ReadElementContentAsBoolean("LightEntry", String.Empty); + reader.ReadInnerXml(); // SculptEntry + + if (hasFlexi) + obj.Flexible = flexible; + if (hasLight) + obj.Light = light; + + reader.ReadEndElement(); + + obj.Scale = ReadVector(reader, "Scale"); // Yes, again + reader.ReadInnerXml(); // UpdateFlag + + reader.ReadInnerXml(); // SitTargetOrientation + reader.ReadInnerXml(); // SitTargetPosition + obj.SitOffset = ReadVector(reader, "SitTargetPositionLL"); + obj.SitRotation = ReadQuaternion(reader, "SitTargetOrientationLL"); + obj.ParentID = (uint)reader.ReadElementContentAsLong("ParentID", String.Empty); + obj.CreationDate = Utils.UnixTimeToDateTime(reader.ReadElementContentAsInt("CreationDate", String.Empty)); + int category = reader.ReadElementContentAsInt("Category", String.Empty); + obj.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty); + obj.SaleType = reader.ReadElementContentAsInt("ObjectSaleType", String.Empty); + int ownershipCost = reader.ReadElementContentAsInt("OwnershipCost", String.Empty); + obj.GroupID = ReadUUID(reader, "GroupID"); + obj.OwnerID = ReadUUID(reader, "OwnerID"); + obj.LastOwnerID = ReadUUID(reader, "LastOwnerID"); + obj.PermsBase = (uint)reader.ReadElementContentAsInt("BaseMask", String.Empty); + obj.PermsOwner = (uint)reader.ReadElementContentAsInt("OwnerMask", String.Empty); + obj.PermsGroup = (uint)reader.ReadElementContentAsInt("GroupMask", String.Empty); + obj.PermsEveryone = (uint)reader.ReadElementContentAsInt("EveryoneMask", String.Empty); + obj.PermsNextOwner = (uint)reader.ReadElementContentAsInt("NextOwnerMask", String.Empty); + + reader.ReadInnerXml(); // Flags + + obj.CollisionSound = ReadUUID(reader, "CollisionSound"); + obj.CollisionSoundVolume = reader.ReadElementContentAsFloat("CollisionSoundVolume", String.Empty); + + reader.ReadEndElement(); + + if (obj.ParentID == 0) + obj.Position = groupPosition; + else + obj.Position = offsetPosition; + + return obj; + } + + static UUID ReadUUID(XmlTextReader reader, string name) + { + UUID id; + string idStr; + + reader.ReadStartElement(name); + + if (reader.Name == "Guid") + idStr = reader.ReadElementString("Guid"); + else // UUID + idStr = reader.ReadElementString("UUID"); + + UUID.TryParse(idStr, out id); + reader.ReadEndElement(); + + return id; + } + + static Vector3 ReadVector(XmlTextReader reader, string name) + { + Vector3 vec; + + reader.ReadStartElement(name); + vec.X = reader.ReadElementContentAsFloat("X", String.Empty); + vec.Y = reader.ReadElementContentAsFloat("Y", String.Empty); + vec.Z = reader.ReadElementContentAsFloat("Z", String.Empty); + reader.ReadEndElement(); + + return vec; + } + + static Quaternion ReadQuaternion(XmlTextReader reader, string name) + { + Quaternion quat; + + reader.ReadStartElement(name); + quat.X = reader.ReadElementContentAsFloat("X", String.Empty); + quat.Y = reader.ReadElementContentAsFloat("Y", String.Empty); + quat.Z = reader.ReadElementContentAsFloat("Z", String.Empty); + quat.W = reader.ReadElementContentAsFloat("W", String.Empty); + reader.ReadEndElement(); + + return quat; + } + } + + /// + /// The deserialized form of a single primitive in a linkset asset + /// + public class PrimObject + { + public class FlexibleBlock + { + public int Softness; + public float Gravity; + public float Drag; + public float Wind; + public float Tension; + public Vector3 Force; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["softness"] = OSD.FromInteger(Softness); + map["gravity"] = OSD.FromReal(Gravity); + map["drag"] = OSD.FromReal(Drag); + map["wind"] = OSD.FromReal(Wind); + map["tension"] = OSD.FromReal(Tension); + map["force"] = OSD.FromVector3(Force); + return map; + } + + public void Deserialize(OSDMap map) + { + Softness = map["softness"].AsInteger(); + Gravity = (float)map["gravity"].AsReal(); + Drag = (float)map["drag"].AsReal(); + Wind = (float)map["wind"].AsReal(); + Tension = (float)map["tension"].AsReal(); + Force = map["force"].AsVector3(); + } + } + + public class LightBlock + { + public Color4 Color; + public float Intensity; + public float Radius; + public float Falloff; + public float Cutoff; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["color"] = OSD.FromColor4(Color); + map["intensity"] = OSD.FromReal(Intensity); + map["radius"] = OSD.FromReal(Radius); + map["falloff"] = OSD.FromReal(Falloff); + map["cutoff"] = OSD.FromReal(Cutoff); + return map; + } + + public void Deserialize(OSDMap map) + { + Color = map["color"].AsColor4(); + Intensity = (float)map["intensity"].AsReal(); + Radius = (float)map["radius"].AsReal(); + Falloff = (float)map["falloff"].AsReal(); + Cutoff = (float)map["cutoff"].AsReal(); + } + } + + public class SculptBlock + { + public UUID Texture; + public int Type; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["texture"] = OSD.FromUUID(Texture); + map["type"] = OSD.FromInteger(Type); + return map; + } + + public void Deserialize(OSDMap map) + { + Texture = map["texture"].AsUUID(); + Type = map["type"].AsInteger(); + } + } + + public class ParticlesBlock + { + public int Flags; + public int Pattern; + public float MaxAge; + public float StartAge; + public float InnerAngle; + public float OuterAngle; + public float BurstRate; + public float BurstRadius; + public float BurstSpeedMin; + public float BurstSpeedMax; + public int BurstParticleCount; + public Vector3 AngularVelocity; + public Vector3 Acceleration; + public UUID TextureID; + public UUID TargetID; + public int DataFlags; + public float ParticleMaxAge; + public Color4 ParticleStartColor; + public Color4 ParticleEndColor; + public Vector2 ParticleStartScale; + public Vector2 ParticleEndScale; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["flags"] = OSD.FromInteger(Flags); + map["pattern"] = OSD.FromInteger(Pattern); + map["max_age"] = OSD.FromReal(MaxAge); + map["start_age"] = OSD.FromReal(StartAge); + map["inner_angle"] = OSD.FromReal(InnerAngle); + map["outer_angle"] = OSD.FromReal(OuterAngle); + map["burst_rate"] = OSD.FromReal(BurstRate); + map["burst_radius"] = OSD.FromReal(BurstRadius); + map["burst_speed_min"] = OSD.FromReal(BurstSpeedMin); + map["burst_speed_max"] = OSD.FromReal(BurstSpeedMax); + map["burst_particle_count"] = OSD.FromInteger(BurstParticleCount); + map["angular_velocity"] = OSD.FromVector3(AngularVelocity); + map["acceleration"] = OSD.FromVector3(Acceleration); + map["texture_id"] = OSD.FromUUID(TextureID); + map["target_id"] = OSD.FromUUID(TargetID); + map["data_flags"] = OSD.FromInteger(DataFlags); + map["particle_max_age"] = OSD.FromReal(ParticleMaxAge); + map["particle_start_color"] = OSD.FromColor4(ParticleStartColor); + map["particle_end_color"] = OSD.FromColor4(ParticleEndColor); + map["particle_start_scale"] = OSD.FromVector2(ParticleStartScale); + map["particle_end_scale"] = OSD.FromVector2(ParticleEndScale); + return map; + } + + public void Deserialize(OSDMap map) + { + Flags = map["flags"].AsInteger(); + Pattern = map["pattern"].AsInteger(); + MaxAge = (float)map["max_age"].AsReal(); + StartAge = (float)map["start_age"].AsReal(); + InnerAngle = (float)map["inner_angle"].AsReal(); + OuterAngle = (float)map["outer_angle"].AsReal(); + BurstRate = (float)map["burst_rate"].AsReal(); + BurstRadius = (float)map["burst_radius"].AsReal(); + BurstSpeedMin = (float)map["burst_speed_min"].AsReal(); + BurstSpeedMax = (float)map["burst_speed_max"].AsReal(); + BurstParticleCount = map["burst_particle_count"].AsInteger(); + AngularVelocity = map["angular_velocity"].AsVector3(); + Acceleration = map["acceleration"].AsVector3(); + TextureID = map["texture_id"].AsUUID(); + DataFlags = map["data_flags"].AsInteger(); + ParticleMaxAge = (float)map["particle_max_age"].AsReal(); + ParticleStartColor = map["particle_start_color"].AsColor4(); + ParticleEndColor = map["particle_end_color"].AsColor4(); + ParticleStartScale = map["particle_start_scale"].AsVector2(); + ParticleEndScale = map["particle_end_scale"].AsVector2(); + } + } + + public class ShapeBlock + { + public int PathCurve; + public float PathBegin; + public float PathEnd; + public float PathScaleX; + public float PathScaleY; + public float PathShearX; + public float PathShearY; + public float PathTwist; + public float PathTwistBegin; + public float PathRadiusOffset; + public float PathTaperX; + public float PathTaperY; + public float PathRevolutions; + public float PathSkew; + public int ProfileCurve; + public float ProfileBegin; + public float ProfileEnd; + public float ProfileHollow; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["path_curve"] = OSD.FromInteger(PathCurve); + map["path_begin"] = OSD.FromReal(PathBegin); + map["path_end"] = OSD.FromReal(PathEnd); + map["path_scale_x"] = OSD.FromReal(PathScaleX); + map["path_scale_y"] = OSD.FromReal(PathScaleY); + map["path_shear_x"] = OSD.FromReal(PathShearX); + map["path_shear_y"] = OSD.FromReal(PathShearY); + map["path_twist"] = OSD.FromReal(PathTwist); + map["path_twist_begin"] = OSD.FromReal(PathTwistBegin); + map["path_radius_offset"] = OSD.FromReal(PathRadiusOffset); + map["path_taper_x"] = OSD.FromReal(PathTaperX); + map["path_taper_y"] = OSD.FromReal(PathTaperY); + map["path_revolutions"] = OSD.FromReal(PathRevolutions); + map["path_skew"] = OSD.FromReal(PathSkew); + map["profile_curve"] = OSD.FromInteger(ProfileCurve); + map["profile_begin"] = OSD.FromReal(ProfileBegin); + map["profile_end"] = OSD.FromReal(ProfileEnd); + map["profile_hollow"] = OSD.FromReal(ProfileHollow); + return map; + } + + public void Deserialize(OSDMap map) + { + PathCurve = map["path_curve"].AsInteger(); + PathBegin = (float)map["path_begin"].AsReal(); + PathEnd = (float)map["path_end"].AsReal(); + PathScaleX = (float)map["path_scale_x"].AsReal(); + PathScaleY = (float)map["path_scale_y"].AsReal(); + PathShearX = (float)map["path_shear_x"].AsReal(); + PathShearY = (float)map["path_shear_y"].AsReal(); + PathTwist = (float)map["path_twist"].AsReal(); + PathTwistBegin = (float)map["path_twist_begin"].AsReal(); + PathRadiusOffset = (float)map["path_radius_offset"].AsReal(); + PathTaperX = (float)map["path_taper_x"].AsReal(); + PathTaperY = (float)map["path_taper_y"].AsReal(); + PathRevolutions = (float)map["path_revolutions"].AsReal(); + PathSkew = (float)map["path_skew"].AsReal(); + ProfileCurve = map["profile_curve"].AsInteger(); + ProfileBegin = (float)map["profile_begin"].AsReal(); + ProfileEnd = (float)map["profile_end"].AsReal(); + ProfileHollow = (float)map["profile_hollow"].AsReal(); + } + } + + public class InventoryBlock + { + public class ItemBlock + { + public UUID ID; + public string Name; + public UUID OwnerID; + public UUID CreatorID; + public UUID GroupID; + public UUID LastOwnerID; + public UUID PermsGranterID; + public UUID AssetID; + public AssetType Type; + public InventoryType InvType; + public string Description; + public uint PermsBase; + public uint PermsOwner; + public uint PermsGroup; + public uint PermsEveryone; + public uint PermsNextOwner; + public int Flags; + public DateTime CreationDate; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["id"] = OSD.FromUUID(ID); + map["name"] = OSD.FromString(Name); + map["owner_id"] = OSD.FromUUID(OwnerID); + map["creator_id"] = OSD.FromUUID(CreatorID); + map["group_id"] = OSD.FromUUID(GroupID); + map["last_owner_id"] = OSD.FromUUID(LastOwnerID); + map["perms_granter_id"] = OSD.FromUUID(PermsGranterID); + map["asset_id"] = OSD.FromUUID(AssetID); + map["asset_type"] = OSD.FromInteger((int)Type); + map["inv_type"] = OSD.FromInteger((int)InvType); + map["description"] = OSD.FromString(Description); + map["perms_base"] = OSD.FromInteger(PermsBase); + map["perms_owner"] = OSD.FromInteger(PermsOwner); + map["perms_group"] = OSD.FromInteger(PermsGroup); + map["perms_everyone"] = OSD.FromInteger(PermsEveryone); + map["perms_next_owner"] = OSD.FromInteger(PermsNextOwner); + map["flags"] = OSD.FromInteger(Flags); + map["creation_date"] = OSD.FromDate(CreationDate); + return map; + } + + public void Deserialize(OSDMap map) + { + ID = map["id"].AsUUID(); + Name = map["name"].AsString(); + OwnerID = map["owner_id"].AsUUID(); + CreatorID = map["creator_id"].AsUUID(); + GroupID = map["group_id"].AsUUID(); + LastOwnerID = map["last_owner_id"].AsUUID(); + PermsGranterID = map["perms_granter_id"].AsUUID(); + AssetID = map["asset_id"].AsUUID(); + Type = (AssetType)map["asset_type"].AsInteger(); + InvType = (InventoryType)map["inv_type"].AsInteger(); + Description = map["description"].AsString(); + PermsBase = (uint)map["perms_base"].AsInteger(); + PermsOwner = (uint)map["perms_owner"].AsInteger(); + PermsGroup = (uint)map["perms_group"].AsInteger(); + PermsEveryone = (uint)map["perms_everyone"].AsInteger(); + PermsNextOwner = (uint)map["perms_next_owner"].AsInteger(); + Flags = map["flags"].AsInteger(); + CreationDate = map["creation_date"].AsDate(); + } + + public static ItemBlock FromInventoryBase(InventoryItem item) + { + ItemBlock block = new ItemBlock(); + block.AssetID = item.AssetUUID; + block.CreationDate = item.CreationDate; + block.CreatorID = item.CreatorID; + block.Description = item.Description; + block.Flags = (int)item.Flags; + block.GroupID = item.GroupID; + block.ID = item.UUID; + block.InvType = item.InventoryType == InventoryType.Unknown && item.AssetType == AssetType.LSLText ? InventoryType.LSL : item.InventoryType; ; + block.LastOwnerID = item.LastOwnerID; + block.Name = item.Name; + block.OwnerID = item.OwnerID; + block.PermsBase = (uint)item.Permissions.BaseMask; + block.PermsEveryone = (uint)item.Permissions.EveryoneMask; + block.PermsGroup = (uint)item.Permissions.GroupMask; + block.PermsNextOwner = (uint)item.Permissions.NextOwnerMask; + block.PermsOwner = (uint)item.Permissions.OwnerMask; + block.PermsGranterID = UUID.Zero; + block.Type = item.AssetType; + return block; + } + } + + public int Serial; + public ItemBlock[] Items; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["serial"] = OSD.FromInteger(Serial); + + if (Items != null) + { + OSDArray array = new OSDArray(Items.Length); + for (int i = 0; i < Items.Length; i++) + array.Add(Items[i].Serialize()); + map["items"] = array; + } + + return map; + } + + public void Deserialize(OSDMap map) + { + Serial = map["serial"].AsInteger(); + + if (map.ContainsKey("items")) + { + OSDArray array = (OSDArray)map["items"]; + Items = new ItemBlock[array.Count]; + + for (int i = 0; i < array.Count; i++) + { + ItemBlock item = new ItemBlock(); + item.Deserialize((OSDMap)array[i]); + Items[i] = item; + } + } + else + { + Items = new ItemBlock[0]; + } + } + } + + public UUID ID; + public bool AllowedDrop; + public Vector3 AttachmentPosition; + public Quaternion AttachmentRotation; + public Quaternion BeforeAttachmentRotation; + public string Name; + public string Description; + public uint PermsBase; + public uint PermsOwner; + public uint PermsGroup; + public uint PermsEveryone; + public uint PermsNextOwner; + public UUID CreatorID; + public UUID OwnerID; + public UUID LastOwnerID; + public UUID GroupID; + public UUID FolderID; + public ulong RegionHandle; + public int ClickAction; + public int LastAttachmentPoint; + public int LinkNumber; + public uint LocalID; + public uint ParentID; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Velocity; + public Vector3 AngularVelocity; + public Vector3 Acceleration; + public Vector3 Scale; + public Vector3 SitOffset; + public Quaternion SitRotation; + public Vector3 CameraEyeOffset; + public Vector3 CameraAtOffset; + public int State; + public int PCode; + public int Material; + public bool PassTouches; + public UUID SoundID; + public float SoundGain; + public float SoundRadius; + public int SoundFlags; + public Color4 TextColor; + public string Text; + public string SitName; + public string TouchName; + public bool Selected; + public UUID SelectorID; + public bool UsePhysics; + public bool Phantom; + public int RemoteScriptAccessPIN; + public bool VolumeDetect; + public bool DieAtEdge; + public bool ReturnAtEdge; + public bool Temporary; + public bool Sandbox; + public DateTime CreationDate; + public DateTime RezDate; + public int SalePrice; + public int SaleType; + public byte[] ScriptState; + public UUID CollisionSound; + public float CollisionSoundVolume; + public FlexibleBlock Flexible; + public LightBlock Light; + public SculptBlock Sculpt; + public ParticlesBlock Particles; + public ShapeBlock Shape; + public Primitive.TextureEntry Textures; + public InventoryBlock Inventory; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["id"] = OSD.FromUUID(ID); + map["attachment_position"] = OSD.FromVector3(AttachmentPosition); + map["attachment_rotation"] = OSD.FromQuaternion(AttachmentRotation); + map["before_attachment_rotation"] = OSD.FromQuaternion(BeforeAttachmentRotation); + map["name"] = OSD.FromString(Name); + map["description"] = OSD.FromString(Description); + map["perms_base"] = OSD.FromInteger(PermsBase); + map["perms_owner"] = OSD.FromInteger(PermsOwner); + map["perms_group"] = OSD.FromInteger(PermsGroup); + map["perms_everyone"] = OSD.FromInteger(PermsEveryone); + map["perms_next_owner"] = OSD.FromInteger(PermsNextOwner); + map["creator_identity"] = OSD.FromUUID(CreatorID); + map["owner_identity"] = OSD.FromUUID(OwnerID); + map["last_owner_identity"] = OSD.FromUUID(LastOwnerID); + map["group_identity"] = OSD.FromUUID(GroupID); + map["folder_id"] = OSD.FromUUID(FolderID); + map["region_handle"] = OSD.FromULong(RegionHandle); + map["click_action"] = OSD.FromInteger(ClickAction); + map["last_attachment_point"] = OSD.FromInteger(LastAttachmentPoint); + map["link_number"] = OSD.FromInteger(LinkNumber); + map["local_id"] = OSD.FromInteger(LocalID); + map["parent_id"] = OSD.FromInteger(ParentID); + map["position"] = OSD.FromVector3(Position); + map["rotation"] = OSD.FromQuaternion(Rotation); + map["velocity"] = OSD.FromVector3(Velocity); + map["angular_velocity"] = OSD.FromVector3(AngularVelocity); + map["acceleration"] = OSD.FromVector3(Acceleration); + map["scale"] = OSD.FromVector3(Scale); + map["sit_offset"] = OSD.FromVector3(SitOffset); + map["sit_rotation"] = OSD.FromQuaternion(SitRotation); + map["camera_eye_offset"] = OSD.FromVector3(CameraEyeOffset); + map["camera_at_offset"] = OSD.FromVector3(CameraAtOffset); + map["state"] = OSD.FromInteger(State); + map["prim_code"] = OSD.FromInteger(PCode); + map["material"] = OSD.FromInteger(Material); + map["pass_touches"] = OSD.FromBoolean(PassTouches); + map["sound_id"] = OSD.FromUUID(SoundID); + map["sound_gain"] = OSD.FromReal(SoundGain); + map["sound_radius"] = OSD.FromReal(SoundRadius); + map["sound_flags"] = OSD.FromInteger(SoundFlags); + map["text_color"] = OSD.FromColor4(TextColor); + map["text"] = OSD.FromString(Text); + map["sit_name"] = OSD.FromString(SitName); + map["touch_name"] = OSD.FromString(TouchName); + map["selected"] = OSD.FromBoolean(Selected); + map["selector_id"] = OSD.FromUUID(SelectorID); + map["use_physics"] = OSD.FromBoolean(UsePhysics); + map["phantom"] = OSD.FromBoolean(Phantom); + map["remote_script_access_pin"] = OSD.FromInteger(RemoteScriptAccessPIN); + map["volume_detect"] = OSD.FromBoolean(VolumeDetect); + map["die_at_edge"] = OSD.FromBoolean(DieAtEdge); + map["return_at_edge"] = OSD.FromBoolean(ReturnAtEdge); + map["temporary"] = OSD.FromBoolean(Temporary); + map["sandbox"] = OSD.FromBoolean(Sandbox); + map["creation_date"] = OSD.FromDate(CreationDate); + map["rez_date"] = OSD.FromDate(RezDate); + map["sale_price"] = OSD.FromInteger(SalePrice); + map["sale_type"] = OSD.FromInteger(SaleType); + + if (Flexible != null) + map["flexible"] = Flexible.Serialize(); + if (Light != null) + map["light"] = Light.Serialize(); + if (Sculpt != null) + map["sculpt"] = Sculpt.Serialize(); + if (Particles != null) + map["particles"] = Particles.Serialize(); + if (Shape != null) + map["shape"] = Shape.Serialize(); + if (Textures != null) + map["textures"] = Textures.GetOSD(); + if (Inventory != null) + map["inventory"] = Inventory.Serialize(); + + return map; + } + + public void Deserialize(OSDMap map) + { + ID = map["id"].AsUUID(); + AttachmentPosition = map["attachment_position"].AsVector3(); + AttachmentRotation = map["attachment_rotation"].AsQuaternion(); + BeforeAttachmentRotation = map["before_attachment_rotation"].AsQuaternion(); + Name = map["name"].AsString(); + Description = map["description"].AsString(); + PermsBase = (uint)map["perms_base"].AsInteger(); + PermsOwner = (uint)map["perms_owner"].AsInteger(); + PermsGroup = (uint)map["perms_group"].AsInteger(); + PermsEveryone = (uint)map["perms_everyone"].AsInteger(); + PermsNextOwner = (uint)map["perms_next_owner"].AsInteger(); + CreatorID = map["creator_identity"].AsUUID(); + OwnerID = map["owner_identity"].AsUUID(); + LastOwnerID = map["last_owner_identity"].AsUUID(); + GroupID = map["group_identity"].AsUUID(); + FolderID = map["folder_id"].AsUUID(); + RegionHandle = map["region_handle"].AsULong(); + ClickAction = map["click_action"].AsInteger(); + LastAttachmentPoint = map["last_attachment_point"].AsInteger(); + LinkNumber = map["link_number"].AsInteger(); + LocalID = (uint)map["local_id"].AsInteger(); + ParentID = (uint)map["parent_id"].AsInteger(); + Position = map["position"].AsVector3(); + Rotation = map["rotation"].AsQuaternion(); + Velocity = map["velocity"].AsVector3(); + AngularVelocity = map["angular_velocity"].AsVector3(); + Acceleration = map["acceleration"].AsVector3(); + Scale = map["scale"].AsVector3(); + SitOffset = map["sit_offset"].AsVector3(); + SitRotation = map["sit_rotation"].AsQuaternion(); + CameraEyeOffset = map["camera_eye_offset"].AsVector3(); + CameraAtOffset = map["camera_at_offset"].AsVector3(); + State = map["state"].AsInteger(); + PCode = map["prim_code"].AsInteger(); + Material = map["material"].AsInteger(); + PassTouches = map["pass_touches"].AsBoolean(); + SoundID = map["sound_id"].AsUUID(); + SoundGain = (float)map["sound_gain"].AsReal(); + SoundRadius = (float)map["sound_radius"].AsReal(); + SoundFlags = map["sound_flags"].AsInteger(); + TextColor = map["text_color"].AsColor4(); + Text = map["text"].AsString(); + SitName = map["sit_name"].AsString(); + TouchName = map["touch_name"].AsString(); + Selected = map["selected"].AsBoolean(); + SelectorID = map["selector_id"].AsUUID(); + UsePhysics = map["use_physics"].AsBoolean(); + Phantom = map["phantom"].AsBoolean(); + RemoteScriptAccessPIN = map["remote_script_access_pin"].AsInteger(); + VolumeDetect = map["volume_detect"].AsBoolean(); + DieAtEdge = map["die_at_edge"].AsBoolean(); + ReturnAtEdge = map["return_at_edge"].AsBoolean(); + Temporary = map["temporary"].AsBoolean(); + Sandbox = map["sandbox"].AsBoolean(); + CreationDate = map["creation_date"].AsDate(); + RezDate = map["rez_date"].AsDate(); + SalePrice = map["sale_price"].AsInteger(); + SaleType = map["sale_type"].AsInteger(); + } + + public static PrimObject FromPrimitive(Primitive obj) + { + PrimObject prim = new PrimObject(); + prim.Acceleration = obj.Acceleration; + prim.AllowedDrop = (obj.Flags & PrimFlags.AllowInventoryDrop) == PrimFlags.AllowInventoryDrop; + prim.AngularVelocity = obj.AngularVelocity; + //prim.AttachmentPosition + //prim.AttachmentRotation + //prim.BeforeAttachmentRotation + //prim.CameraAtOffset + //prim.CameraEyeOffset + prim.ClickAction = (int)obj.ClickAction; + //prim.CollisionSound + //prim.CollisionSoundVolume; + prim.CreationDate = obj.Properties.CreationDate; + prim.CreatorID = obj.Properties.CreatorID; + prim.Description = obj.Properties.Description; + prim.DieAtEdge = (obj.Flags & PrimFlags.DieAtEdge) == PrimFlags.AllowInventoryDrop; + if (obj.Flexible != null) + { + prim.Flexible = new FlexibleBlock(); + prim.Flexible.Drag = obj.Flexible.Drag; + prim.Flexible.Force = obj.Flexible.Force; + prim.Flexible.Gravity = obj.Flexible.Gravity; + prim.Flexible.Softness = obj.Flexible.Softness; + prim.Flexible.Tension = obj.Flexible.Tension; + prim.Flexible.Wind = obj.Flexible.Wind; + } + prim.FolderID = obj.Properties.FolderID; + prim.GroupID = obj.Properties.GroupID; + prim.ID = obj.Properties.ObjectID; + //prim.Inventory; + //prim.LastAttachmentPoint; + prim.LastOwnerID = obj.Properties.LastOwnerID; + if (obj.Light != null) + { + prim.Light = new LightBlock(); + prim.Light.Color = obj.Light.Color; + prim.Light.Cutoff = obj.Light.Cutoff; + prim.Light.Falloff = obj.Light.Falloff; + prim.Light.Intensity = obj.Light.Intensity; + prim.Light.Radius = obj.Light.Radius; + } + + //prim.LinkNumber; + prim.LocalID = obj.LocalID; + prim.Material = (int)obj.PrimData.Material; + prim.Name = obj.Properties.Name; + prim.OwnerID = obj.Properties.OwnerID; + prim.ParentID = obj.ParentID; + + prim.Particles = new ParticlesBlock(); + prim.Particles.AngularVelocity = obj.ParticleSys.AngularVelocity; + prim.Particles.Acceleration = obj.ParticleSys.PartAcceleration; + prim.Particles.BurstParticleCount = obj.ParticleSys.BurstPartCount; + prim.Particles.BurstRate = obj.ParticleSys.BurstRadius; + prim.Particles.BurstRate = obj.ParticleSys.BurstRate; + prim.Particles.BurstSpeedMax = obj.ParticleSys.BurstSpeedMax; + prim.Particles.BurstSpeedMin = obj.ParticleSys.BurstSpeedMin; + prim.Particles.DataFlags = (int)obj.ParticleSys.PartDataFlags; + prim.Particles.Flags = (int)obj.ParticleSys.PartFlags; + prim.Particles.InnerAngle = obj.ParticleSys.InnerAngle; + prim.Particles.MaxAge = obj.ParticleSys.MaxAge; + prim.Particles.OuterAngle = obj.ParticleSys.OuterAngle; + prim.Particles.ParticleEndColor = obj.ParticleSys.PartEndColor; + prim.Particles.ParticleEndScale = new Vector2(obj.ParticleSys.PartEndScaleX, obj.ParticleSys.PartEndScaleY); + prim.Particles.ParticleMaxAge = obj.ParticleSys.MaxAge; + prim.Particles.ParticleStartColor = obj.ParticleSys.PartStartColor; + prim.Particles.ParticleStartScale = new Vector2(obj.ParticleSys.PartStartScaleX, obj.ParticleSys.PartStartScaleY); + prim.Particles.Pattern = (int)obj.ParticleSys.Pattern; + prim.Particles.StartAge = obj.ParticleSys.StartAge; + prim.Particles.TargetID = obj.ParticleSys.Target; + prim.Particles.TextureID = obj.ParticleSys.Texture; + + //prim.PassTouches; + prim.PCode = (int)obj.PrimData.PCode; + prim.PermsBase = (uint)obj.Properties.Permissions.BaseMask; + prim.PermsEveryone = (uint)obj.Properties.Permissions.EveryoneMask; + prim.PermsGroup = (uint)obj.Properties.Permissions.GroupMask; + prim.PermsNextOwner = (uint)obj.Properties.Permissions.NextOwnerMask; + prim.PermsOwner = (uint)obj.Properties.Permissions.OwnerMask; + prim.Phantom = (obj.Flags & PrimFlags.Phantom) == PrimFlags.Phantom; + prim.Position = obj.Position; + prim.RegionHandle = obj.RegionHandle; + //prim.RemoteScriptAccessPIN; + prim.ReturnAtEdge = (obj.Flags & PrimFlags.ReturnAtEdge) == PrimFlags.ReturnAtEdge; + //prim.RezDate; + prim.Rotation = obj.Rotation; + prim.SalePrice = obj.Properties.SalePrice; + prim.SaleType = (int)obj.Properties.SaleType; + prim.Sandbox = (obj.Flags & PrimFlags.Sandbox) == PrimFlags.Sandbox; + prim.Scale = obj.Scale; + //prim.ScriptState; + if (obj.Sculpt != null) + { + prim.Sculpt = new SculptBlock(); + prim.Sculpt.Texture = obj.Sculpt.SculptTexture; + prim.Sculpt.Type = (int)obj.Sculpt.Type; + } + prim.Shape = new ShapeBlock(); + prim.Shape.PathBegin = obj.PrimData.PathBegin; + prim.Shape.PathCurve = (int)obj.PrimData.PathCurve; + prim.Shape.PathEnd = obj.PrimData.PathEnd; + prim.Shape.PathRadiusOffset = obj.PrimData.PathRadiusOffset; + prim.Shape.PathRevolutions = obj.PrimData.PathRevolutions; + prim.Shape.PathScaleX = obj.PrimData.PathScaleX; + prim.Shape.PathScaleY = obj.PrimData.PathScaleY; + prim.Shape.PathShearX = obj.PrimData.PathShearX; + prim.Shape.PathShearY = obj.PrimData.PathShearY; + prim.Shape.PathSkew = obj.PrimData.PathSkew; + prim.Shape.PathTaperX = obj.PrimData.PathTaperX; + prim.Shape.PathTaperY = obj.PrimData.PathTaperY; + + prim.Shape.PathTwist = obj.PrimData.PathTwist; + prim.Shape.PathTwistBegin = obj.PrimData.PathTwistBegin; + prim.Shape.ProfileBegin = obj.PrimData.ProfileBegin; + prim.Shape.ProfileCurve = obj.PrimData.profileCurve; + prim.Shape.ProfileEnd = obj.PrimData.ProfileEnd; + prim.Shape.ProfileHollow = obj.PrimData.ProfileHollow; + + prim.SitName = obj.Properties.SitName; + //prim.SitOffset; + //prim.SitRotation; + prim.SoundFlags = (int)obj.SoundFlags; + prim.SoundGain = obj.SoundGain; + prim.SoundID = obj.Sound; + prim.SoundRadius = obj.SoundRadius; + prim.State = obj.PrimData.State; + prim.Temporary = (obj.Flags & PrimFlags.Temporary) == PrimFlags.Temporary; + prim.Text = obj.Text; + prim.TextColor = obj.TextColor; + prim.Textures = obj.Textures; + //prim.TouchName; + prim.UsePhysics = (obj.Flags & PrimFlags.Physics) == PrimFlags.Physics; + prim.Velocity = obj.Velocity; + + return prim; + } + + public Primitive ToPrimitive() + { + Primitive prim = new Primitive(); + prim.Properties = new Primitive.ObjectProperties(); + + prim.Acceleration = this.Acceleration; + prim.AngularVelocity = this.AngularVelocity; + prim.ClickAction = (ClickAction)this.ClickAction; + prim.Properties.CreationDate = this.CreationDate; + prim.Properties.CreatorID = this.CreatorID; + prim.Properties.Description = this.Description; + if (this.DieAtEdge) prim.Flags |= PrimFlags.DieAtEdge; + prim.Properties.FolderID = this.FolderID; + prim.Properties.GroupID = this.GroupID; + prim.ID = this.ID; + prim.Properties.LastOwnerID = this.LastOwnerID; + prim.LocalID = this.LocalID; + prim.PrimData.Material = (Material)this.Material; + prim.Properties.Name = this.Name; + prim.OwnerID = this.OwnerID; + prim.ParentID = this.ParentID; + prim.PrimData.PCode = (PCode)this.PCode; + prim.Properties.Permissions = new Permissions(this.PermsBase, this.PermsEveryone, this.PermsGroup, this.PermsNextOwner, this.PermsOwner); + if (this.Phantom) prim.Flags |= PrimFlags.Phantom; + prim.Position = this.Position; + if (this.ReturnAtEdge) prim.Flags |= PrimFlags.ReturnAtEdge; + prim.Rotation = this.Rotation; + prim.Properties.SalePrice = this.SalePrice; + prim.Properties.SaleType = (SaleType)this.SaleType; + if (this.Sandbox) prim.Flags |= PrimFlags.Sandbox; + prim.Scale = this.Scale; + prim.SoundFlags = (SoundFlags)this.SoundFlags; + prim.SoundGain = this.SoundGain; + prim.Sound = this.SoundID; + prim.SoundRadius = this.SoundRadius; + prim.PrimData.State = (byte)this.State; + if (this.Temporary) prim.Flags |= PrimFlags.Temporary; + prim.Text = this.Text; + prim.TextColor = this.TextColor; + prim.Textures = this.Textures; + if (this.UsePhysics) prim.Flags |= PrimFlags.Physics; + prim.Velocity = this.Velocity; + + prim.PrimData.PathBegin = this.Shape.PathBegin; + prim.PrimData.PathCurve = (PathCurve)this.Shape.PathCurve; + prim.PrimData.PathEnd = this.Shape.PathEnd; + prim.PrimData.PathRadiusOffset = this.Shape.PathRadiusOffset; + prim.PrimData.PathRevolutions = this.Shape.PathRevolutions; + prim.PrimData.PathScaleX = this.Shape.PathScaleX; + prim.PrimData.PathScaleY = this.Shape.PathScaleY; + prim.PrimData.PathShearX = this.Shape.PathShearX; + prim.PrimData.PathShearY = this.Shape.PathShearY; + prim.PrimData.PathSkew = this.Shape.PathSkew; + prim.PrimData.PathTaperX = this.Shape.PathTaperX; + prim.PrimData.PathTaperY = this.Shape.PathTaperY; + prim.PrimData.PathTwist = this.Shape.PathTwist; + prim.PrimData.PathTwistBegin = this.Shape.PathTwistBegin; + prim.PrimData.ProfileBegin = this.Shape.ProfileBegin; + prim.PrimData.profileCurve = (byte)this.Shape.ProfileCurve; + prim.PrimData.ProfileEnd = this.Shape.ProfileEnd; + prim.PrimData.ProfileHollow = this.Shape.ProfileHollow; + + if (this.Flexible != null) + { + prim.Flexible = new Primitive.FlexibleData(); + prim.Flexible.Drag = this.Flexible.Drag; + prim.Flexible.Force = this.Flexible.Force; + prim.Flexible.Gravity = this.Flexible.Gravity; + prim.Flexible.Softness = this.Flexible.Softness; + prim.Flexible.Tension = this.Flexible.Tension; + prim.Flexible.Wind = this.Flexible.Wind; + } + + if (this.Light != null) + { + prim.Light = new Primitive.LightData(); + prim.Light.Color = this.Light.Color; + prim.Light.Cutoff = this.Light.Cutoff; + prim.Light.Falloff = this.Light.Falloff; + prim.Light.Intensity = this.Light.Intensity; + prim.Light.Radius = this.Light.Radius; + } + + if (this.Particles != null) + { + prim.ParticleSys = new Primitive.ParticleSystem(); + prim.ParticleSys.AngularVelocity = this.Particles.AngularVelocity; + prim.ParticleSys.PartAcceleration = this.Particles.Acceleration; + prim.ParticleSys.BurstPartCount = (byte)this.Particles.BurstParticleCount; + prim.ParticleSys.BurstRate = this.Particles.BurstRadius; + prim.ParticleSys.BurstRate = this.Particles.BurstRate; + prim.ParticleSys.BurstSpeedMax = this.Particles.BurstSpeedMax; + prim.ParticleSys.BurstSpeedMin = this.Particles.BurstSpeedMin; + prim.ParticleSys.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)this.Particles.DataFlags; + prim.ParticleSys.PartFlags = (uint)this.Particles.Flags; + prim.ParticleSys.InnerAngle = this.Particles.InnerAngle; + prim.ParticleSys.MaxAge = this.Particles.MaxAge; + prim.ParticleSys.OuterAngle = this.Particles.OuterAngle; + prim.ParticleSys.PartEndColor = this.Particles.ParticleEndColor; + prim.ParticleSys.PartEndScaleX = this.Particles.ParticleEndScale.X; + prim.ParticleSys.PartEndScaleY = this.Particles.ParticleEndScale.Y; + prim.ParticleSys.MaxAge = this.Particles.ParticleMaxAge; + prim.ParticleSys.PartStartColor = this.Particles.ParticleStartColor; + prim.ParticleSys.PartStartScaleX = this.Particles.ParticleStartScale.X; + prim.ParticleSys.PartStartScaleY = this.Particles.ParticleStartScale.Y; + prim.ParticleSys.Pattern = (Primitive.ParticleSystem.SourcePattern)this.Particles.Pattern; + prim.ParticleSys.StartAge = this.Particles.StartAge; + prim.ParticleSys.Target = this.Particles.TargetID; + prim.ParticleSys.Texture = this.Particles.TextureID; + } + + if (this.Sculpt != null) + { + prim.Sculpt = new Primitive.SculptData(); + prim.Sculpt.SculptTexture = this.Sculpt.Texture; + prim.Sculpt.Type = (SculptType)this.Sculpt.Type; + } + + return prim; + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs b/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs new file mode 100644 index 0000000..b9cc178 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an AssetScriptBinary object containing the + /// LSO compiled bytecode of an LSL script + /// + public class AssetScriptBinary : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.LSLBytecode; } } + + /// Initializes a new instance of an AssetScriptBinary object + public AssetScriptBinary() { } + + /// Initializes a new instance of an AssetScriptBinary object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetScriptBinary(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + } + + /// + /// TODO: Encodes a scripts contents into a LSO Bytecode file + /// + public override void Encode() { } + + /// + /// TODO: Decode LSO Bytecode into a string + /// + /// true + public override bool Decode() { return true; } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs b/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs new file mode 100644 index 0000000..b423c50 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an LSL Text object containing a string of UTF encoded characters + /// + public class AssetScriptText : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.LSLText; } } + + /// A string of characters represting the script contents + public string Source; + + /// Initializes a new AssetScriptText object + public AssetScriptText() { } + + /// + /// Initializes a new AssetScriptText object with parameters + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetScriptText(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// + /// Encode a string containing the scripts contents into byte encoded AssetData + /// + public override void Encode() + { + AssetData = Utils.StringToBytes(Source); + } + + /// + /// Decode a byte array containing the scripts contents into a string + /// + /// true if decoding is successful + public override bool Decode() + { + Source = Utils.BytesToString(AssetData); + return true; + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetSound.cs b/OpenMetaverse/Assets/AssetTypes/AssetSound.cs new file mode 100644 index 0000000..5e984bf --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetSound.cs @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a Sound Asset + /// + public class AssetSound : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Sound; } } + + /// Initializes a new instance of an AssetSound object + public AssetSound() { } + + /// Initializes a new instance of an AssetSound object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetSound(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + } + + /// + /// TODO: Encodes a sound file + /// + public override void Encode() { } + + /// + /// TODO: Decode a sound file + /// + /// true + public override bool Decode() { return true; } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs b/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs new file mode 100644 index 0000000..3db1a51 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; +using OpenMetaverse.Imaging; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a texture + /// + public class AssetTexture : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Texture; } } + + /// A object containing image data + public ManagedImage Image; + + /// + public OpenJPEG.J2KLayerInfo[] LayerInfo; + + /// + public int Components; + + /// Initializes a new instance of an AssetTexture object + public AssetTexture() { } + + /// + /// Initializes a new instance of an AssetTexture object + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetTexture(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// + /// Initializes a new instance of an AssetTexture object + /// + /// A object containing texture data + public AssetTexture(ManagedImage image) + { + Image = image; + Components = 0; + if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) + Components += 3; + if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) + ++Components; + } + + /// + /// Populates the byte array with a JPEG2000 + /// encoded image created from the data in + /// + public override void Encode() + { + AssetData = OpenJPEG.Encode(Image); + } + + /// + /// Decodes the JPEG2000 data in AssetData to the + /// object + /// + /// True if the decoding was successful, otherwise false + public override bool Decode() + { + if (AssetData != null && AssetData.Length > 0) + { + this.Components = 0; + + if (OpenJPEG.DecodeToImage(AssetData, out Image)) + { + if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) + Components += 3; + if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) + ++Components; + + return true; + } + } + + return false; + } + + /// + /// Decodes the begin and end byte positions for each quality layer in + /// the image + /// + /// + public bool DecodeLayerBoundaries() + { + return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo, out Components); + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs b/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs new file mode 100644 index 0000000..e28619c --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a Wearable Asset, Clothing, Hair, Skin, Etc + /// + public abstract class AssetWearable : Asset + { + /// A string containing the name of the asset + public string Name = String.Empty; + /// A string containing a short description of the asset + public string Description = String.Empty; + /// The Assets WearableType + public WearableType WearableType = WearableType.Shape; + /// The For-Sale status of the object + public SaleType ForSale; + /// An Integer representing the purchase price of the asset + public int SalePrice; + /// The of the assets creator + public UUID Creator; + /// The of the assets current owner + public UUID Owner; + /// The of the assets prior owner + public UUID LastOwner; + /// The of the Group this asset is set to + public UUID Group; + /// True if the asset is owned by a + public bool GroupOwned; + /// The Permissions mask of the asset + public Permissions Permissions; + /// A Dictionary containing Key/Value pairs of the objects parameters + public Dictionary Params = new Dictionary(); + /// A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures + public Dictionary Textures = new Dictionary(); + + /// Initializes a new instance of an AssetWearable object + public AssetWearable() { } + + /// Initializes a new instance of an AssetWearable object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetWearable(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// + /// Decode an assets byte encoded data to a string + /// + /// true if the asset data was decoded successfully + public override bool Decode() + { + if (AssetData == null || AssetData.Length == 0) + return false; + + int version = -1; + Permissions = new Permissions(); + + try + { + string data = Utils.BytesToString(AssetData); + + data = data.Replace("\r", String.Empty); + string[] lines = data.Split('\n'); + for (int stri = 0; stri < lines.Length; stri++) + { + if (stri == 0) + { + string versionstring = lines[stri]; + if (versionstring.Split(' ').Length == 1) + version = Int32.Parse(versionstring); + else + version = Int32.Parse(versionstring.Split(' ')[2]); + if (version != 22 && version != 18 && version != 16 && version != 15) + return false; + } + else if (stri == 1) + { + Name = lines[stri]; + } + else if (stri == 2) + { + Description = lines[stri]; + } + else + { + string line = lines[stri].Trim(); + string[] fields = line.Split('\t'); + + if (fields.Length == 1) + { + fields = line.Split(' '); + if (fields[0] == "parameters") + { + int count = Int32.Parse(fields[1]) + stri; + for (; stri < count; ) + { + stri++; + line = lines[stri].Trim(); + fields = line.Split(' '); + + int id = 0; + + // Special handling for -0 edge case + if (fields[0] != "-0") + id = Int32.Parse(fields[0]); + + if (fields[1] == ",") + fields[1] = "0"; + else + fields[1] = fields[1].Replace(',', '.'); + + float weight = float.Parse(fields[1], System.Globalization.NumberStyles.Float, + Utils.EnUsCulture.NumberFormat); + + Params[id] = weight; + } + } + else if (fields[0] == "textures") + { + int count = Int32.Parse(fields[1]) + stri; + for (; stri < count; ) + { + stri++; + line = lines[stri].Trim(); + fields = line.Split(' '); + + AvatarTextureIndex id = (AvatarTextureIndex)Int32.Parse(fields[0]); + UUID texture = new UUID(fields[1]); + + Textures[id] = texture; + } + } + else if (fields[0] == "type") + { + WearableType = (WearableType)Int32.Parse(fields[1]); + } + + } + else if (fields.Length == 2) + { + switch (fields[0]) + { + case "creator_mask": + // Deprecated, apply this as the base mask + Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "base_mask": + Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "owner_mask": + Permissions.OwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "group_mask": + Permissions.GroupMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "everyone_mask": + Permissions.EveryoneMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "next_owner_mask": + Permissions.NextOwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "creator_id": + Creator = new UUID(fields[1]); + break; + case "owner_id": + Owner = new UUID(fields[1]); + break; + case "last_owner_id": + LastOwner = new UUID(fields[1]); + break; + case "group_id": + Group = new UUID(fields[1]); + break; + case "group_owned": + GroupOwned = (Int32.Parse(fields[1]) != 0); + break; + case "sale_type": + ForSale = Utils.StringToSaleType(fields[1]); + break; + case "sale_price": + SalePrice = Int32.Parse(fields[1]); + break; + case "sale_info": + // Container for sale_type and sale_price, ignore + break; + case "perm_mask": + // Deprecated, apply this as the next owner mask + Permissions.NextOwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + default: + return false; + } + } + } + } + } + catch (Exception ex) + { + Logger.Log("Failed decoding wearable asset " + this.AssetID + ": " + ex.Message, + Helpers.LogLevel.Warning); + return false; + } + + return true; + } + + /// + /// Encode the assets string represantion into a format consumable by the asset server + /// + public override void Encode() + { + const string NL = "\n"; + + StringBuilder data = new StringBuilder("LLWearable version 22\n"); + data.Append(Name); data.Append(NL); data.Append(NL); + data.Append("\tpermissions 0\n\t{\n"); + data.Append("\t\tbase_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.BaseMask)); data.Append(NL); + data.Append("\t\towner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.OwnerMask)); data.Append(NL); + data.Append("\t\tgroup_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.GroupMask)); data.Append(NL); + data.Append("\t\teveryone_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.EveryoneMask)); data.Append(NL); + data.Append("\t\tnext_owner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.NextOwnerMask)); data.Append(NL); + data.Append("\t\tcreator_id\t"); data.Append(Creator.ToString()); data.Append(NL); + data.Append("\t\towner_id\t"); data.Append(Owner.ToString()); data.Append(NL); + data.Append("\t\tlast_owner_id\t"); data.Append(LastOwner.ToString()); data.Append(NL); + data.Append("\t\tgroup_id\t"); data.Append(Group.ToString()); data.Append(NL); + if (GroupOwned) data.Append("\t\tgroup_owned\t1\n"); + data.Append("\t}\n"); + data.Append("\tsale_info\t0\n"); + data.Append("\t{\n"); + data.Append("\t\tsale_type\t"); data.Append(Utils.SaleTypeToString(ForSale)); data.Append(NL); + data.Append("\t\tsale_price\t"); data.Append(SalePrice); data.Append(NL); + data.Append("\t}\n"); + data.Append("type "); data.Append((int)WearableType); data.Append(NL); + + data.Append("parameters "); data.Append(Params.Count); data.Append(NL); + foreach (KeyValuePair param in Params) + { + data.Append(param.Key); data.Append(" "); data.Append(Helpers.FloatToTerseString(param.Value)); data.Append(NL); + } + + data.Append("textures "); data.Append(Textures.Count); data.Append(NL); + foreach (KeyValuePair texture in Textures) + { + data.Append((byte)texture.Key); data.Append(" "); data.Append(texture.Value.ToString()); data.Append(NL); + } + + AssetData = Utils.StringToBytes(data.ToString()); + } + } +} diff --git a/OpenMetaverse/Avatar.cs b/OpenMetaverse/Avatar.cs new file mode 100644 index 0000000..377273b --- /dev/null +++ b/OpenMetaverse/Avatar.cs @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using System.Reflection; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// Avatar profile flags + /// + [Flags] + public enum ProfileFlags : uint + { + AllowPublish = 1, + MaturePublish = 2, + Identified = 4, + Transacted = 8, + Online = 16 + } + + #endregion Enums + + /// + /// Represents an avatar (other than your own) + /// + public class Avatar : Primitive + { + #region Subclasses + + /// + /// Positive and negative ratings + /// + public struct Statistics + { + /// Positive ratings for Behavior + public int BehaviorPositive; + /// Negative ratings for Behavior + public int BehaviorNegative; + /// Positive ratings for Appearance + public int AppearancePositive; + /// Negative ratings for Appearance + public int AppearanceNegative; + /// Positive ratings for Building + public int BuildingPositive; + /// Negative ratings for Building + public int BuildingNegative; + /// Positive ratings given by this avatar + public int GivenPositive; + /// Negative ratings given by this avatar + public int GivenNegative; + + public OSD GetOSD() + { + OSDMap tex = new OSDMap(8); + tex["behavior_positive"] = OSD.FromInteger(BehaviorPositive); + tex["behavior_negative"] = OSD.FromInteger(BehaviorNegative); + tex["appearance_positive"] = OSD.FromInteger(AppearancePositive); + tex["appearance_negative"] = OSD.FromInteger(AppearanceNegative); + tex["buildings_positive"] = OSD.FromInteger(BuildingPositive); + tex["buildings_negative"] = OSD.FromInteger(BuildingNegative); + tex["given_positive"] = OSD.FromInteger(GivenPositive); + tex["given_negative"] = OSD.FromInteger(GivenNegative); + return tex; + } + + public static Statistics FromOSD(OSD O) + { + Statistics S = new Statistics(); + OSDMap tex = (OSDMap)O; + + S.BehaviorPositive = tex["behavior_positive"].AsInteger(); + S.BuildingNegative = tex["behavior_negative"].AsInteger(); + S.AppearancePositive = tex["appearance_positive"].AsInteger(); + S.AppearanceNegative = tex["appearance_negative"].AsInteger(); + S.BuildingPositive = tex["buildings_positive"].AsInteger(); + S.BuildingNegative = tex["buildings_negative"].AsInteger(); + S.GivenPositive = tex["given_positive"].AsInteger(); + S.GivenNegative = tex["given_negative"].AsInteger(); + + + return S; + + } + } + + /// + /// Avatar properties including about text, profile URL, image IDs and + /// publishing settings + /// + public struct AvatarProperties + { + /// First Life about text + public string FirstLifeText; + /// First Life image ID + public UUID FirstLifeImage; + /// + public UUID Partner; + /// + public string AboutText; + /// + public string BornOn; + /// + public string CharterMember; + /// Profile image ID + public UUID ProfileImage; + /// Flags of the profile + public ProfileFlags Flags; + /// Web URL for this profile + public string ProfileURL; + + #region Properties + + /// Should this profile be published on the web + public bool AllowPublish + { + get { return ((Flags & ProfileFlags.AllowPublish) != 0); } + set + { + if (value == true) + Flags |= ProfileFlags.AllowPublish; + else + Flags &= ~ProfileFlags.AllowPublish; + } + } + /// Avatar Online Status + public bool Online + { + get { return ((Flags & ProfileFlags.Online) != 0); } + set + { + if (value == true) + Flags |= ProfileFlags.Online; + else + Flags &= ~ProfileFlags.Online; + } + } + /// Is this a mature profile + public bool MaturePublish + { + get { return ((Flags & ProfileFlags.MaturePublish) != 0); } + set + { + if (value == true) + Flags |= ProfileFlags.MaturePublish; + else + Flags &= ~ProfileFlags.MaturePublish; + } + } + /// + public bool Identified + { + get { return ((Flags & ProfileFlags.Identified) != 0); } + set + { + if (value == true) + Flags |= ProfileFlags.Identified; + else + Flags &= ~ProfileFlags.Identified; + } + } + /// + public bool Transacted + { + get { return ((Flags & ProfileFlags.Transacted) != 0); } + set + { + if (value == true) + Flags |= ProfileFlags.Transacted; + else + Flags &= ~ProfileFlags.Transacted; + } + } + + public OSD GetOSD() + { + OSDMap tex = new OSDMap(9); + tex["first_life_text"] = OSD.FromString(FirstLifeText); + tex["first_life_image"] = OSD.FromUUID(FirstLifeImage); + tex["partner"] = OSD.FromUUID(Partner); + tex["about_text"] = OSD.FromString(AboutText); + tex["born_on"] = OSD.FromString(BornOn); + tex["charter_member"] = OSD.FromString(CharterMember); + tex["profile_image"] = OSD.FromUUID(ProfileImage); + tex["flags"] = OSD.FromInteger((byte)Flags); + tex["profile_url"] = OSD.FromString(ProfileURL); + return tex; + } + + public static AvatarProperties FromOSD(OSD O) + { + AvatarProperties A = new AvatarProperties(); + OSDMap tex = (OSDMap)O; + + A.FirstLifeText = tex["first_life_text"].AsString(); + A.FirstLifeImage = tex["first_life_image"].AsUUID(); + A.Partner = tex["partner"].AsUUID(); + A.AboutText = tex["about_text"].AsString(); + A.BornOn = tex["born_on"].AsString(); + A.CharterMember = tex["chart_member"].AsString(); + A.ProfileImage = tex["profile_image"].AsUUID(); + A.Flags = (ProfileFlags)tex["flags"].AsInteger(); + A.ProfileURL = tex["profile_url"].AsString(); + + return A; + + } + + #endregion Properties + } + + /// + /// Avatar interests including spoken languages, skills, and "want to" + /// choices + /// + public struct Interests + { + /// Languages profile field + public string LanguagesText; + /// + // FIXME: + public uint SkillsMask; + /// + public string SkillsText; + /// + // FIXME: + public uint WantToMask; + /// + public string WantToText; + + public OSD GetOSD() + { + OSDMap InterestsOSD = new OSDMap(5); + InterestsOSD["languages_text"] = OSD.FromString(LanguagesText); + InterestsOSD["skills_mask"] = OSD.FromUInteger(SkillsMask); + InterestsOSD["skills_text"] = OSD.FromString(SkillsText); + InterestsOSD["want_to_mask"] = OSD.FromUInteger(WantToMask); + InterestsOSD["want_to_text"] = OSD.FromString(WantToText); + return InterestsOSD; + } + + public static Interests FromOSD(OSD O) + { + Interests I = new Interests(); + OSDMap tex = (OSDMap)O; + + I.LanguagesText = tex["languages_text"].AsString(); + I.SkillsMask = tex["skills_mask"].AsUInteger(); + I.SkillsText = tex["skills_text"].AsString(); + I.WantToMask = tex["want_to_mask"].AsUInteger(); + I.WantToText = tex["want_to_text"].AsString(); + + return I; + + } + } + + #endregion Subclasses + + #region Public Members + + /// Groups that this avatar is a member of + public List Groups = new List(); + /// Positive and negative ratings + public Statistics ProfileStatistics; + /// Avatar properties including about text, profile URL, image IDs and + /// publishing settings + public AvatarProperties ProfileProperties; + /// Avatar interests including spoken languages, skills, and "want to" + /// choices + public Interests ProfileInterests; + /// Movement control flags for avatars. Typically not set or used by + /// clients. To move your avatar, use Client.Self.Movement instead + public AgentManager.ControlFlags ControlFlags; + + /// + /// Contains the visual parameters describing the deformation of the avatar + /// + public byte[] VisualParameters = null; + + /// + /// Appearance version. Value greater than 0 indicates using server side baking + /// + public byte AppearanceVersion = 0; + + /// + /// Version of the Current Outfit Folder that the appearance is based on + /// + public int COFVersion = 0; + + /// + /// Appearance flags. Introduced with server side baking, currently unused. + /// + public AppearanceFlags AppearanceFlags = AppearanceFlags.None; + + /// + /// List of current avatar animations + /// + public List Animations; + + #endregion Public Members + + protected string name; + protected string groupName; + + #region Properties + + /// First name + public string FirstName + { + get + { + for (int i = 0; i < NameValues.Length; i++) + { + if (NameValues[i].Name == "FirstName" && NameValues[i].Type == NameValue.ValueType.String) + return (string)NameValues[i].Value; + } + + return String.Empty; + } + } + + /// Last name + public string LastName + { + get + { + for (int i = 0; i < NameValues.Length; i++) + { + if (NameValues[i].Name == "LastName" && NameValues[i].Type == NameValue.ValueType.String) + return (string)NameValues[i].Value; + } + + return String.Empty; + } + } + + /// Full name + public string Name + { + get + { + if (!String.IsNullOrEmpty(name)) + { + return name; + } + else if (NameValues != null && NameValues.Length > 0) + { + lock (NameValues) + { + string firstName = String.Empty; + string lastName = String.Empty; + + for (int i = 0; i < NameValues.Length; i++) + { + if (NameValues[i].Name == "FirstName" && NameValues[i].Type == NameValue.ValueType.String) + firstName = (string)NameValues[i].Value; + else if (NameValues[i].Name == "LastName" && NameValues[i].Type == NameValue.ValueType.String) + lastName = (string)NameValues[i].Value; + } + + if (firstName != String.Empty && lastName != String.Empty) + { + name = String.Format("{0} {1}", firstName, lastName); + return name; + } + else + { + return String.Empty; + } + } + } + else + { + return String.Empty; + } + } + } + + /// Active group + public string GroupName + { + get + { + if (!String.IsNullOrEmpty(groupName)) + { + return groupName; + } + else + { + if (NameValues == null || NameValues.Length == 0) + { + return String.Empty; + } + else + { + lock (NameValues) + { + for (int i = 0; i < NameValues.Length; i++) + { + if (NameValues[i].Name == "Title" && NameValues[i].Type == NameValue.ValueType.String) + { + groupName = (string)NameValues[i].Value; + return groupName; + } + } + } + return String.Empty; + } + } + } + } + + public override OSD GetOSD() + { + OSDMap Avi = (OSDMap)base.GetOSD(); + + OSDArray grp = new OSDArray(); + Groups.ForEach(delegate(UUID u) { grp.Add(OSD.FromUUID(u)); }); + + OSDArray vp = new OSDArray(); + + for (int i = 0; i < VisualParameters.Length; i++) + { + vp.Add(OSD.FromInteger(VisualParameters[i])); + } + + Avi["groups"] = grp; + Avi["profile_statistics"] = ProfileStatistics.GetOSD(); + Avi["profile_properties"] = ProfileProperties.GetOSD(); + Avi["profile_interest"] = ProfileInterests.GetOSD(); + Avi["control_flags"] = OSD.FromInteger((byte)ControlFlags); + Avi["visual_parameters"] = vp; + Avi["first_name"] = OSD.FromString(FirstName); + Avi["last_name"] = OSD.FromString(LastName); + Avi["group_name"] = OSD.FromString(GroupName); + + return Avi; + + } + + public static new Avatar FromOSD(OSD O) + { + + OSDMap tex = (OSDMap)O; + + Avatar A = new Avatar(); + + Primitive P = Primitive.FromOSD(O); + + Type Prim = typeof(Primitive); + + FieldInfo[] Fields = Prim.GetFields(); + + for (int x = 0; x < Fields.Length; x++) + { + Logger.Log("Field Matched in FromOSD: "+Fields[x].Name, Helpers.LogLevel.Debug); + Fields[x].SetValue(A, Fields[x].GetValue(P)); + } + + A.Groups = new List(); + + foreach (OSD U in (OSDArray)tex["groups"]) + { + A.Groups.Add(U.AsUUID()); + } + + A.ProfileStatistics = Statistics.FromOSD(tex["profile_statistics"]); + A.ProfileProperties = AvatarProperties.FromOSD(tex["profile_properties"]); + A.ProfileInterests = Interests.FromOSD(tex["profile_interest"]); + A.ControlFlags = (AgentManager.ControlFlags)tex["control_flags"].AsInteger(); + + OSDArray vp = (OSDArray)tex["visual_parameters"]; + A.VisualParameters = new byte[vp.Count]; + + for (int i = 0; i < vp.Count; i++) + { + A.VisualParameters[i] = (byte)vp[i].AsInteger(); + } + + // *********************From Code Above ******************************* + /*if (NameValues[i].Name == "FirstName" && NameValues[i].Type == NameValue.ValueType.String) + firstName = (string)NameValues[i].Value; + else if (NameValues[i].Name == "LastName" && NameValues[i].Type == NameValue.ValueType.String) + lastName = (string)NameValues[i].Value;*/ + // ******************************************************************** + + A.NameValues = new NameValue[3]; + + NameValue First = new NameValue(); + First.Name = "FirstName"; + First.Type = NameValue.ValueType.String; + First.Value = tex["first_name"].AsString(); + + NameValue Last = new NameValue(); + Last.Name = "LastName"; + Last.Type = NameValue.ValueType.String; + Last.Value = tex["last_name"].AsString(); + + // ***************From Code Above*************** + // if (NameValues[i].Name == "Title" && NameValues[i].Type == NameValue.ValueType.String) + // ********************************************* + + NameValue Group = new NameValue(); + Group.Name = "Title"; + Group.Type = NameValue.ValueType.String; + Group.Value = tex["group_name"].AsString(); + + + + A.NameValues[0] = First; + A.NameValues[1] = Last; + A.NameValues[2] = Group; + + return A; + + + } + + #endregion Properties + + #region Constructors + + /// + /// Default constructor + /// + public Avatar() + { + } + + #endregion Constructors + } +} diff --git a/OpenMetaverse/AvatarManager.cs b/OpenMetaverse/AvatarManager.cs new file mode 100644 index 0000000..df036ed --- /dev/null +++ b/OpenMetaverse/AvatarManager.cs @@ -0,0 +1,1705 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse.Http; +using OpenMetaverse.Packets; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse +{ + + #region Structs + /// Information about agents display name + public class AgentDisplayName + { + /// Agent UUID + public UUID ID; + /// Username + public string UserName; + /// Display name + public string DisplayName; + /// First name (legacy) + public string LegacyFirstName; + /// Last name (legacy) + public string LegacyLastName; + /// Full name (legacy) + public string LegacyFullName { get { return string.Format("{0} {1}", LegacyFirstName, LegacyLastName); } } + /// Is display name default display name + public bool IsDefaultDisplayName; + /// Cache display name until + public DateTime NextUpdate; + /// Last updated timestamp + public DateTime Updated; + + /// + /// Creates AgentDisplayName object from OSD + /// + /// Incoming OSD data + /// AgentDisplayName object + public static AgentDisplayName FromOSD(OSD data) + { + AgentDisplayName ret = new AgentDisplayName(); + + OSDMap map = (OSDMap)data; + ret.ID = map["id"]; + ret.UserName = map["username"]; + ret.DisplayName = map["display_name"]; + ret.LegacyFirstName = map["legacy_first_name"]; + ret.LegacyLastName = map["legacy_last_name"]; + ret.IsDefaultDisplayName = map["is_display_name_default"]; + ret.NextUpdate = map["display_name_next_update"]; + ret.Updated = map["last_updated"]; + + return ret; + } + + /// + /// Return object as OSD map + /// + /// OSD containing agent's display name data + public OSD GetOSD() + { + OSDMap map = new OSDMap(); + + map["id"] = ID; + map["username"] = UserName; + map["display_name"] = DisplayName; + map["legacy_first_name"] = LegacyFirstName; + map["legacy_last_name"] = LegacyLastName; + map["is_display_name_default"] = IsDefaultDisplayName; + map["display_name_next_update"] = NextUpdate; + map["last_updated"] = Updated; + + return map; + } + + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// + /// Holds group information for Avatars such as those you might find in a profile + /// + public struct AvatarGroup + { + /// true of Avatar accepts group notices + public bool AcceptNotices; + /// Groups Key + public UUID GroupID; + /// Texture Key for groups insignia + public UUID GroupInsigniaID; + /// Name of the group + public string GroupName; + /// Powers avatar has in the group + public GroupPowers GroupPowers; + /// Avatars Currently selected title + public string GroupTitle; + /// true of Avatar has chosen to list this in their profile + public bool ListInProfile; + } + + /// + /// Contains an animation currently being played by an agent + /// + public struct Animation + { + /// The ID of the animation asset + public UUID AnimationID; + /// A number to indicate start order of currently playing animations + /// On Linden Grids this number is unique per region, with OpenSim it is per client + public int AnimationSequence; + /// + public UUID AnimationSourceObjectID; + } + + /// + /// Holds group information on an individual profile pick + /// + public struct ProfilePick + { + public UUID PickID; + public UUID CreatorID; + public bool TopPick; + public UUID ParcelID; + public string Name; + public string Desc; + public UUID SnapshotID; + public string User; + public string OriginalName; + public string SimName; + public Vector3d PosGlobal; + public int SortOrder; + public bool Enabled; + } + + public struct ClassifiedAd + { + public UUID ClassifiedID; + public uint Catagory; + public UUID ParcelID; + public uint ParentEstate; + public UUID SnapShotID; + public Vector3d Position; + public byte ClassifiedFlags; + public int Price; + public string Name; + public string Desc; + } + #endregion + + /// + /// Retrieve friend status notifications, and retrieve avatar names and + /// profiles + /// + public class AvatarManager + { + const int MAX_UUIDS_PER_PACKET = 100; + + #region Events + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarAnimation; + + ///Raises the AvatarAnimation Event + /// An AvatarAnimationEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarAnimation(AvatarAnimationEventArgs e) + { + EventHandler handler = m_AvatarAnimation; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarAnimationLock = new object(); + + /// Raised when the simulator sends us data containing + /// an agents animation playlist + public event EventHandler AvatarAnimation + { + add { lock (m_AvatarAnimationLock) { m_AvatarAnimation += value; } } + remove { lock (m_AvatarAnimationLock) { m_AvatarAnimation -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarAppearance; + + ///Raises the AvatarAppearance Event + /// A AvatarAppearanceEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarAppearance(AvatarAppearanceEventArgs e) + { + EventHandler handler = m_AvatarAppearance; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarAppearanceLock = new object(); + + /// Raised when the simulator sends us data containing + /// the appearance information for an agent + public event EventHandler AvatarAppearance + { + add { lock (m_AvatarAppearanceLock) { m_AvatarAppearance += value; } } + remove { lock (m_AvatarAppearanceLock) { m_AvatarAppearance -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_UUIDNameReply; + + ///Raises the UUIDNameReply Event + /// A UUIDNameReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnUUIDNameReply(UUIDNameReplyEventArgs e) + { + EventHandler handler = m_UUIDNameReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_UUIDNameReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// agent names/id values + public event EventHandler UUIDNameReply + { + add { lock (m_UUIDNameReplyLock) { m_UUIDNameReply += value; } } + remove { lock (m_UUIDNameReplyLock) { m_UUIDNameReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarInterestsReply; + + ///Raises the AvatarInterestsReply Event + /// A AvatarInterestsReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarInterestsReply(AvatarInterestsReplyEventArgs e) + { + EventHandler handler = m_AvatarInterestsReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarInterestsReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the interests listed in an agents profile + public event EventHandler AvatarInterestsReply + { + add { lock (m_AvatarInterestsReplyLock) { m_AvatarInterestsReply += value; } } + remove { lock (m_AvatarInterestsReplyLock) { m_AvatarInterestsReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarPropertiesReply; + + ///Raises the AvatarPropertiesReply Event + /// A AvatarPropertiesReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarPropertiesReply(AvatarPropertiesReplyEventArgs e) + { + EventHandler handler = m_AvatarPropertiesReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarPropertiesReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// profile property information for an agent + public event EventHandler AvatarPropertiesReply + { + add { lock (m_AvatarPropertiesReplyLock) { m_AvatarPropertiesReply += value; } } + remove { lock (m_AvatarPropertiesReplyLock) { m_AvatarPropertiesReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarGroupsReply; + + ///Raises the AvatarGroupsReply Event + /// A AvatarGroupsReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarGroupsReply(AvatarGroupsReplyEventArgs e) + { + EventHandler handler = m_AvatarGroupsReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarGroupsReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the group membership an agent is a member of + public event EventHandler AvatarGroupsReply + { + add { lock (m_AvatarGroupsReplyLock) { m_AvatarGroupsReply += value; } } + remove { lock (m_AvatarGroupsReplyLock) { m_AvatarGroupsReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarPickerReply; + + ///Raises the AvatarPickerReply Event + /// A AvatarPickerReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarPickerReply(AvatarPickerReplyEventArgs e) + { + EventHandler handler = m_AvatarPickerReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarPickerReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// name/id pair + public event EventHandler AvatarPickerReply + { + add { lock (m_AvatarPickerReplyLock) { m_AvatarPickerReply += value; } } + remove { lock (m_AvatarPickerReplyLock) { m_AvatarPickerReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_ViewerEffectPointAt; + + ///Raises the ViewerEffectPointAt Event + /// A ViewerEffectPointAtEventArgs object containing + /// the data sent from the simulator + protected virtual void OnViewerEffectPointAt(ViewerEffectPointAtEventArgs e) + { + EventHandler handler = m_ViewerEffectPointAt; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ViewerEffectPointAtLock = new object(); + + /// Raised when the simulator sends us data containing + /// the objects and effect when an agent is pointing at + public event EventHandler ViewerEffectPointAt + { + add { lock (m_ViewerEffectPointAtLock) { m_ViewerEffectPointAt += value; } } + remove { lock (m_ViewerEffectPointAtLock) { m_ViewerEffectPointAt -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_ViewerEffectLookAt; + + ///Raises the ViewerEffectLookAt Event + /// A ViewerEffectLookAtEventArgs object containing + /// the data sent from the simulator + protected virtual void OnViewerEffectLookAt(ViewerEffectLookAtEventArgs e) + { + EventHandler handler = m_ViewerEffectLookAt; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ViewerEffectLookAtLock = new object(); + + /// Raised when the simulator sends us data containing + /// the objects and effect when an agent is looking at + public event EventHandler ViewerEffectLookAt + { + add { lock (m_ViewerEffectLookAtLock) { m_ViewerEffectLookAt += value; } } + remove { lock (m_ViewerEffectLookAtLock) { m_ViewerEffectLookAt -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_ViewerEffect; + + ///Raises the ViewerEffect Event + /// A ViewerEffectEventArgs object containing + /// the data sent from the simulator + protected virtual void OnViewerEffect(ViewerEffectEventArgs e) + { + EventHandler handler = m_ViewerEffect; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ViewerEffectLock = new object(); + + /// Raised when the simulator sends us data containing + /// an agents viewer effect information + public event EventHandler ViewerEffect + { + add { lock (m_ViewerEffectLock) { m_ViewerEffect += value; } } + remove { lock (m_ViewerEffectLock) { m_ViewerEffect -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarPicksReply; + + ///Raises the AvatarPicksReply Event + /// A AvatarPicksReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarPicksReply(AvatarPicksReplyEventArgs e) + { + EventHandler handler = m_AvatarPicksReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarPicksReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the top picks from an agents profile + public event EventHandler AvatarPicksReply + { + add { lock (m_AvatarPicksReplyLock) { m_AvatarPicksReply += value; } } + remove { lock (m_AvatarPicksReplyLock) { m_AvatarPicksReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_PickInfoReply; + + ///Raises the PickInfoReply Event + /// A PickInfoReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnPickInfoReply(PickInfoReplyEventArgs e) + { + EventHandler handler = m_PickInfoReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_PickInfoReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the Pick details + public event EventHandler PickInfoReply + { + add { lock (m_PickInfoReplyLock) { m_PickInfoReply += value; } } + remove { lock (m_PickInfoReplyLock) { m_PickInfoReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarClassifiedReply; + + ///Raises the AvatarClassifiedReply Event + /// A AvatarClassifiedReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarClassifiedReply(AvatarClassifiedReplyEventArgs e) + { + EventHandler handler = m_AvatarClassifiedReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarClassifiedReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the classified ads an agent has placed + public event EventHandler AvatarClassifiedReply + { + add { lock (m_AvatarClassifiedReplyLock) { m_AvatarClassifiedReply += value; } } + remove { lock (m_AvatarClassifiedReplyLock) { m_AvatarClassifiedReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_ClassifiedInfoReply; + + ///Raises the ClassifiedInfoReply Event + /// A ClassifiedInfoReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnClassifiedInfoReply(ClassifiedInfoReplyEventArgs e) + { + EventHandler handler = m_ClassifiedInfoReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ClassifiedInfoReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the details of a classified ad + public event EventHandler ClassifiedInfoReply + { + add { lock (m_ClassifiedInfoReplyLock) { m_ClassifiedInfoReply += value; } } + remove { lock (m_ClassifiedInfoReplyLock) { m_ClassifiedInfoReply -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_DisplayNameUpdate; + + ///Raises the DisplayNameUpdate Event + /// A DisplayNameUpdateEventArgs object containing + /// the data sent from the simulator + protected virtual void OnDisplayNameUpdate(DisplayNameUpdateEventArgs e) + { + EventHandler handler = m_DisplayNameUpdate; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DisplayNameUpdateLock = new object(); + + /// Raised when the simulator sends us data containing + /// the details of display name change + public event EventHandler DisplayNameUpdate + { + add { lock (m_DisplayNameUpdateLock) { m_DisplayNameUpdate += value; } } + remove { lock (m_DisplayNameUpdateLock) { m_DisplayNameUpdate -= value; } } + } + + #endregion Events + + #region Delegates + /// + /// Callback giving results when fetching display names + /// + /// If the request was successful + /// Array of display names + /// Array of UUIDs that could not be fetched + public delegate void DisplayNamesCallback(bool success, AgentDisplayName[] names, UUID[] badIDs); + #endregion Delegates + + private GridClient Client; + + /// + /// Represents other avatars + /// + /// + public AvatarManager(GridClient client) + { + Client = client; + + // Avatar appearance callback + Client.Network.RegisterCallback(PacketType.AvatarAppearance, AvatarAppearanceHandler); + + // Avatar profile callbacks + Client.Network.RegisterCallback(PacketType.AvatarPropertiesReply, AvatarPropertiesHandler); + // Client.Network.RegisterCallback(PacketType.AvatarStatisticsReply, AvatarStatisticsHandler); + Client.Network.RegisterCallback(PacketType.AvatarInterestsReply, AvatarInterestsHandler); + + // Avatar group callback + Client.Network.RegisterCallback(PacketType.AvatarGroupsReply, AvatarGroupsReplyHandler); + Client.Network.RegisterEventCallback("AgentGroupDataUpdate", AvatarGroupsReplyMessageHandler); + Client.Network.RegisterEventCallback("AvatarGroupsReply", AvatarGroupsReplyMessageHandler); + + // Viewer effect callback + Client.Network.RegisterCallback(PacketType.ViewerEffect, ViewerEffectHandler); + + // Other callbacks + Client.Network.RegisterCallback(PacketType.UUIDNameReply, UUIDNameReplyHandler); + Client.Network.RegisterCallback(PacketType.AvatarPickerReply, AvatarPickerReplyHandler); + Client.Network.RegisterCallback(PacketType.AvatarAnimation, AvatarAnimationHandler); + + // Picks callbacks + Client.Network.RegisterCallback(PacketType.AvatarPicksReply, AvatarPicksReplyHandler); + Client.Network.RegisterCallback(PacketType.PickInfoReply, PickInfoReplyHandler); + + // Classifieds callbacks + Client.Network.RegisterCallback(PacketType.AvatarClassifiedReply, AvatarClassifiedReplyHandler); + Client.Network.RegisterCallback(PacketType.ClassifiedInfoReply, ClassifiedInfoReplyHandler); + + Client.Network.RegisterEventCallback("DisplayNameUpdate", DisplayNameUpdateMessageHandler); + } + + /// Tracks the specified avatar on your map + /// Avatar ID to track + public void RequestTrackAgent(UUID preyID) + { + TrackAgentPacket p = new TrackAgentPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + p.TargetData.PreyID = preyID; + Client.Network.SendPacket(p); + } + + /// + /// Request a single avatar name + /// + /// The avatar key to retrieve a name for + public void RequestAvatarName(UUID id) + { + UUIDNameRequestPacket request = new UUIDNameRequestPacket(); + request.UUIDNameBlock = new UUIDNameRequestPacket.UUIDNameBlockBlock[1]; + request.UUIDNameBlock[0] = new UUIDNameRequestPacket.UUIDNameBlockBlock(); + request.UUIDNameBlock[0].ID = id; + + Client.Network.SendPacket(request); + } + + /// + /// Request a list of avatar names + /// + /// The avatar keys to retrieve names for + public void RequestAvatarNames(List ids) + { + int m = MAX_UUIDS_PER_PACKET; + int n = ids.Count / m; // Number of full requests to make + int i = 0; + + UUIDNameRequestPacket request; + + for (int j = 0; j < n; j++) + { + request = new UUIDNameRequestPacket(); + request.UUIDNameBlock = new UUIDNameRequestPacket.UUIDNameBlockBlock[m]; + + for (; i < (j + 1) * m; i++) + { + request.UUIDNameBlock[i % m] = new UUIDNameRequestPacket.UUIDNameBlockBlock(); + request.UUIDNameBlock[i % m].ID = ids[i]; + } + + Client.Network.SendPacket(request); + } + + // Get any remaining names after left after the full requests + if (ids.Count > n * m) + { + request = new UUIDNameRequestPacket(); + request.UUIDNameBlock = new UUIDNameRequestPacket.UUIDNameBlockBlock[ids.Count - n * m]; + + for (; i < ids.Count; i++) + { + request.UUIDNameBlock[i % m] = new UUIDNameRequestPacket.UUIDNameBlockBlock(); + request.UUIDNameBlock[i % m].ID = ids[i]; + } + + Client.Network.SendPacket(request); + } + } + + /// + /// Check if Display Names functionality is available + /// + /// True if Display name functionality is available + public bool DisplayNamesAvailable() + { + return (Client.Network.CurrentSim != null && Client.Network.CurrentSim.Caps != null) && Client.Network.CurrentSim.Caps.CapabilityURI("GetDisplayNames") != null; + } + + /// + /// Request retrieval of display names (max 90 names per request) + /// + /// List of UUIDs to lookup + /// Callback to report result of the operation + public void GetDisplayNames(List ids, DisplayNamesCallback callback) + { + if (!DisplayNamesAvailable() || ids.Count == 0) + { + callback(false, null, null); + } + + StringBuilder query = new StringBuilder(); + for (int i = 0; i < ids.Count && i < 90; i++) + { + query.AppendFormat("ids={0}", ids[i]); + if (i < ids.Count - 1) + { + query.Append("&"); + } + } + + Uri uri = new Uri(Client.Network.CurrentSim.Caps.CapabilityURI("GetDisplayNames").AbsoluteUri + "/?" + query); + + CapsClient cap = new CapsClient(uri); + cap.OnComplete += (CapsClient client, OSD result, Exception error) => + { + try + { + if (error != null) + throw error; + GetDisplayNamesMessage msg = new GetDisplayNamesMessage(); + msg.Deserialize((OSDMap)result); + callback(true, msg.Agents, msg.BadIDs); + } + catch (Exception ex) + { + Logger.Log("Failed to call GetDisplayNames capability: ", + Helpers.LogLevel.Warning, Client, ex); + callback(false, null, null); + } + }; + cap.BeginGetResponse(null, String.Empty, Client.Settings.CAPS_TIMEOUT); + } + + /// + /// Start a request for Avatar Properties + /// + /// + public void RequestAvatarProperties(UUID avatarid) + { + AvatarPropertiesRequestPacket aprp = new AvatarPropertiesRequestPacket(); + + aprp.AgentData.AgentID = Client.Self.AgentID; + aprp.AgentData.SessionID = Client.Self.SessionID; + aprp.AgentData.AvatarID = avatarid; + + Client.Network.SendPacket(aprp); + } + + /// + /// Search for an avatar (first name, last name) + /// + /// The name to search for + /// An ID to associate with this query + public void RequestAvatarNameSearch(string name, UUID queryID) + { + AvatarPickerRequestPacket aprp = new AvatarPickerRequestPacket(); + + aprp.AgentData.AgentID = Client.Self.AgentID; + aprp.AgentData.SessionID = Client.Self.SessionID; + aprp.AgentData.QueryID = queryID; + aprp.Data.Name = Utils.StringToBytes(name); + + Client.Network.SendPacket(aprp); + } + + /// + /// Start a request for Avatar Picks + /// + /// UUID of the avatar + public void RequestAvatarPicks(UUID avatarid) + { + GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = Client.Self.AgentID; + gmp.AgentData.SessionID = Client.Self.SessionID; + gmp.AgentData.TransactionID = UUID.Zero; + + gmp.MethodData.Method = Utils.StringToBytes("avatarpicksrequest"); + gmp.MethodData.Invoice = UUID.Zero; + gmp.ParamList = new GenericMessagePacket.ParamListBlock[1]; + gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[0].Parameter = Utils.StringToBytes(avatarid.ToString()); + + Client.Network.SendPacket(gmp); + } + + /// + /// Start a request for Avatar Classifieds + /// + /// UUID of the avatar + public void RequestAvatarClassified(UUID avatarid) + { + GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = Client.Self.AgentID; + gmp.AgentData.SessionID = Client.Self.SessionID; + gmp.AgentData.TransactionID = UUID.Zero; + + gmp.MethodData.Method = Utils.StringToBytes("avatarclassifiedsrequest"); + gmp.MethodData.Invoice = UUID.Zero; + gmp.ParamList = new GenericMessagePacket.ParamListBlock[1]; + gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[0].Parameter = Utils.StringToBytes(avatarid.ToString()); + + Client.Network.SendPacket(gmp); + } + + /// + /// Start a request for details of a specific profile pick + /// + /// UUID of the avatar + /// UUID of the profile pick + public void RequestPickInfo(UUID avatarid, UUID pickid) + { + GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = Client.Self.AgentID; + gmp.AgentData.SessionID = Client.Self.SessionID; + gmp.AgentData.TransactionID = UUID.Zero; + + gmp.MethodData.Method = Utils.StringToBytes("pickinforequest"); + gmp.MethodData.Invoice = UUID.Zero; + gmp.ParamList = new GenericMessagePacket.ParamListBlock[2]; + gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[0].Parameter = Utils.StringToBytes(avatarid.ToString()); + gmp.ParamList[1] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[1].Parameter = Utils.StringToBytes(pickid.ToString()); + + Client.Network.SendPacket(gmp); + } + + /// + /// Start a request for details of a specific profile classified + /// + /// UUID of the avatar + /// UUID of the profile classified + public void RequestClassifiedInfo(UUID avatarid, UUID classifiedid) + { + GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = Client.Self.AgentID; + gmp.AgentData.SessionID = Client.Self.SessionID; + gmp.AgentData.TransactionID = UUID.Zero; + + gmp.MethodData.Method = Utils.StringToBytes("classifiedinforequest"); + gmp.MethodData.Invoice = UUID.Zero; + gmp.ParamList = new GenericMessagePacket.ParamListBlock[2]; + gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[0].Parameter = Utils.StringToBytes(avatarid.ToString()); + gmp.ParamList[1] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[1].Parameter = Utils.StringToBytes(classifiedid.ToString()); + + Client.Network.SendPacket(gmp); + } + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void UUIDNameReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_UUIDNameReply != null) + { + Packet packet = e.Packet; + Dictionary names = new Dictionary(); + UUIDNameReplyPacket reply = (UUIDNameReplyPacket)packet; + + foreach (UUIDNameReplyPacket.UUIDNameBlockBlock block in reply.UUIDNameBlock) + { + names[block.ID] = Utils.BytesToString(block.FirstName) + + " " + Utils.BytesToString(block.LastName); + } + + OnUUIDNameReply(new UUIDNameReplyEventArgs(names)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarAnimationHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + AvatarAnimationPacket data = (AvatarAnimationPacket)packet; + + List signaledAnimations = new List(data.AnimationList.Length); + + for (int i = 0; i < data.AnimationList.Length; i++) + { + Animation animation = new Animation(); + animation.AnimationID = data.AnimationList[i].AnimID; + animation.AnimationSequence = data.AnimationList[i].AnimSequenceID; + if (i < data.AnimationSourceList.Length) + { + animation.AnimationSourceObjectID = data.AnimationSourceList[i].ObjectID; + } + + signaledAnimations.Add(animation); + } + + Avatar avatar = e.Simulator.ObjectsAvatars.Find(avi => avi.ID == data.Sender.ID); + if (avatar != null) + { + avatar.Animations = signaledAnimations; + } + + OnAvatarAnimation(new AvatarAnimationEventArgs(data.Sender.ID, signaledAnimations)); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarAppearanceHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarAppearance != null || Client.Settings.AVATAR_TRACKING) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet; + + List visualParams = new List(); + foreach (AvatarAppearancePacket.VisualParamBlock block in appearance.VisualParam) + { + visualParams.Add(block.ParamValue); + } + + Primitive.TextureEntry textureEntry = new Primitive.TextureEntry(appearance.ObjectData.TextureEntry, 0, + appearance.ObjectData.TextureEntry.Length); + + Primitive.TextureEntryFace defaultTexture = textureEntry.DefaultTexture; + Primitive.TextureEntryFace[] faceTextures = textureEntry.FaceTextures; + + byte appearanceVersion = 0; + int COFVersion = 0; + AppearanceFlags appearanceFlags = 0; + + if (appearance.AppearanceData != null && appearance.AppearanceData.Length > 0) + { + appearanceVersion = appearance.AppearanceData[0].AppearanceVersion; + COFVersion = appearance.AppearanceData[0].CofVersion; + appearanceFlags = (AppearanceFlags)appearance.AppearanceData[0].Flags; + } + + Avatar av = simulator.ObjectsAvatars.Find((Avatar a) => { return a.ID == appearance.Sender.ID; }); + if (av != null) + { + av.Textures = textureEntry; + av.VisualParameters = visualParams.ToArray(); + av.AppearanceVersion = appearanceVersion; + av.COFVersion = COFVersion; + av.AppearanceFlags = appearanceFlags; + } + + OnAvatarAppearance(new AvatarAppearanceEventArgs(simulator, appearance.Sender.ID, appearance.Sender.IsTrial, + defaultTexture, faceTextures, visualParams, appearanceVersion, COFVersion, appearanceFlags)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarPropertiesHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarPropertiesReply != null) + { + Packet packet = e.Packet; + AvatarPropertiesReplyPacket reply = (AvatarPropertiesReplyPacket)packet; + Avatar.AvatarProperties properties = new Avatar.AvatarProperties(); + + properties.ProfileImage = reply.PropertiesData.ImageID; + properties.FirstLifeImage = reply.PropertiesData.FLImageID; + properties.Partner = reply.PropertiesData.PartnerID; + properties.AboutText = Utils.BytesToString(reply.PropertiesData.AboutText); + properties.FirstLifeText = Utils.BytesToString(reply.PropertiesData.FLAboutText); + properties.BornOn = Utils.BytesToString(reply.PropertiesData.BornOn); + //properties.CharterMember = Utils.BytesToString(reply.PropertiesData.CharterMember); + uint charter = Utils.BytesToUInt(reply.PropertiesData.CharterMember); + if (charter == 0) + { + properties.CharterMember = "Resident"; + } + else if (charter == 2) + { + properties.CharterMember = "Charter"; + } + else if (charter == 3) + { + properties.CharterMember = "Linden"; + } + else + { + properties.CharterMember = Utils.BytesToString(reply.PropertiesData.CharterMember); + } + properties.Flags = (ProfileFlags)reply.PropertiesData.Flags; + properties.ProfileURL = Utils.BytesToString(reply.PropertiesData.ProfileURL); + + OnAvatarPropertiesReply(new AvatarPropertiesReplyEventArgs(reply.AgentData.AvatarID, properties)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarInterestsHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarInterestsReply != null) + { + Packet packet = e.Packet; + + AvatarInterestsReplyPacket airp = (AvatarInterestsReplyPacket)packet; + Avatar.Interests interests = new Avatar.Interests(); + + interests.WantToMask = airp.PropertiesData.WantToMask; + interests.WantToText = Utils.BytesToString(airp.PropertiesData.WantToText); + interests.SkillsMask = airp.PropertiesData.SkillsMask; + interests.SkillsText = Utils.BytesToString(airp.PropertiesData.SkillsText); + interests.LanguagesText = Utils.BytesToString(airp.PropertiesData.LanguagesText); + + OnAvatarInterestsReply(new AvatarInterestsReplyEventArgs(airp.AgentData.AvatarID, interests)); + } + } + + /// + /// EQ Message fired when someone nearby changes their display name + /// + /// The message key + /// the IMessage object containing the deserialized data sent from the simulator + /// The which originated the packet + protected void DisplayNameUpdateMessageHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_DisplayNameUpdate != null) + { + DisplayNameUpdateMessage msg = (DisplayNameUpdateMessage)message; + OnDisplayNameUpdate(new DisplayNameUpdateEventArgs(msg.OldDisplayName, msg.DisplayName)); + } + } + + /// + /// Crossed region handler for message that comes across the EventQueue. Sent to an agent + /// when the agent crosses a sim border into a new region. + /// + /// The message key + /// the IMessage object containing the deserialized data sent from the simulator + /// The which originated the packet + protected void AvatarGroupsReplyMessageHandler(string capsKey, IMessage message, Simulator simulator) + { + AgentGroupDataUpdateMessage msg = (AgentGroupDataUpdateMessage)message; + List avatarGroups = new List(msg.GroupDataBlock.Length); + for (int i = 0; i < msg.GroupDataBlock.Length; i++) + { + AvatarGroup avatarGroup = new AvatarGroup(); + avatarGroup.AcceptNotices = msg.GroupDataBlock[i].AcceptNotices; + avatarGroup.GroupID = msg.GroupDataBlock[i].GroupID; + avatarGroup.GroupInsigniaID = msg.GroupDataBlock[i].GroupInsigniaID; + avatarGroup.GroupName = msg.GroupDataBlock[i].GroupName; + avatarGroup.GroupPowers = msg.GroupDataBlock[i].GroupPowers; + avatarGroup.ListInProfile = msg.NewGroupDataBlock[i].ListInProfile; + + avatarGroups.Add(avatarGroup); + } + + OnAvatarGroupsReply(new AvatarGroupsReplyEventArgs(msg.AgentID, avatarGroups)); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarGroupsReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarGroupsReply != null) + { + Packet packet = e.Packet; + AvatarGroupsReplyPacket groups = (AvatarGroupsReplyPacket)packet; + List avatarGroups = new List(groups.GroupData.Length); + + for (int i = 0; i < groups.GroupData.Length; i++) + { + AvatarGroup avatarGroup = new AvatarGroup(); + + avatarGroup.AcceptNotices = groups.GroupData[i].AcceptNotices; + avatarGroup.GroupID = groups.GroupData[i].GroupID; + avatarGroup.GroupInsigniaID = groups.GroupData[i].GroupInsigniaID; + avatarGroup.GroupName = Utils.BytesToString(groups.GroupData[i].GroupName); + avatarGroup.GroupPowers = (GroupPowers)groups.GroupData[i].GroupPowers; + avatarGroup.GroupTitle = Utils.BytesToString(groups.GroupData[i].GroupTitle); + avatarGroup.ListInProfile = groups.NewGroupData.ListInProfile; + + avatarGroups.Add(avatarGroup); + } + + OnAvatarGroupsReply(new AvatarGroupsReplyEventArgs(groups.AgentData.AvatarID, avatarGroups)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarPickerReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarPickerReply != null) + { + Packet packet = e.Packet; + AvatarPickerReplyPacket reply = (AvatarPickerReplyPacket)packet; + Dictionary avatars = new Dictionary(); + + foreach (AvatarPickerReplyPacket.DataBlock block in reply.Data) + { + avatars[block.AvatarID] = Utils.BytesToString(block.FirstName) + + " " + Utils.BytesToString(block.LastName); + } + OnAvatarPickerReply(new AvatarPickerReplyEventArgs(reply.AgentData.QueryID, avatars)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ViewerEffectHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + ViewerEffectPacket effect = (ViewerEffectPacket)packet; + + foreach (ViewerEffectPacket.EffectBlock block in effect.Effect) + { + EffectType type = (EffectType)block.Type; + + // Each ViewerEffect type uses it's own custom binary format for additional data. Fun eh? + switch (type) + { + case EffectType.Text: + Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.Icon: + Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.Connector: + Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.FlexibleObject: + Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.AnimalControls: + Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.AnimationObject: + Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.Cloth: + Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.Glow: + Logger.Log("Received a Glow ViewerEffect which is not implemented yet", + Helpers.LogLevel.Warning, Client); + break; + case EffectType.Beam: + case EffectType.Point: + case EffectType.Trail: + case EffectType.Sphere: + case EffectType.Spiral: + case EffectType.Edit: + if (m_ViewerEffect != null) + { + if (block.TypeData.Length == 56) + { + UUID sourceAvatar = new UUID(block.TypeData, 0); + UUID targetObject = new UUID(block.TypeData, 16); + Vector3d targetPos = new Vector3d(block.TypeData, 32); + OnViewerEffect(new ViewerEffectEventArgs(type, sourceAvatar, targetObject, targetPos, block.Duration, block.ID)); + } + else + { + Logger.Log("Received a " + type.ToString() + + " ViewerEffect with an incorrect TypeData size of " + + block.TypeData.Length + " bytes", Helpers.LogLevel.Warning, Client); + } + } + break; + case EffectType.LookAt: + if (m_ViewerEffectLookAt != null) + { + if (block.TypeData.Length == 57) + { + UUID sourceAvatar = new UUID(block.TypeData, 0); + UUID targetObject = new UUID(block.TypeData, 16); + Vector3d targetPos = new Vector3d(block.TypeData, 32); + LookAtType lookAt = (LookAtType)block.TypeData[56]; + + OnViewerEffectLookAt(new ViewerEffectLookAtEventArgs(sourceAvatar, targetObject, targetPos, lookAt, + block.Duration, block.ID)); + } + else + { + Logger.Log("Received a LookAt ViewerEffect with an incorrect TypeData size of " + + block.TypeData.Length + " bytes", Helpers.LogLevel.Warning, Client); + } + } + break; + case EffectType.PointAt: + if (m_ViewerEffectPointAt != null) + { + if (block.TypeData.Length == 57) + { + UUID sourceAvatar = new UUID(block.TypeData, 0); + UUID targetObject = new UUID(block.TypeData, 16); + Vector3d targetPos = new Vector3d(block.TypeData, 32); + PointAtType pointAt = (PointAtType)block.TypeData[56]; + + OnViewerEffectPointAt(new ViewerEffectPointAtEventArgs(e.Simulator, sourceAvatar, targetObject, targetPos, + pointAt, block.Duration, block.ID)); + } + else + { + Logger.Log("Received a PointAt ViewerEffect with an incorrect TypeData size of " + + block.TypeData.Length + " bytes", Helpers.LogLevel.Warning, Client); + } + } + break; + default: + Logger.Log("Received a ViewerEffect with an unknown type " + type, Helpers.LogLevel.Warning, Client); + break; + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarPicksReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarPicksReply == null) + { + return; + } + Packet packet = e.Packet; + + AvatarPicksReplyPacket p = (AvatarPicksReplyPacket)packet; + Dictionary picks = new Dictionary(); + + foreach (AvatarPicksReplyPacket.DataBlock b in p.Data) + { + picks.Add(b.PickID, Utils.BytesToString(b.PickName)); + } + + OnAvatarPicksReply(new AvatarPicksReplyEventArgs(p.AgentData.TargetID, picks)); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void PickInfoReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_PickInfoReply != null) + { + Packet packet = e.Packet; + PickInfoReplyPacket p = (PickInfoReplyPacket)packet; + ProfilePick ret = new ProfilePick(); + ret.CreatorID = p.Data.CreatorID; + ret.Desc = Utils.BytesToString(p.Data.Desc); + ret.Enabled = p.Data.Enabled; + ret.Name = Utils.BytesToString(p.Data.Name); + ret.OriginalName = Utils.BytesToString(p.Data.OriginalName); + ret.ParcelID = p.Data.ParcelID; + ret.PickID = p.Data.PickID; + ret.PosGlobal = p.Data.PosGlobal; + ret.SimName = Utils.BytesToString(p.Data.SimName); + ret.SnapshotID = p.Data.SnapshotID; + ret.SortOrder = p.Data.SortOrder; + ret.TopPick = p.Data.TopPick; + ret.User = Utils.BytesToString(p.Data.User); + + OnPickInfoReply(new PickInfoReplyEventArgs(ret.PickID, ret)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AvatarClassifiedReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarClassifiedReply != null) + { + Packet packet = e.Packet; + AvatarClassifiedReplyPacket p = (AvatarClassifiedReplyPacket)packet; + Dictionary classifieds = new Dictionary(); + + foreach (AvatarClassifiedReplyPacket.DataBlock b in p.Data) + { + classifieds.Add(b.ClassifiedID, Utils.BytesToString(b.Name)); + } + + OnAvatarClassifiedReply(new AvatarClassifiedReplyEventArgs(p.AgentData.TargetID, classifieds)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ClassifiedInfoReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarClassifiedReply != null) + { + Packet packet = e.Packet; + ClassifiedInfoReplyPacket p = (ClassifiedInfoReplyPacket)packet; + ClassifiedAd ret = new ClassifiedAd(); + ret.Desc = Utils.BytesToString(p.Data.Desc); + ret.Name = Utils.BytesToString(p.Data.Name); + ret.ParcelID = p.Data.ParcelID; + ret.ClassifiedID = p.Data.ClassifiedID; + ret.Position = p.Data.PosGlobal; + ret.SnapShotID = p.Data.SnapshotID; + ret.Price = p.Data.PriceForListing; + ret.ParentEstate = p.Data.ParentEstate; + ret.ClassifiedFlags = p.Data.ClassifiedFlags; + ret.Catagory = p.Data.Category; + + OnClassifiedInfoReply(new ClassifiedInfoReplyEventArgs(ret.ClassifiedID, ret)); + } + } + + #endregion Packet Handlers + } + + #region EventArgs + + /// Provides data for the event + /// The event occurs when the simulator sends + /// the animation playlist for an agent + /// + /// The following code example uses the and + /// properties to display the animation playlist of an avatar on the window. + /// + /// // subscribe to the event + /// Client.Avatars.AvatarAnimation += Avatars_AvatarAnimation; + /// + /// private void Avatars_AvatarAnimation(object sender, AvatarAnimationEventArgs e) + /// { + /// // create a dictionary of "known" animations from the Animations class using System.Reflection + /// Dictionary<UUID, string> systemAnimations = new Dictionary<UUID, string>(); + /// Type type = typeof(Animations); + /// System.Reflection.FieldInfo[] fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + /// foreach (System.Reflection.FieldInfo field in fields) + /// { + /// systemAnimations.Add((UUID)field.GetValue(type), field.Name); + /// } + /// + /// // find out which animations being played are known animations and which are assets + /// foreach (Animation animation in e.Animations) + /// { + /// if (systemAnimations.ContainsKey(animation.AnimationID)) + /// { + /// Console.WriteLine("{0} is playing {1} ({2}) sequence {3}", e.AvatarID, + /// systemAnimations[animation.AnimationID], animation.AnimationSequence); + /// } + /// else + /// { + /// Console.WriteLine("{0} is playing {1} (Asset) sequence {2}", e.AvatarID, + /// animation.AnimationID, animation.AnimationSequence); + /// } + /// } + /// } + /// + /// + public class AvatarAnimationEventArgs : EventArgs + { + private readonly UUID m_AvatarID; + private readonly List m_Animations; + + /// Get the ID of the agent + public UUID AvatarID { get { return m_AvatarID; } } + /// Get the list of animations to start + public List Animations { get { return m_Animations; } } + + /// + /// Construct a new instance of the AvatarAnimationEventArgs class + /// + /// The ID of the agent + /// The list of animations to start + public AvatarAnimationEventArgs(UUID avatarID, List anims) + { + this.m_AvatarID = avatarID; + this.m_Animations = anims; + } + } + + /// Provides data for the event + /// The event occurs when the simulator sends + /// the appearance data for an avatar + /// + /// The following code example uses the and + /// properties to display the selected shape of an avatar on the window. + /// + /// // subscribe to the event + /// Client.Avatars.AvatarAppearance += Avatars_AvatarAppearance; + /// + /// // handle the data when the event is raised + /// void Avatars_AvatarAppearance(object sender, AvatarAppearanceEventArgs e) + /// { + /// Console.WriteLine("The Agent {0} is using a {1} shape.", e.AvatarID, (e.VisualParams[31] > 0) : "male" ? "female") + /// } + /// + /// + public class AvatarAppearanceEventArgs : EventArgs + { + + private readonly Simulator m_Simulator; + private readonly UUID m_AvatarID; + private readonly bool m_IsTrial; + private readonly Primitive.TextureEntryFace m_DefaultTexture; + private readonly Primitive.TextureEntryFace[] m_FaceTextures; + private readonly List m_VisualParams; + private readonly byte m_AppearanceVersion; + private readonly int m_COFVersion; + private readonly AppearanceFlags m_AppearanceFlags; + + /// Get the Simulator this request is from of the agent + public Simulator Simulator { get { return m_Simulator; } } + /// Get the ID of the agent + public UUID AvatarID { get { return m_AvatarID; } } + /// true if the agent is a trial account + public bool IsTrial { get { return m_IsTrial; } } + /// Get the default agent texture + public Primitive.TextureEntryFace DefaultTexture { get { return m_DefaultTexture; } } + /// Get the agents appearance layer textures + public Primitive.TextureEntryFace[] FaceTextures { get { return m_FaceTextures; } } + /// Get the for the agent + public List VisualParams { get { return m_VisualParams; } } + /// Version of the appearance system used. + /// Value greater than 0 indicates that server side baking is used + public byte AppearanceVersion { get { return m_AppearanceVersion; } } + /// Version of the Current Outfit Folder the appearance is based on + public int COFVersion { get { return m_COFVersion; } } + /// Appearance flags, introduced with server side baking, currently unused + public AppearanceFlags AppearanceFlags { get { return m_AppearanceFlags; } } + + /// + /// Construct a new instance of the AvatarAppearanceEventArgs class + /// + /// The simulator request was from + /// The ID of the agent + /// true of the agent is a trial account + /// The default agent texture + /// The agents appearance layer textures + /// The for the agent + public AvatarAppearanceEventArgs(Simulator sim, UUID avatarID, bool isTrial, Primitive.TextureEntryFace defaultTexture, + Primitive.TextureEntryFace[] faceTextures, List visualParams, + byte appearanceVersion, int COFVersion, AppearanceFlags appearanceFlags) + { + this.m_Simulator = sim; + this.m_AvatarID = avatarID; + this.m_IsTrial = isTrial; + this.m_DefaultTexture = defaultTexture; + this.m_FaceTextures = faceTextures; + this.m_VisualParams = visualParams; + this.m_AppearanceVersion = appearanceVersion; + this.m_COFVersion = COFVersion; + this.m_AppearanceFlags = appearanceFlags; + } + } + + /// Represents the interests from the profile of an agent + public class AvatarInterestsReplyEventArgs : EventArgs + { + private readonly UUID m_AvatarID; + private readonly Avatar.Interests m_Interests; + + /// Get the ID of the agent + public UUID AvatarID { get { return m_AvatarID; } } + public Avatar.Interests Interests { get { return m_Interests; } } + + public AvatarInterestsReplyEventArgs(UUID avatarID, Avatar.Interests interests) + { + this.m_AvatarID = avatarID; + this.m_Interests = interests; + } + } + + /// The properties of an agent + public class AvatarPropertiesReplyEventArgs : EventArgs + { + private readonly UUID m_AvatarID; + private readonly Avatar.AvatarProperties m_Properties; + + /// Get the ID of the agent + public UUID AvatarID { get { return m_AvatarID; } } + public Avatar.AvatarProperties Properties { get { return m_Properties; } } + + public AvatarPropertiesReplyEventArgs(UUID avatarID, Avatar.AvatarProperties properties) + { + this.m_AvatarID = avatarID; + this.m_Properties = properties; + } + } + + + public class AvatarGroupsReplyEventArgs : EventArgs + { + private readonly UUID m_AvatarID; + private readonly List m_Groups; + + /// Get the ID of the agent + public UUID AvatarID { get { return m_AvatarID; } } + public List Groups { get { return m_Groups; } } + + public AvatarGroupsReplyEventArgs(UUID avatarID, List avatarGroups) + { + this.m_AvatarID = avatarID; + this.m_Groups = avatarGroups; + } + } + + public class AvatarPicksReplyEventArgs : EventArgs + { + private readonly UUID m_AvatarID; + private readonly Dictionary m_Picks; + + /// Get the ID of the agent + public UUID AvatarID { get { return m_AvatarID; } } + public Dictionary Picks { get { return m_Picks; } } + + public AvatarPicksReplyEventArgs(UUID avatarid, Dictionary picks) + { + this.m_AvatarID = avatarid; + this.m_Picks = picks; + } + } + + public class PickInfoReplyEventArgs : EventArgs + { + private readonly UUID m_PickID; + private readonly ProfilePick m_Pick; + + public UUID PickID { get { return m_PickID; } } + public ProfilePick Pick { get { return m_Pick; } } + + + public PickInfoReplyEventArgs(UUID pickid, ProfilePick pick) + { + this.m_PickID = pickid; + this.m_Pick = pick; + } + } + + public class AvatarClassifiedReplyEventArgs : EventArgs + { + private readonly UUID m_AvatarID; + private readonly Dictionary m_Classifieds; + + /// Get the ID of the avatar + public UUID AvatarID { get { return m_AvatarID; } } + public Dictionary Classifieds { get { return m_Classifieds; } } + + public AvatarClassifiedReplyEventArgs(UUID avatarid, Dictionary classifieds) + { + this.m_AvatarID = avatarid; + this.m_Classifieds = classifieds; + } + } + + public class ClassifiedInfoReplyEventArgs : EventArgs + { + private readonly UUID m_ClassifiedID; + private readonly ClassifiedAd m_Classified; + + public UUID ClassifiedID { get { return m_ClassifiedID; } } + public ClassifiedAd Classified { get { return m_Classified; } } + + + public ClassifiedInfoReplyEventArgs(UUID classifiedID, ClassifiedAd Classified) + { + this.m_ClassifiedID = classifiedID; + this.m_Classified = Classified; + } + } + + public class UUIDNameReplyEventArgs : EventArgs + { + private readonly Dictionary m_Names; + + public Dictionary Names { get { return m_Names; } } + + public UUIDNameReplyEventArgs(Dictionary names) + { + this.m_Names = names; + } + } + + public class AvatarPickerReplyEventArgs : EventArgs + { + private readonly UUID m_QueryID; + private readonly Dictionary m_Avatars; + + public UUID QueryID { get { return m_QueryID; } } + public Dictionary Avatars { get { return m_Avatars; } } + + public AvatarPickerReplyEventArgs(UUID queryID, Dictionary avatars) + { + this.m_QueryID = queryID; + this.m_Avatars = avatars; + } + } + + public class ViewerEffectEventArgs : EventArgs + { + private readonly EffectType m_Type; + private readonly UUID m_SourceID; + private readonly UUID m_TargetID; + private readonly Vector3d m_TargetPosition; + private readonly float m_Duration; + private readonly UUID m_EffectID; + + public EffectType Type { get { return m_Type; } } + public UUID SourceID { get { return m_SourceID; } } + public UUID TargetID { get { return m_TargetID; } } + public Vector3d TargetPosition { get { return m_TargetPosition; } } + public float Duration { get { return m_Duration; } } + public UUID EffectID { get { return m_EffectID; } } + + public ViewerEffectEventArgs(EffectType type, UUID sourceID, UUID targetID, Vector3d targetPos, float duration, UUID id) + { + this.m_Type = type; + this.m_SourceID = sourceID; + this.m_TargetID = targetID; + this.m_TargetPosition = targetPos; + this.m_Duration = duration; + this.m_EffectID = id; + } + } + + public class ViewerEffectPointAtEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly UUID m_SourceID; + private readonly UUID m_TargetID; + private readonly Vector3d m_TargetPosition; + private readonly PointAtType m_PointType; + private readonly float m_Duration; + private readonly UUID m_EffectID; + + public Simulator Simulator { get { return m_Simulator; } } + public UUID SourceID { get { return m_SourceID; } } + public UUID TargetID { get { return m_TargetID; } } + public Vector3d TargetPosition { get { return m_TargetPosition; } } + public PointAtType PointType { get { return m_PointType; } } + public float Duration { get { return m_Duration; } } + public UUID EffectID { get { return m_EffectID; } } + + public ViewerEffectPointAtEventArgs(Simulator simulator, UUID sourceID, UUID targetID, Vector3d targetPos, PointAtType pointType, float duration, UUID id) + { + this.m_Simulator = simulator; + this.m_SourceID = sourceID; + this.m_TargetID = targetID; + this.m_TargetPosition = targetPos; + this.m_PointType = pointType; + this.m_Duration = duration; + this.m_EffectID = id; + } + } + + public class ViewerEffectLookAtEventArgs : EventArgs + { + private readonly UUID m_SourceID; + private readonly UUID m_TargetID; + private readonly Vector3d m_TargetPosition; + private readonly LookAtType m_LookType; + private readonly float m_Duration; + private readonly UUID m_EffectID; + + + public UUID SourceID { get { return m_SourceID; } } + public UUID TargetID { get { return m_TargetID; } } + public Vector3d TargetPosition { get { return m_TargetPosition; } } + public LookAtType LookType { get { return m_LookType; } } + public float Duration { get { return m_Duration; } } + public UUID EffectID { get { return m_EffectID; } } + + public ViewerEffectLookAtEventArgs(UUID sourceID, UUID targetID, Vector3d targetPos, LookAtType lookType, float duration, UUID id) + { + this.m_SourceID = sourceID; + this.m_TargetID = targetID; + this.m_TargetPosition = targetPos; + this.m_LookType = lookType; + this.m_Duration = duration; + this.m_EffectID = id; + } + } + + /// + /// Event args class for display name notification messages + /// + public class DisplayNameUpdateEventArgs : EventArgs + { + private string oldDisplayName; + private AgentDisplayName displayName; + + public string OldDisplayName { get { return oldDisplayName; } } + public AgentDisplayName DisplayName { get { return displayName; } } + + public DisplayNameUpdateEventArgs(string oldDisplayName, AgentDisplayName displayName) + { + this.oldDisplayName = oldDisplayName; + this.displayName = displayName; + } + } + #endregion +} diff --git a/OpenMetaverse/BVHDecoder.cs b/OpenMetaverse/BVHDecoder.cs new file mode 100644 index 0000000..1c894bd --- /dev/null +++ b/OpenMetaverse/BVHDecoder.cs @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +using System; + +namespace OpenMetaverse +{ + /// + /// Reads in a byte array of an Animation Asset created by the SecondLife(tm) client. + /// + public class BinBVHAnimationReader + { + /// + /// Rotation Keyframe count (used internally) + /// + private int rotationkeys; + + /// + /// Position Keyframe count (used internally) + /// + private int positionkeys; + + public UInt16 unknown0; // Always 1 + public UInt16 unknown1; // Always 0 + + /// + /// Animation Priority + /// + public int Priority; + + /// + /// The animation length in seconds. + /// + public Single Length; + + /// + /// Expression set in the client. Null if [None] is selected + /// + public string ExpressionName; // "" (null) + + /// + /// The time in seconds to start the animation + /// + public Single InPoint; + + /// + /// The time in seconds to end the animation + /// + public Single OutPoint; + + /// + /// Loop the animation + /// + public bool Loop; + + /// + /// Meta data. Ease in Seconds. + /// + public Single EaseInTime; + + /// + /// Meta data. Ease out seconds. + /// + public Single EaseOutTime; + + /// + /// Meta Data for the Hand Pose + /// + public uint HandPose; + + /// + /// Number of joints defined in the animation + /// + public uint JointCount; + + + /// + /// Contains an array of joints + /// + public binBVHJoint[] joints; + + /// + /// Searialize an animation asset into it's joints/keyframes/meta data + /// + /// + public BinBVHAnimationReader(byte[] animationdata) + { + int i = 0; + if (!BitConverter.IsLittleEndian) + { + unknown0 = Utils.BytesToUInt16(EndianSwap(animationdata, i, 2)); i += 2; // Always 1 + unknown1 = Utils.BytesToUInt16(EndianSwap(animationdata, i, 2)); i += 2; // Always 0 + Priority = Utils.BytesToInt(EndianSwap(animationdata, i, 4)); i += 4; + Length = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4; + } + else + { + unknown0 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 1 + unknown1 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 0 + Priority = Utils.BytesToInt(animationdata, i); i += 4; + Length = Utils.BytesToFloat(animationdata, i); i += 4; + } + ExpressionName = ReadBytesUntilNull(animationdata, ref i); + if (!BitConverter.IsLittleEndian) + { + InPoint = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4; + OutPoint = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4; + Loop = (Utils.BytesToInt(EndianSwap(animationdata, i, 4)) != 0); i += 4; + EaseInTime = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4; + EaseOutTime = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4; + HandPose = Utils.BytesToUInt(EndianSwap(animationdata, i, 4)); i += 4; // Handpose? + + JointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count + } + else + { + InPoint = Utils.BytesToFloat(animationdata, i); i += 4; + OutPoint = Utils.BytesToFloat(animationdata, i); i += 4; + Loop = (Utils.BytesToInt(animationdata, i) != 0); i += 4; + EaseInTime = Utils.BytesToFloat(animationdata, i); i += 4; + EaseOutTime = Utils.BytesToFloat(animationdata, i); i += 4; + HandPose = Utils.BytesToUInt(animationdata, i); i += 4; // Handpose? + + JointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count + } + joints = new binBVHJoint[JointCount]; + + // deserialize the number of joints in the animation. + // Joints are variable length blocks of binary data consisting of joint data and keyframes + for (int iter = 0; iter < JointCount; iter++) + { + binBVHJoint joint = readJoint(animationdata, ref i); + joints[iter] = joint; + } + } + + private byte[] EndianSwap(byte[] arr, int offset, int len) + { + byte[] bendian = new byte[offset + len]; + Buffer.BlockCopy(arr, offset, bendian, 0, len); + Array.Reverse(bendian); + return bendian; + } + /// + /// Variable length strings seem to be null terminated in the animation asset.. but.. + /// use with caution, home grown. + /// advances the index. + /// + /// The animation asset byte array + /// The offset to start reading + /// a string + public string ReadBytesUntilNull(byte[] data, ref int i) + { + char nterm = '\0'; // Null terminator + int endpos = i; + int startpos = i; + + // Find the null character + for (int j = i; j < data.Length; j++) + { + char spot = Convert.ToChar(data[j]); + if (spot == nterm) + { + endpos = j; + break; + } + } + + // if we got to the end, then it's a zero length string + if (i == endpos) + { + // advance the 1 null character + i++; + return string.Empty; + } + else + { + // We found the end of the string + // append the bytes from the beginning of the string to the end of the string + // advance i + byte[] interm = new byte[endpos - i]; + for (; i < endpos; i++) + { + interm[i - startpos] = data[i]; + } + i++; // advance past the null character + + return Utils.BytesToString(interm); + } + } + + /// + /// Read in a Joint from an animation asset byte array + /// Variable length Joint fields, yay! + /// Advances the index + /// + /// animation asset byte array + /// Byte Offset of the start of the joint + /// The Joint data serialized into the binBVHJoint structure + public binBVHJoint readJoint(byte[] data, ref int i) + { + + binBVHJointKey[] positions; + binBVHJointKey[] rotations; + + binBVHJoint pJoint = new binBVHJoint(); + + /* + 109 + 84 + 111 + 114 + 114 + 111 + 0 <--- Null terminator + */ + + pJoint.Name = ReadBytesUntilNull(data, ref i); // Joint name + + /* + 2 <- Priority Revisited + 0 + 0 + 0 + */ + + /* + 5 <-- 5 keyframes + 0 + 0 + 0 + ... 5 Keyframe data blocks + */ + + /* + 2 <-- 2 keyframes + 0 + 0 + 0 + .. 2 Keyframe data blocks + */ + if (!BitConverter.IsLittleEndian) + { + pJoint.Priority = Utils.BytesToInt(EndianSwap(data, i, 4)); i += 4; // Joint Priority override? + rotationkeys = Utils.BytesToInt(EndianSwap(data, i, 4)); i += 4; // How many rotation keyframes + } + else + { + pJoint.Priority = Utils.BytesToInt(data, i); i += 4; // Joint Priority override? + rotationkeys = Utils.BytesToInt(data, i); i += 4; // How many rotation keyframes + } + + // Sanity check how many rotation keys there are + if (rotationkeys < 0 || rotationkeys > 10000) + { + rotationkeys = 0; + } + + rotations = readKeys(data, ref i, rotationkeys, -1.0f, 1.0f); + + if (!BitConverter.IsLittleEndian) + { + positionkeys = Utils.BytesToInt(EndianSwap(data, i, 4)); i += 4; // How many position keyframes + } + else + { + positionkeys = Utils.BytesToInt(data, i); i += 4; // How many position keyframes + } + + // Sanity check how many positions keys there are + if (positionkeys < 0 || positionkeys > 10000) + { + positionkeys = 0; + } + + // Read in position keyframes + positions = readKeys(data, ref i, positionkeys, -0.5f, 1.5f); + + pJoint.rotationkeys = rotations; + pJoint.positionkeys = positions; + + return pJoint; + } + + /// + /// Read Keyframes of a certain type + /// advance i + /// + /// Animation Byte array + /// Offset in the Byte Array. Will be advanced + /// Number of Keyframes + /// Scaling Min to pass to the Uint16ToFloat method + /// Scaling Max to pass to the Uint16ToFloat method + /// + public binBVHJointKey[] readKeys(byte[] data, ref int i, int keycount, float min, float max) + { + float x; + float y; + float z; + + /* + 17 255 <-- Time Code + 17 255 <-- Time Code + 255 255 <-- X + 127 127 <-- X + 255 255 <-- Y + 127 127 <-- Y + 213 213 <-- Z + 142 142 <---Z + + */ + + binBVHJointKey[] m_keys = new binBVHJointKey[keycount]; + for (int j = 0; j < keycount; j++) + { + binBVHJointKey pJKey = new binBVHJointKey(); + if (!BitConverter.IsLittleEndian) + { + pJKey.time = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, InPoint, OutPoint); i += 2; + x = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, min, max); i += 2; + y = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, min, max); i += 2; + z = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, min, max); i += 2; + } + else + { + pJKey.time = Utils.UInt16ToFloat(data, i, InPoint, OutPoint); i += 2; + x = Utils.UInt16ToFloat(data, i, min, max); i += 2; + y = Utils.UInt16ToFloat(data, i, min, max); i += 2; + z = Utils.UInt16ToFloat(data, i, min, max); i += 2; + } + pJKey.key_element = new Vector3(x, y, z); + m_keys[j] = pJKey; + } + return m_keys; + } + + public bool Equals(BinBVHAnimationReader other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Loop.Equals(Loop) && other.OutPoint == OutPoint && other.InPoint == InPoint && other.Length == Length && other.HandPose == HandPose && other.JointCount == JointCount && Equals(other.joints, joints) && other.EaseInTime == EaseInTime && other.EaseOutTime == EaseOutTime && other.Priority == Priority && other.unknown1 == unknown1 && other.unknown0 == unknown0 && other.positionkeys == positionkeys && other.rotationkeys == rotationkeys; + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// true if the specified is equal to the current ; otherwise, false. + /// + /// The to compare with the current . + /// The parameter is null. + /// 2 + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(BinBVHAnimationReader)) return false; + return Equals((BinBVHAnimationReader)obj); + } + + /// + /// Serves as a hash function for a particular type. + /// + /// + /// A hash code for the current . + /// + /// 2 + public override int GetHashCode() + { + unchecked + { + int result = Loop.GetHashCode(); + result = (result * 397) ^ OutPoint.GetHashCode(); + result = (result * 397) ^ InPoint.GetHashCode(); + result = (result * 397) ^ Length.GetHashCode(); + result = (result * 397) ^ HandPose.GetHashCode(); + result = (result * 397) ^ JointCount.GetHashCode(); + result = (result * 397) ^ (joints != null ? joints.GetHashCode() : 0); + result = (result * 397) ^ EaseInTime.GetHashCode(); + result = (result * 397) ^ EaseOutTime.GetHashCode(); + result = (result * 397) ^ Priority; + result = (result * 397) ^ unknown1.GetHashCode(); + result = (result * 397) ^ unknown0.GetHashCode(); + result = (result * 397) ^ positionkeys; + result = (result * 397) ^ rotationkeys; + return result; + } + } + + public static bool Equals(binBVHJoint[] arr1, binBVHJoint[] arr2) + { + if (arr1.Length == arr2.Length) + { + for (int i = 0; i < arr1.Length; i++) + if (!arr1[i].Equals(arr2[i])) + return false; + /* not same*/ + return true; + } + return false; + } + + } + + + /// + /// A Joint and it's associated meta data and keyframes + /// + public struct binBVHJoint + { + public static bool Equals(binBVHJointKey[] arr1, binBVHJointKey[] arr2) + { + if (arr1.Length == arr2.Length) + { + for (int i = 0; i < arr1.Length; i++) + if (!Equals(arr1[i], arr2[i])) + return false; + /* not same*/ + return true; + } + return false; + } + public static bool Equals(binBVHJointKey arr1, binBVHJointKey arr2) + { + return (arr1.time == arr2.time && arr1.key_element == arr2.key_element); + } + + public bool Equals(binBVHJoint other) + { + return other.Priority == Priority && Equals(other.rotationkeys, rotationkeys) && Equals(other.Name, Name) && Equals(other.positionkeys, positionkeys); + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// + /// true if and this instance are the same type and represent the same value; otherwise, false. + /// + /// Another object to compare to. + /// 2 + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (obj.GetType() != typeof(binBVHJoint)) return false; + return Equals((binBVHJoint)obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// + /// A 32-bit signed integer that is the hash code for this instance. + /// + /// 2 + public override int GetHashCode() + { + unchecked + { + int result = Priority; + result = (result * 397) ^ (rotationkeys != null ? rotationkeys.GetHashCode() : 0); + result = (result * 397) ^ (Name != null ? Name.GetHashCode() : 0); + result = (result * 397) ^ (positionkeys != null ? positionkeys.GetHashCode() : 0); + return result; + } + } + + public static bool operator ==(binBVHJoint left, binBVHJoint right) + { + return left.Equals(right); + } + + public static bool operator !=(binBVHJoint left, binBVHJoint right) + { + return !left.Equals(right); + } + + /// + /// Name of the Joint. Matches the avatar_skeleton.xml in client distros + /// + public string Name; + + /// + /// Joint Animation Override? Was the same as the Priority in testing.. + /// + public int Priority; + + /// + /// Array of Rotation Keyframes in order from earliest to latest + /// + public binBVHJointKey[] rotationkeys; + + /// + /// Array of Position Keyframes in order from earliest to latest + /// This seems to only be for the Pelvis? + /// + public binBVHJointKey[] positionkeys; + + /// + /// Custom application data that can be attached to a joint + /// + public object Tag; + } + + /// + /// A Joint Keyframe. This is either a position or a rotation. + /// + public struct binBVHJointKey + { + // Time in seconds for this keyframe. + public float time; + + /// + /// Either a Vector3 position or a Vector3 Euler rotation + /// + public Vector3 key_element; + } + + /// + /// Poses set in the animation metadata for the hands. + /// + public enum HandPose : uint + { + Spread = 0, + Relaxed = 1, + Point_Both = 2, + Fist = 3, + Relaxed_Left = 4, + Point_Left = 5, + Fist_Left = 6, + Relaxed_Right = 7, + Point_Right = 8, + Fist_Right = 9, + Salute_Right = 10, + Typing = 11, + Peace_Right = 12 + } +} diff --git a/OpenMetaverse/BitPack.cs b/OpenMetaverse/BitPack.cs new file mode 100644 index 0000000..582bc99 --- /dev/null +++ b/OpenMetaverse/BitPack.cs @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + /// + /// Wrapper around a byte array that allows bit to be packed and unpacked + /// one at a time or by a variable amount. Useful for very tightly packed + /// data like LayerData packets + /// + public class BitPack + { + /// + public byte[] Data; + + /// + public int BytePos + { + get + { + if (bytePos != 0 && bitPos == 0) + return bytePos - 1; + else + return bytePos; + } + } + + /// + public int BitPos { get { return bitPos; } } + + + private const int MAX_BITS = 8; + private static readonly byte[] ON = new byte[] { 1 }; + private static readonly byte[] OFF = new byte[] { 0 }; + + private int bytePos; + private int bitPos; + private bool weAreBigEndian = !BitConverter.IsLittleEndian; + + + /// + /// Default constructor, initialize the bit packer / bit unpacker + /// with a byte array and starting position + /// + /// Byte array to pack bits in to or unpack from + /// Starting position in the byte array + public BitPack(byte[] data, int pos) + { + Data = data; + bytePos = pos; + } + + /// + /// Pack a floating point value in to the data + /// + /// Floating point value to pack + public void PackFloat(float data) + { + byte[] input = BitConverter.GetBytes(data); + if (weAreBigEndian) Array.Reverse(input); + PackBitArray(input, 32); + } + + /// + /// Pack part or all of an integer in to the data + /// + /// Integer containing the data to pack + /// Number of bits of the integer to pack + public void PackBits(int data, int totalCount) + { + byte[] input = BitConverter.GetBytes(data); + if (weAreBigEndian) Array.Reverse(input); + PackBitArray(input, totalCount); + } + + /// + /// Pack part or all of an unsigned integer in to the data + /// + /// Unsigned integer containing the data to pack + /// Number of bits of the integer to pack + public void PackBits(uint data, int totalCount) + { + byte[] input = BitConverter.GetBytes(data); + if (weAreBigEndian) Array.Reverse(input); + PackBitArray(input, totalCount); + } + + /// + /// Pack a single bit in to the data + /// + /// Bit to pack + public void PackBit(bool bit) + { + if (bit) + PackBitArray(ON, 1); + else + PackBitArray(OFF, 1); + } + + /// + /// + /// + /// + /// + /// + /// + public void PackFixed(float data, bool isSigned, int intBits, int fracBits) + { + int unsignedBits = intBits + fracBits; + int totalBits = unsignedBits; + int min, max; + + if (isSigned) + { + totalBits++; + min = 1 << intBits; + min *= -1; + } + else + { + min = 0; + } + + max = 1 << intBits; + + float fixedVal = Utils.Clamp(data, (float)min, (float)max); + if (isSigned) fixedVal += max; + fixedVal *= 1 << fracBits; + + if (totalBits <= 8) + PackBits((uint)fixedVal, 8); + else if (totalBits <= 16) + PackBits((uint)fixedVal, 16); + else if (totalBits <= 31) + PackBits((uint)fixedVal, 32); + else + throw new Exception("Can't use fixed point packing for " + totalBits); + } + + /// + /// + /// + /// + public void PackUUID(UUID data) + { + byte[] bytes = data.GetBytes(); + + // Not sure if our PackBitArray function can handle 128-bit byte + //arrays, so using this for now + for (int i = 0; i < 16; i++) + PackBits(bytes[i], 8); + } + + /// + /// + /// + /// + public void PackColor(Color4 data) + { + byte[] bytes = data.GetBytes(); + PackBitArray(bytes, 32); + } + + /// + /// Unpacking a floating point value from the data + /// + /// Unpacked floating point value + public float UnpackFloat() + { + byte[] output = UnpackBitsArray(32); + + if (weAreBigEndian) Array.Reverse(output); + return BitConverter.ToSingle(output, 0); + } + + /// + /// Unpack a variable number of bits from the data in to integer format + /// + /// Number of bits to unpack + /// An integer containing the unpacked bits + /// This function is only useful up to 32 bits + public int UnpackBits(int totalCount) + { + byte[] output = UnpackBitsArray(totalCount); + + if (weAreBigEndian) Array.Reverse(output); + return BitConverter.ToInt32(output, 0); + } + + /// + /// Unpack a variable number of bits from the data in to unsigned + /// integer format + /// + /// Number of bits to unpack + /// An unsigned integer containing the unpacked bits + /// This function is only useful up to 32 bits + public uint UnpackUBits(int totalCount) + { + byte[] output = UnpackBitsArray(totalCount); + + if (weAreBigEndian) Array.Reverse(output); + return BitConverter.ToUInt32(output, 0); + } + + /// + /// Unpack a 16-bit signed integer + /// + /// 16-bit signed integer + public short UnpackShort() + { + return (short)UnpackBits(16); + } + + /// + /// Unpack a 16-bit unsigned integer + /// + /// 16-bit unsigned integer + public ushort UnpackUShort() + { + return (ushort)UnpackUBits(16); + } + + /// + /// Unpack a 32-bit signed integer + /// + /// 32-bit signed integer + public int UnpackInt() + { + return UnpackBits(32); + } + + /// + /// Unpack a 32-bit unsigned integer + /// + /// 32-bit unsigned integer + public uint UnpackUInt() + { + return UnpackUBits(32); + } + + public byte UnpackByte() + { + byte[] output = UnpackBitsArray(8); + return output[0]; + } + + public float UnpackFixed(bool signed, int intBits, int fracBits) + { + int minVal; + int maxVal; + int unsignedBits = intBits + fracBits; + int totalBits = unsignedBits; + float fixedVal; + + if (signed) + { + totalBits++; + + minVal = 1 << intBits; + minVal *= -1; + } + maxVal = 1 << intBits; + + if (totalBits <= 8) + fixedVal = (float)UnpackByte(); + else if (totalBits <= 16) + fixedVal = (float)UnpackUBits(16); + else if (totalBits <= 31) + fixedVal = (float)UnpackUBits(32); + else + return 0.0f; + + fixedVal /= (float)(1 << fracBits); + + if (signed) fixedVal -= (float)maxVal; + + return fixedVal; + } + + public string UnpackString(int size) + { + if (bitPos != 0 || bytePos + size > Data.Length) throw new IndexOutOfRangeException(); + + string str = System.Text.UTF8Encoding.UTF8.GetString(Data, bytePos, size); + bytePos += size; + return str; + } + + public UUID UnpackUUID() + { + if (bitPos != 0) throw new IndexOutOfRangeException(); + + UUID val = new UUID(Data, bytePos); + bytePos += 16; + return val; + } + + private void PackBitArray(byte[] data, int totalCount) + { + int count = 0; + int curBytePos = 0; + int curBitPos = 0; + + while (totalCount > 0) + { + if (totalCount > MAX_BITS) + { + count = MAX_BITS; + totalCount -= MAX_BITS; + } + else + { + count = totalCount; + totalCount = 0; + } + + while (count > 0) + { + byte curBit = (byte)(0x80 >> bitPos); + + if ((data[curBytePos] & (0x01 << (count - 1))) != 0) + Data[bytePos] |= curBit; + else + Data[bytePos] &= (byte)~curBit; + + --count; + ++bitPos; + ++curBitPos; + + if (bitPos >= MAX_BITS) + { + bitPos = 0; + ++bytePos; + } + if (curBitPos >= MAX_BITS) + { + curBitPos = 0; + ++curBytePos; + } + } + } + } + + private byte[] UnpackBitsArray(int totalCount) + { + int count = 0; + byte[] output = new byte[4]; + int curBytePos = 0; + int curBitPos = 0; + + while (totalCount > 0) + { + if (totalCount > MAX_BITS) + { + count = MAX_BITS; + totalCount -= MAX_BITS; + } + else + { + count = totalCount; + totalCount = 0; + } + + while (count > 0) + { + // Shift the previous bits + output[curBytePos] <<= 1; + + // Grab one bit + if ((Data[bytePos] & (0x80 >> bitPos++)) != 0) + ++output[curBytePos]; + + --count; + ++curBitPos; + + if (bitPos >= MAX_BITS) + { + bitPos = 0; + ++bytePos; + } + if (curBitPos >= MAX_BITS) + { + curBitPos = 0; + ++curBytePos; + } + } + } + + return output; + } + } +} diff --git a/OpenMetaverse/Capabilities/CapsBase.cs b/OpenMetaverse/Capabilities/CapsBase.cs new file mode 100644 index 0000000..f5d5e01 --- /dev/null +++ b/OpenMetaverse/Capabilities/CapsBase.cs @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Net.Security; +using System.IO; +using System.Text; +using System.Threading; +using System.Security.Cryptography.X509Certificates; + +namespace OpenMetaverse.Http +{ + public class TrustAllCertificatePolicy : ICertificatePolicy + { + public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest req, int problem) + { + return true; + } + + public static bool TrustAllCertificateHandler(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; + } + } + + public static class CapsBase + { + public delegate void OpenWriteEventHandler(HttpWebRequest request); + public delegate void DownloadProgressEventHandler(HttpWebRequest request, HttpWebResponse response, int bytesReceived, int totalBytesToReceive); + public delegate void RequestCompletedEventHandler(HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error); + + static CapsBase() + { + ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy(); + // Even though this will compile on Mono 2.4, it throws a runtime exception + //ServicePointManager.ServerCertificateValidationCallback = TrustAllCertificatePolicy.TrustAllCertificateHandler; + } + + private class RequestState + { + public HttpWebRequest Request; + public byte[] UploadData; + public int MillisecondsTimeout; + public OpenWriteEventHandler OpenWriteCallback; + public DownloadProgressEventHandler DownloadProgressCallback; + public RequestCompletedEventHandler CompletedCallback; + + public RequestState(HttpWebRequest request, byte[] uploadData, int millisecondsTimeout, OpenWriteEventHandler openWriteCallback, + DownloadProgressEventHandler downloadProgressCallback, RequestCompletedEventHandler completedCallback) + { + Request = request; + UploadData = uploadData; + MillisecondsTimeout = millisecondsTimeout; + OpenWriteCallback = openWriteCallback; + DownloadProgressCallback = downloadProgressCallback; + CompletedCallback = completedCallback; + } + } + + public static HttpWebRequest UploadDataAsync(Uri address, X509Certificate2 clientCert, string contentType, byte[] data, + int millisecondsTimeout, OpenWriteEventHandler openWriteCallback, DownloadProgressEventHandler downloadProgressCallback, + RequestCompletedEventHandler completedCallback) + { + // Create the request + HttpWebRequest request = SetupRequest(address, clientCert); + request.ContentLength = data.Length; + if (!String.IsNullOrEmpty(contentType)) + request.ContentType = contentType; + request.Method = "POST"; + + // Create an object to hold all of the state for this request + RequestState state = new RequestState(request, data, millisecondsTimeout, openWriteCallback, + downloadProgressCallback, completedCallback); + + // Start the request for a stream to upload to + IAsyncResult result = request.BeginGetRequestStream(OpenWrite, state); + // Register a timeout for the request + ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, TimeoutCallback, state, millisecondsTimeout, true); + + return request; + } + + public static HttpWebRequest DownloadStringAsync(Uri address, X509Certificate2 clientCert, int millisecondsTimeout, + DownloadProgressEventHandler downloadProgressCallback, RequestCompletedEventHandler completedCallback) + { + // Create the request + HttpWebRequest request = SetupRequest(address, clientCert); + request.Method = "GET"; + DownloadDataAsync(request, millisecondsTimeout, downloadProgressCallback, completedCallback); + return request; + } + + public static void DownloadDataAsync(HttpWebRequest request, int millisecondsTimeout, + DownloadProgressEventHandler downloadProgressCallback, RequestCompletedEventHandler completedCallback) + { + // Create an object to hold all of the state for this request + RequestState state = new RequestState(request, null, millisecondsTimeout, null, downloadProgressCallback, + completedCallback); + + // Start the request for the remote server response + IAsyncResult result = request.BeginGetResponse(GetResponse, state); + // Register a timeout for the request + ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, TimeoutCallback, state, millisecondsTimeout, true); + } + + static HttpWebRequest SetupRequest(Uri address, X509Certificate2 clientCert) + { + if (address == null) + throw new ArgumentNullException("address"); + + // Create the request + HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(address); + + // Add the client certificate to the request if one was given + if (clientCert != null) + request.ClientCertificates.Add(clientCert); + + // Leave idle connections to this endpoint open for up to 60 seconds + request.ServicePoint.MaxIdleTime = 1000 * 60; + // Disable stupid Expect-100: Continue header + request.ServicePoint.Expect100Continue = false; + // Crank up the max number of connections per endpoint + // We set this manually here instead of in ServicePointManager to avoid intereference with callers. + if (request.ServicePoint.ConnectionLimit < Settings.MAX_HTTP_CONNECTIONS) + { + Logger.Log( + string.Format( + "In CapsBase.SetupRequest() setting conn limit for {0}:{1} to {2}", + address.Host, address.Port, Settings.MAX_HTTP_CONNECTIONS), Helpers.LogLevel.Debug); + request.ServicePoint.ConnectionLimit = Settings.MAX_HTTP_CONNECTIONS; + } + // Caps requests are never sent as trickles of data, so Nagle's + // coalescing algorithm won't help us + request.ServicePoint.UseNagleAlgorithm = false; + // If not on mono, set accept-encoding header that allows response compression + request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + return request; + } + + static void OpenWrite(IAsyncResult ar) + { + RequestState state = (RequestState)ar.AsyncState; + + try + { + // Get the stream to write our upload to + using (Stream uploadStream = state.Request.EndGetRequestStream(ar)) + { + // Fire the callback for successfully opening the stream + if (state.OpenWriteCallback != null) + state.OpenWriteCallback(state.Request); + + // Write our data to the upload stream + uploadStream.Write(state.UploadData, 0, state.UploadData.Length); + } + + // Start the request for the remote server response + IAsyncResult result = state.Request.BeginGetResponse(GetResponse, state); + // Register a timeout for the request + ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, TimeoutCallback, state, + state.MillisecondsTimeout, true); + } + catch (Exception ex) + { + //Logger.Log.Debug("CapsBase.OpenWrite(): " + ex.Message); + if (state.CompletedCallback != null) + state.CompletedCallback(state.Request, null, null, ex); + } + } + + static void GetResponse(IAsyncResult ar) + { + RequestState state = (RequestState)ar.AsyncState; + HttpWebResponse response = null; + byte[] responseData = null; + Exception error = null; + + try + { + using (response = (HttpWebResponse)state.Request.EndGetResponse(ar)) + { + // Get the stream for downloading the response + using (Stream responseStream = response.GetResponseStream()) + { + #region Read the response + + // If Content-Length is set we create a buffer of the exact size, otherwise + // a MemoryStream is used to receive the response + bool nolength = (response.ContentLength <= 0) || (Type.GetType("Mono.Runtime") != null); + int size = (nolength) ? 8192 : (int)response.ContentLength; + MemoryStream ms = (nolength) ? new MemoryStream() : null; + byte[] buffer = new byte[size]; + + int bytesRead = 0; + int offset = 0; + int totalBytesRead = 0; + int totalSize = nolength ? 0 : size; + + while ((bytesRead = responseStream.Read(buffer, offset, size)) != 0) + { + totalBytesRead += bytesRead; + + if (nolength) + { + totalSize += (size - bytesRead); + ms.Write(buffer, 0, bytesRead); + } + else + { + offset += bytesRead; + size -= bytesRead; + } + + // Fire the download progress callback for each chunk of received data + if (state.DownloadProgressCallback != null) + state.DownloadProgressCallback(state.Request, response, totalBytesRead, totalSize); + } + + if (nolength) + { + responseData = ms.ToArray(); + ms.Close(); + ms.Dispose(); + } + else + { + responseData = buffer; + } + + #endregion Read the response + } + } + } + catch (Exception ex) + { + // Logger.DebugLog("CapsBase.GetResponse(): " + ex.Message); + error = ex; + } + + if (state.CompletedCallback != null) + state.CompletedCallback(state.Request, response, responseData, error); + } + + static void TimeoutCallback(object state, bool timedOut) + { + if (timedOut) + { + RequestState requestState = state as RequestState; + //Logger.Log.Debug("CapsBase.TimeoutCallback(): Request to " + requestState.Request.RequestUri + + // " timed out after " + requestState.MillisecondsTimeout + " milliseconds"); + if (requestState != null && requestState.Request != null) + requestState.Request.Abort(); + } + } + } +} diff --git a/OpenMetaverse/Capabilities/CapsClient.cs b/OpenMetaverse/Capabilities/CapsClient.cs new file mode 100644 index 0000000..5a80a7c --- /dev/null +++ b/OpenMetaverse/Capabilities/CapsClient.cs @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Http +{ + public class CapsClient + { + public delegate void DownloadProgressCallback(CapsClient client, int bytesReceived, int totalBytesToReceive); + public delegate void CompleteCallback(CapsClient client, OSD result, Exception error); + + public event DownloadProgressCallback OnDownloadProgress; + public event CompleteCallback OnComplete; + + public object UserData; + + protected Uri _Address; + protected byte[] _PostData; + protected X509Certificate2 _ClientCert; + protected string _ContentType; + protected HttpWebRequest _Request; + protected OSD _Response; + protected AutoResetEvent _ResponseEvent = new AutoResetEvent(false); + + public CapsClient(Uri capability) + : this(capability, null) + { + } + + public CapsClient(Uri capability, X509Certificate2 clientCert) + { + _Address = capability; + _ClientCert = clientCert; + } + + public void BeginGetResponse(int millisecondsTimeout) + { + BeginGetResponse(null, null, millisecondsTimeout); + } + + public void BeginGetResponse(OSD data, OSDFormat format, int millisecondsTimeout) + { + byte[] postData; + string contentType; + + switch (format) + { + case OSDFormat.Xml: + postData = OSDParser.SerializeLLSDXmlBytes(data); + contentType = "application/llsd+xml"; + break; + case OSDFormat.Binary: + postData = OSDParser.SerializeLLSDBinary(data); + contentType = "application/llsd+binary"; + break; + case OSDFormat.Json: + default: + postData = System.Text.Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(data)); + contentType = "application/llsd+json"; + break; + } + + BeginGetResponse(postData, contentType, millisecondsTimeout); + } + + public void BeginGetResponse(byte[] postData, string contentType, int millisecondsTimeout) + { + _PostData = postData; + _ContentType = contentType; + + if (_Request != null) + { + _Request.Abort(); + _Request = null; + } + + if (postData == null) + { + // GET + //Logger.Log.Debug("[CapsClient] GET " + _Address); + _Request = CapsBase.DownloadStringAsync(_Address, _ClientCert, millisecondsTimeout, DownloadProgressHandler, + RequestCompletedHandler); + } + else + { + // POST + //Logger.Log.Debug("[CapsClient] POST (" + postData.Length + " bytes) " + _Address); + _Request = CapsBase.UploadDataAsync(_Address, _ClientCert, contentType, postData, millisecondsTimeout, null, + DownloadProgressHandler, RequestCompletedHandler); + } + } + + public OSD GetResponse(int millisecondsTimeout) + { + BeginGetResponse(millisecondsTimeout); + _ResponseEvent.WaitOne(millisecondsTimeout, false); + return _Response; + } + + public OSD GetResponse(OSD data, OSDFormat format, int millisecondsTimeout) + { + BeginGetResponse(data, format, millisecondsTimeout); + _ResponseEvent.WaitOne(millisecondsTimeout, false); + return _Response; + } + + public OSD GetResponse(byte[] postData, string contentType, int millisecondsTimeout) + { + BeginGetResponse(postData, contentType, millisecondsTimeout); + _ResponseEvent.WaitOne(millisecondsTimeout, false); + return _Response; + } + + public void Cancel() + { + if (_Request != null) + _Request.Abort(); + } + + void DownloadProgressHandler(HttpWebRequest request, HttpWebResponse response, int bytesReceived, int totalBytesToReceive) + { + _Request = request; + + if (OnDownloadProgress != null) + { + try { OnDownloadProgress(this, bytesReceived, totalBytesToReceive); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, ex); } + } + } + + void RequestCompletedHandler(HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) + { + _Request = request; + + OSD result = null; + + if (responseData != null) + { + try { result = OSDParser.Deserialize(responseData); } + catch (Exception ex) { error = ex; } + } + + FireCompleteCallback(result, error); + } + + private void FireCompleteCallback(OSD result, Exception error) + { + CompleteCallback callback = OnComplete; + if (callback != null) + { + try { callback(this, result, error); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, ex); } + } + + _Response = result; + _ResponseEvent.Set(); + } + } +} diff --git a/OpenMetaverse/Capabilities/EventQueueClient.cs b/OpenMetaverse/Capabilities/EventQueueClient.cs new file mode 100644 index 0000000..cb1ffc9 --- /dev/null +++ b/OpenMetaverse/Capabilities/EventQueueClient.cs @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Threading; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Http +{ + public class EventQueueClient + { + /// = + public const int REQUEST_TIMEOUT = 1000 * 120; + + public delegate void ConnectedCallback(); + public delegate void EventCallback(string eventName, OSDMap body); + + public ConnectedCallback OnConnected; + public EventCallback OnEvent; + + public bool Running { get { return _Running; } } + + protected Uri _Address; + protected bool _Dead; + protected bool _Running; + protected HttpWebRequest _Request; + + /// Number of times we've received an unknown CAPS exception in series. + private int _errorCount; + /// For exponential backoff on error. + private static Random _random = new Random(); + + public EventQueueClient(Uri eventQueueLocation) + { + _Address = eventQueueLocation; + } + + public void Start() + { + _Dead = false; + + // Create an EventQueueGet request + OSDMap request = new OSDMap(); + request["ack"] = new OSD(); + request["done"] = OSD.FromBoolean(false); + + byte[] postData = OSDParser.SerializeLLSDXmlBytes(request); + + _Request = CapsBase.UploadDataAsync(_Address, null, "application/xml", postData, REQUEST_TIMEOUT, OpenWriteHandler, null, RequestCompletedHandler); + } + + public void Stop(bool immediate) + { + _Dead = true; + + if (immediate) + _Running = false; + + if (_Request != null) + _Request.Abort(); + } + + void OpenWriteHandler(HttpWebRequest request) + { + _Running = true; + _Request = request; + + Logger.DebugLog("Capabilities event queue connected"); + + // The event queue is starting up for the first time + if (OnConnected != null) + { + try { OnConnected(); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, ex); } + } + } + + void RequestCompletedHandler(HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) + { + // We don't care about this request now that it has completed + _Request = null; + + OSDArray events = null; + int ack = 0; + + if (responseData != null) + { + _errorCount = 0; + // Got a response + OSDMap result = OSDParser.DeserializeLLSDXml(responseData) as OSDMap; + + if (result != null) + { + events = result["events"] as OSDArray; + ack = result["id"].AsInteger(); + } + else + { + Logger.Log("Got an unparseable response from the event queue: \"" + + System.Text.Encoding.UTF8.GetString(responseData) + "\"", Helpers.LogLevel.Warning); + } + } + else if (error != null) + { + #region Error handling + + HttpStatusCode code = HttpStatusCode.OK; + + if (error is WebException) + { + WebException webException = (WebException)error; + + if (webException.Response != null) + code = ((HttpWebResponse)webException.Response).StatusCode; + else if (webException.Status == WebExceptionStatus.RequestCanceled) + goto HandlingDone; + } + + if (error is WebException && ((WebException)error).Response != null) + code = ((HttpWebResponse)((WebException)error).Response).StatusCode; + + if (code == HttpStatusCode.NotFound || code == HttpStatusCode.Gone) + { + Logger.Log(String.Format("Closing event queue at {0} due to missing caps URI", _Address), Helpers.LogLevel.Info); + + _Running = false; + _Dead = true; + } + else if (code == HttpStatusCode.BadGateway) + { + // This is not good (server) protocol design, but it's normal. + // The EventQueue server is a proxy that connects to a Squid + // cache which will time out periodically. The EventQueue server + // interprets this as a generic error and returns a 502 to us + // that we ignore + } + else + { + ++_errorCount; + + // Try to log a meaningful error message + if (code != HttpStatusCode.OK) + { + Logger.Log(String.Format("Unrecognized caps connection problem from {0}: {1}", + _Address, code), Helpers.LogLevel.Warning); + } + else if (error.InnerException != null) + { + Logger.Log(String.Format("Unrecognized internal caps exception from {0}: {1}", + _Address, error.InnerException.Message), Helpers.LogLevel.Warning); + } + else + { + Logger.Log(String.Format("Unrecognized caps exception from {0}: {1}", + _Address, error.Message), Helpers.LogLevel.Warning); + } + } + + #endregion Error handling + } + else + { + ++_errorCount; + + Logger.Log("No response from the event queue but no reported error either", Helpers.LogLevel.Warning); + } + + HandlingDone: + + #region Resume the connection + + if (_Running) + { + OSDMap osdRequest = new OSDMap(); + if (ack != 0) osdRequest["ack"] = OSD.FromInteger(ack); + else osdRequest["ack"] = new OSD(); + osdRequest["done"] = OSD.FromBoolean(_Dead); + + byte[] postData = OSDParser.SerializeLLSDXmlBytes(osdRequest); + + if (_errorCount > 0) // Exponentially back off, so we don't hammer the CPU + Thread.Sleep(_random.Next(500 + (int)Math.Pow(2, _errorCount))); + + // Resume the connection. The event handler for the connection opening + // just sets class _Request variable to the current HttpWebRequest + CapsBase.UploadDataAsync(_Address, null, "application/xml", postData, REQUEST_TIMEOUT, + delegate(HttpWebRequest newRequest) { _Request = newRequest; }, null, RequestCompletedHandler); + + // If the event queue is dead at this point, turn it off since + // that was the last thing we want to do + if (_Dead) + { + _Running = false; + Logger.DebugLog("Sent event queue shutdown message"); + } + } + + #endregion Resume the connection + + #region Handle incoming events + + if (OnEvent != null && events != null && events.Count > 0) + { + // Fire callbacks for each event received + foreach (OSDMap evt in events) + { + string msg = evt["message"].AsString(); + OSDMap body = (OSDMap)evt["body"]; + + try { OnEvent(msg, body); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, ex); } + } + } + + #endregion Handle incoming events + } + } +} diff --git a/OpenMetaverse/Caps.cs b/OpenMetaverse/Caps.cs new file mode 100644 index 0000000..5924520 --- /dev/null +++ b/OpenMetaverse/Caps.cs @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Http; + +namespace OpenMetaverse +{ + /// + /// Capabilities is the name of the bi-directional HTTP REST protocol + /// used to communicate non real-time transactions such as teleporting or + /// group messaging + /// + public partial class Caps + { + /// + /// Triggered when an event is received via the EventQueueGet + /// capability + /// + /// Event name + /// Decoded event data + /// The simulator that generated the event + //public delegate void EventQueueCallback(string message, StructuredData.OSD body, Simulator simulator); + + public delegate void EventQueueCallback(string capsKey, IMessage message, Simulator simulator); + + /// Reference to the simulator this system is connected to + public Simulator Simulator; + + internal string _SeedCapsURI; + internal Dictionary _Caps = new Dictionary(); + + private CapsClient _SeedRequest; + private EventQueueClient _EventQueueCap = null; + + /// Capabilities URI this system was initialized with + public string SeedCapsURI { get { return _SeedCapsURI; } } + + /// Whether the capabilities event queue is connected and + /// listening for incoming events + public bool IsEventQueueRunning + { + get + { + if (_EventQueueCap != null) + return _EventQueueCap.Running; + else + return false; + } + } + + /// + /// Default constructor + /// + /// + /// + internal Caps(Simulator simulator, string seedcaps) + { + Simulator = simulator; + _SeedCapsURI = seedcaps; + + MakeSeedRequest(); + } + + public void Disconnect(bool immediate) + { + Logger.Log(String.Format("Caps system for {0} is {1}", Simulator, + (immediate ? "aborting" : "disconnecting")), Helpers.LogLevel.Info, Simulator.Client); + + if (_SeedRequest != null) + _SeedRequest.Cancel(); + + if (_EventQueueCap != null) + _EventQueueCap.Stop(immediate); + } + + /// + /// Request the URI of a named capability + /// + /// Name of the capability to request + /// The URI of the requested capability, or String.Empty if + /// the capability does not exist + public Uri CapabilityURI(string capability) + { + Uri cap; + + if (_Caps.TryGetValue(capability, out cap)) + return cap; + else + return null; + } + + private void MakeSeedRequest() + { + if (Simulator == null || !Simulator.Client.Network.Connected) + return; + + // Create a request list + OSDArray req = new OSDArray(); + // This list can be updated by using the following command to obtain a current list of capabilities the official linden viewer supports: + // wget -q -O - https://bitbucket.org/lindenlab/viewer-release/raw/default/indra/newview/llviewerregion.cpp | grep 'capabilityNames.append' | sed 's/^[ \t]*//;s/capabilityNames.append("/req.Add("/' + req.Add("AgentPreferences"); + req.Add("AgentState"); + req.Add("AttachmentResources"); + req.Add("AvatarPickerSearch"); + req.Add("AvatarRenderInfo"); + req.Add("CharacterProperties"); + req.Add("ChatSessionRequest"); + req.Add("CopyInventoryFromNotecard"); + req.Add("CreateInventoryCategory"); + req.Add("DispatchRegionInfo"); + req.Add("EnvironmentSettings"); + req.Add("EstateChangeInfo"); + req.Add("EventQueueGet"); + req.Add("FacebookConnect"); + req.Add("FlickrConnect"); + req.Add("TwitterConnect"); + req.Add("FetchLib2"); + req.Add("FetchLibDescendents2"); + req.Add("FetchInventory2"); + req.Add("FetchInventoryDescendents2"); + req.Add("IncrementCOFVersion"); + req.Add("GetDisplayNames"); + req.Add("GetMesh"); + req.Add("GetMesh2"); + req.Add("GetObjectCost"); + req.Add("GetObjectPhysicsData"); + req.Add("GetTexture"); + req.Add("GroupAPIv1"); + req.Add("GroupMemberData"); + req.Add("GroupProposalBallot"); + req.Add("HomeLocation"); + req.Add("LandResources"); + req.Add("LSLSyntax"); + req.Add("MapLayer"); + req.Add("MapLayerGod"); + req.Add("MeshUploadFlag"); + req.Add("NavMeshGenerationStatus"); + req.Add("NewFileAgentInventory"); + req.Add("ObjectMedia"); + req.Add("ObjectMediaNavigate"); + req.Add("ObjectNavMeshProperties"); + req.Add("ParcelPropertiesUpdate"); + req.Add("ParcelVoiceInfoRequest"); + req.Add("ProductInfoRequest"); + req.Add("ProvisionVoiceAccountRequest"); + req.Add("RemoteParcelRequest"); + req.Add("RenderMaterials"); + req.Add("RequestTextureDownload"); + req.Add("ResourceCostSelected"); + req.Add("RetrieveNavMeshSrc"); + req.Add("SearchStatRequest"); + req.Add("SearchStatTracking"); + req.Add("SendPostcard"); + req.Add("SendUserReport"); + req.Add("SendUserReportWithScreenshot"); + req.Add("ServerReleaseNotes"); + req.Add("SetDisplayName"); + req.Add("SimConsoleAsync"); + req.Add("SimulatorFeatures"); + req.Add("StartGroupProposal"); + req.Add("TerrainNavMeshProperties"); + req.Add("TextureStats"); + req.Add("UntrustedSimulatorMessage"); + req.Add("UpdateAgentInformation"); + req.Add("UpdateAgentLanguage"); + req.Add("UpdateAvatarAppearance"); + req.Add("UpdateGestureAgentInventory"); + req.Add("UpdateGestureTaskInventory"); + req.Add("UpdateNotecardAgentInventory"); + req.Add("UpdateNotecardTaskInventory"); + req.Add("UpdateScriptAgent"); + req.Add("UpdateScriptTask"); + req.Add("UploadBakedTexture"); + req.Add("ViewerMetrics"); + req.Add("ViewerStartAuction"); + req.Add("ViewerStats"); + + _SeedRequest = new CapsClient(new Uri(_SeedCapsURI)); + _SeedRequest.OnComplete += new CapsClient.CompleteCallback(SeedRequestCompleteHandler); + _SeedRequest.BeginGetResponse(req, OSDFormat.Xml, Simulator.Client.Settings.CAPS_TIMEOUT); + } + + private void SeedRequestCompleteHandler(CapsClient client, OSD result, Exception error) + { + if (result != null && result.Type == OSDType.Map) + { + OSDMap respTable = (OSDMap)result; + + foreach (string cap in respTable.Keys) + { + _Caps[cap] = respTable[cap].AsUri(); + } + + if (_Caps.ContainsKey("EventQueueGet")) + { + Logger.DebugLog("Starting event queue for " + Simulator.ToString(), Simulator.Client); + + _EventQueueCap = new EventQueueClient(_Caps["EventQueueGet"]); + _EventQueueCap.OnConnected += EventQueueConnectedHandler; + _EventQueueCap.OnEvent += EventQueueEventHandler; + _EventQueueCap.Start(); + } + } + else if ( + error != null && + error is WebException && + ((WebException)error).Response != null && + ((HttpWebResponse)((WebException)error).Response).StatusCode == HttpStatusCode.NotFound) + { + // 404 error + Logger.Log("Seed capability returned a 404, capability system is aborting", Helpers.LogLevel.Error); + } + else + { + // The initial CAPS connection failed, try again + MakeSeedRequest(); + } + } + + private void EventQueueConnectedHandler() + { + Simulator.Client.Network.RaiseConnectedEvent(Simulator); + } + + /// + /// Process any incoming events, check to see if we have a message created for the event, + /// + /// + /// + private void EventQueueEventHandler(string eventName, OSDMap body) + { + IMessage message = Messages.MessageUtils.DecodeEvent(eventName, body); + if (message != null) + { + Simulator.Client.Network.CapsEvents.BeginRaiseEvent(eventName, message, Simulator); + + #region Stats Tracking + if (Simulator.Client.Settings.TRACK_UTILIZATION) + { + Simulator.Client.Stats.Update(eventName, OpenMetaverse.Stats.Type.Message, 0, body.ToString().Length); + } + #endregion + } + else + { + Logger.Log("No Message handler exists for event " + eventName + ". Unable to decode. Will try Generic Handler next", Helpers.LogLevel.Warning); + Logger.Log("Please report this information to http://jira.openmetaverse.org/: \n" + body, Helpers.LogLevel.Debug); + + // try generic decoder next which takes a caps event and tries to match it to an existing packet + if (body.Type == OSDType.Map) + { + OSDMap map = (OSDMap)body; + Packet packet = Packet.BuildPacket(eventName, map); + if (packet != null) + { + NetworkManager.IncomingPacket incomingPacket; + incomingPacket.Simulator = Simulator; + incomingPacket.Packet = packet; + + Logger.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler", Simulator.Client); + + Simulator.Client.Network.PacketInbox.Enqueue(incomingPacket); + } + else + { + Logger.Log("No Packet or Message handler exists for " + eventName, Helpers.LogLevel.Warning); + } + } + } + } + } +} diff --git a/OpenMetaverse/CapsToPacket.cs b/OpenMetaverse/CapsToPacket.cs new file mode 100644 index 0000000..eba389e --- /dev/null +++ b/OpenMetaverse/CapsToPacket.cs @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Packets +{ + public abstract partial class Packet + { + #region Serialization/Deserialization + + public static string ToXmlString(Packet packet) + { + return OSDParser.SerializeLLSDXmlString(GetLLSD(packet)); + } + + public static OSD GetLLSD(Packet packet) + { + OSDMap body = new OSDMap(); + Type type = packet.GetType(); + + foreach (FieldInfo field in type.GetFields()) + { + if (field.IsPublic) + { + Type blockType = field.FieldType; + + if (blockType.IsArray) + { + object blockArray = field.GetValue(packet); + Array array = (Array)blockArray; + OSDArray blockList = new OSDArray(array.Length); + IEnumerator ie = array.GetEnumerator(); + + while (ie.MoveNext()) + { + object block = ie.Current; + blockList.Add(BuildLLSDBlock(block)); + } + + body[field.Name] = blockList; + } + else + { + object block = field.GetValue(packet); + body[field.Name] = BuildLLSDBlock(block); + } + } + } + + return body; + } + + public static byte[] ToBinary(Packet packet) + { + return OSDParser.SerializeLLSDBinary(GetLLSD(packet)); + } + + public static Packet FromXmlString(string xml) + { + System.Xml.XmlTextReader reader = + new System.Xml.XmlTextReader(new System.IO.MemoryStream(Utils.StringToBytes(xml))); + + return FromLLSD(OSDParser.DeserializeLLSDXml(reader)); + } + + public static Packet FromLLSD(OSD osd) + { + // FIXME: Need the inverse of the reflection magic above done here + throw new NotImplementedException(); + } + + #endregion Serialization/Deserialization + + /// + /// Attempts to convert an LLSD structure to a known Packet type + /// + /// Event name, this must match an actual + /// packet name for a Packet to be successfully built + /// LLSD to convert to a Packet + /// A Packet on success, otherwise null + public static Packet BuildPacket(string capsEventName, OSDMap body) + { + Assembly assembly = Assembly.GetExecutingAssembly(); + + // Check if we have a subclass of packet with the same name as this event + Type type = assembly.GetType("OpenMetaverse.Packets." + capsEventName + "Packet", false); + if (type == null) + return null; + + Packet packet = null; + + try + { + // Create an instance of the object + packet = (Packet)Activator.CreateInstance(type); + + // Iterate over all of the fields in the packet class, looking for matches in the LLSD + foreach (FieldInfo field in type.GetFields()) + { + if (body.ContainsKey(field.Name)) + { + Type blockType = field.FieldType; + + if (blockType.IsArray) + { + OSDArray array = (OSDArray)body[field.Name]; + Type elementType = blockType.GetElementType(); + object[] blockArray = (object[])Array.CreateInstance(elementType, array.Count); + + for (int i = 0; i < array.Count; i++) + { + OSDMap map = (OSDMap)array[i]; + blockArray[i] = ParseLLSDBlock(map, elementType); + } + + field.SetValue(packet, blockArray); + } + else + { + OSDMap map = (OSDMap)((OSDArray)body[field.Name])[0]; + field.SetValue(packet, ParseLLSDBlock(map, blockType)); + } + } + } + } + catch (Exception) + { + //FIXME Logger.Log(e.Message, Helpers.LogLevel.Error, e); + } + + return packet; + } + + private static object ParseLLSDBlock(OSDMap blockData, Type blockType) + { + object block = Activator.CreateInstance(blockType); + + // Iterate over each field and set the value if a match was found in the LLSD + foreach (FieldInfo field in blockType.GetFields()) + { + if (blockData.ContainsKey(field.Name)) + { + Type fieldType = field.FieldType; + + if (fieldType == typeof(ulong)) + { + // ulongs come in as a byte array, convert it manually here + byte[] bytes = blockData[field.Name].AsBinary(); + ulong value = Utils.BytesToUInt64(bytes); + field.SetValue(block, value); + } + else if (fieldType == typeof(uint)) + { + // uints come in as a byte array, convert it manually here + byte[] bytes = blockData[field.Name].AsBinary(); + uint value = Utils.BytesToUInt(bytes); + field.SetValue(block, value); + } + else if (fieldType == typeof(ushort)) + { + // Just need a bit of manual typecasting love here + field.SetValue(block, (ushort)blockData[field.Name].AsInteger()); + } + else if (fieldType == typeof(byte)) + { + // Just need a bit of manual typecasting love here + field.SetValue(block, (byte)blockData[field.Name].AsInteger()); + } + else if (fieldType == typeof(sbyte)) + { + field.SetValue(block, (sbyte)blockData[field.Name].AsInteger()); + } + else if (fieldType == typeof(short)) + { + field.SetValue(block, (short)blockData[field.Name].AsInteger()); + } + else if (fieldType == typeof(string)) + { + field.SetValue(block, blockData[field.Name].AsString()); + } + else if (fieldType == typeof(bool)) + { + field.SetValue(block, blockData[field.Name].AsBoolean()); + } + else if (fieldType == typeof(float)) + { + field.SetValue(block, (float)blockData[field.Name].AsReal()); + } + else if (fieldType == typeof(double)) + { + field.SetValue(block, blockData[field.Name].AsReal()); + } + else if (fieldType == typeof(int)) + { + field.SetValue(block, blockData[field.Name].AsInteger()); + } + else if (fieldType == typeof(UUID)) + { + field.SetValue(block, blockData[field.Name].AsUUID()); + } + else if (fieldType == typeof(Vector3)) + { + Vector3 vec = ((OSDArray)blockData[field.Name]).AsVector3(); + field.SetValue(block, vec); + } + else if (fieldType == typeof(Vector4)) + { + Vector4 vec = ((OSDArray)blockData[field.Name]).AsVector4(); + field.SetValue(block, vec); + } + else if (fieldType == typeof(Quaternion)) + { + Quaternion quat = ((OSDArray)blockData[field.Name]).AsQuaternion(); + field.SetValue(block, quat); + } + else if (fieldType == typeof(byte[]) && blockData[field.Name].Type == OSDType.String) + { + field.SetValue(block, Utils.StringToBytes(blockData[field.Name])); + } + } + } + + // Additional fields come as properties, Handle those as well. + foreach (PropertyInfo property in blockType.GetProperties()) + { + if (blockData.ContainsKey(property.Name)) + { + OSDType proptype = blockData[property.Name].Type; + MethodInfo set = property.GetSetMethod(); + + if (proptype.Equals(OSDType.Binary)) + { + set.Invoke(block, new object[] { blockData[property.Name].AsBinary() }); + } + else + set.Invoke(block, new object[] { Utils.StringToBytes(blockData[property.Name].AsString()) }); + } + } + + return block; + } + + private static OSD BuildLLSDBlock(object block) + { + OSDMap map = new OSDMap(); + Type blockType = block.GetType(); + + foreach (FieldInfo field in blockType.GetFields()) + { + if (field.IsPublic) + map[field.Name] = OSD.FromObject(field.GetValue(block)); + } + + foreach (PropertyInfo property in blockType.GetProperties()) + { + if (property.Name != "Length") + { + map[property.Name] = OSD.FromObject(property.GetValue(block, null)); + } + } + + return map; + } + } +} diff --git a/OpenMetaverse/CoordinateFrame.cs b/OpenMetaverse/CoordinateFrame.cs new file mode 100644 index 0000000..eabe5b9 --- /dev/null +++ b/OpenMetaverse/CoordinateFrame.cs @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + public class CoordinateFrame + { + public static readonly Vector3 X_AXIS = new Vector3(1f, 0f, 0f); + public static readonly Vector3 Y_AXIS = new Vector3(0f, 1f, 0f); + public static readonly Vector3 Z_AXIS = new Vector3(0f, 0f, 1f); + + /// Origin position of this coordinate frame + public Vector3 Origin + { + get { return origin; } + set + { + if (!value.IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame.Origin assignment"); + origin = value; + } + } + /// X axis of this coordinate frame, or Forward/At in grid terms + public Vector3 XAxis + { + get { return xAxis; } + set + { + if (!value.IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame.XAxis assignment"); + xAxis = value; + } + } + /// Y axis of this coordinate frame, or Left in grid terms + public Vector3 YAxis + { + get { return yAxis; } + set + { + if (!value.IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame.YAxis assignment"); + yAxis = value; + } + } + /// Z axis of this coordinate frame, or Up in grid terms + public Vector3 ZAxis + { + get { return zAxis; } + set + { + if (!value.IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame.ZAxis assignment"); + zAxis = value; + } + } + + protected Vector3 origin; + protected Vector3 xAxis; + protected Vector3 yAxis; + protected Vector3 zAxis; + + #region Constructors + + public CoordinateFrame(Vector3 origin) + { + this.origin = origin; + xAxis = X_AXIS; + yAxis = Y_AXIS; + zAxis = Z_AXIS; + + if (!this.origin.IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame constructor"); + } + + public CoordinateFrame(Vector3 origin, Vector3 direction) + { + this.origin = origin; + LookDirection(direction); + + if (!IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame constructor"); + } + + public CoordinateFrame(Vector3 origin, Vector3 xAxis, Vector3 yAxis, Vector3 zAxis) + { + this.origin = origin; + this.xAxis = xAxis; + this.yAxis = yAxis; + this.zAxis = zAxis; + + if (!IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame constructor"); + } + + public CoordinateFrame(Vector3 origin, Matrix4 rotation) + { + this.origin = origin; + xAxis = rotation.AtAxis; + yAxis = rotation.LeftAxis; + zAxis = rotation.UpAxis; + + if (!IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame constructor"); + } + + public CoordinateFrame(Vector3 origin, Quaternion rotation) + { + Matrix4 m = Matrix4.CreateFromQuaternion(rotation); + + this.origin = origin; + xAxis = m.AtAxis; + yAxis = m.LeftAxis; + zAxis = m.UpAxis; + + if (!IsFinite()) + throw new ArgumentException("Non-finite in CoordinateFrame constructor"); + } + + #endregion Constructors + + #region Public Methods + + public void ResetAxes() + { + xAxis = X_AXIS; + yAxis = Y_AXIS; + zAxis = Z_AXIS; + } + + public void Rotate(float angle, Vector3 rotationAxis) + { + Quaternion q = Quaternion.CreateFromAxisAngle(rotationAxis, angle); + Rotate(q); + } + + public void Rotate(Quaternion q) + { + Matrix4 m = Matrix4.CreateFromQuaternion(q); + Rotate(m); + } + + public void Rotate(Matrix4 m) + { + xAxis = Vector3.Transform(xAxis, m); + yAxis = Vector3.Transform(yAxis, m); + + Orthonormalize(); + + if (!IsFinite()) + throw new Exception("Non-finite in CoordinateFrame.Rotate()"); + } + + public void Roll(float angle) + { + Quaternion q = Quaternion.CreateFromAxisAngle(xAxis, angle); + Matrix4 m = Matrix4.CreateFromQuaternion(q); + Rotate(m); + + if (!yAxis.IsFinite() || !zAxis.IsFinite()) + throw new Exception("Non-finite in CoordinateFrame.Roll()"); + } + + public void Pitch(float angle) + { + Quaternion q = Quaternion.CreateFromAxisAngle(yAxis, angle); + Matrix4 m = Matrix4.CreateFromQuaternion(q); + Rotate(m); + + if (!xAxis.IsFinite() || !zAxis.IsFinite()) + throw new Exception("Non-finite in CoordinateFrame.Pitch()"); + } + + public void Yaw(float angle) + { + Quaternion q = Quaternion.CreateFromAxisAngle(zAxis, angle); + Matrix4 m = Matrix4.CreateFromQuaternion(q); + Rotate(m); + + if (!xAxis.IsFinite() || !yAxis.IsFinite()) + throw new Exception("Non-finite in CoordinateFrame.Yaw()"); + } + + public void LookDirection(Vector3 at) + { + LookDirection(at, Z_AXIS); + } + + /// + /// + /// + /// Looking direction, must be a normalized vector + /// Up direction, must be a normalized vector + public void LookDirection(Vector3 at, Vector3 upDirection) + { + // The two parameters cannot be parallel + Vector3 left = Vector3.Cross(upDirection, at); + if (left == Vector3.Zero) + { + // Prevent left from being zero + at.X += 0.01f; + at.Normalize(); + left = Vector3.Cross(upDirection, at); + } + left.Normalize(); + + xAxis = at; + yAxis = left; + zAxis = Vector3.Cross(at, left); + } + + /// + /// Align the coordinate frame X and Y axis with a given rotation + /// around the Z axis in radians + /// + /// Absolute rotation around the Z axis in + /// radians + public void LookDirection(double heading) + { + yAxis.X = (float)Math.Cos(heading); + yAxis.Y = (float)Math.Sin(heading); + xAxis.X = (float)-Math.Sin(heading); + xAxis.Y = (float)Math.Cos(heading); + } + + public void LookAt(Vector3 origin, Vector3 target) + { + LookAt(origin, target, new Vector3(0f, 0f, 1f)); + } + + public void LookAt(Vector3 origin, Vector3 target, Vector3 upDirection) + { + this.origin = origin; + Vector3 at = new Vector3(target - origin); + at.Normalize(); + + LookDirection(at, upDirection); + } + + #endregion Public Methods + + protected bool IsFinite() + { + if (xAxis.IsFinite() && yAxis.IsFinite() && zAxis.IsFinite()) + return true; + else + return false; + } + + protected void Orthonormalize() + { + // Make sure the axis are orthagonal and normalized + xAxis.Normalize(); + yAxis -= xAxis * (xAxis * yAxis); + yAxis.Normalize(); + zAxis = Vector3.Cross(xAxis, yAxis); + } + } +} diff --git a/OpenMetaverse/DirectoryManager.cs b/OpenMetaverse/DirectoryManager.cs new file mode 100644 index 0000000..2ff99d4 --- /dev/null +++ b/OpenMetaverse/DirectoryManager.cs @@ -0,0 +1,1610 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using System.Collections.Generic; +using OpenMetaverse.Packets; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse +{ + /// + /// Access to the data server which allows searching for land, events, people, etc + /// + public class DirectoryManager + { + #region Enums + /// Classified Ad categories + public enum ClassifiedCategories + { + /// Classified is listed in the Any category + Any = 0, + /// Classified is shopping related + Shopping, + /// Classified is + LandRental, + /// + PropertyRental, + /// + SpecialAttraction, + /// + NewProducts, + /// + Employment, + /// + Wanted, + /// + Service, + /// + Personal + } + + /// Event Categories + public enum EventCategories + { + /// + All = 0, + /// + Discussion = 18, + /// + Sports = 19, + /// + LiveMusic = 20, + /// + Commercial = 22, + /// + Nightlife = 23, + /// + Games = 24, + /// + Pageants = 25, + /// + Education = 26, + /// + Arts = 27, + /// + Charity = 28, + /// + Miscellaneous = 29 + } + + /// + /// Query Flags used in many of the DirectoryManager methods to specify which query to execute and how to return the results. + /// + /// Flags can be combined using the | (pipe) character, not all flags are available in all queries + /// + [Flags] + public enum DirFindFlags + { + /// Query the People database + People = 1 << 0, + /// + Online = 1 << 1, + // + //[Obsolete] + //Places = 1 << 2, + /// + Events = 1 << 3, + /// Query the Groups database + Groups = 1 << 4, + /// Query the Events database + DateEvents = 1 << 5, + /// Query the land holdings database for land owned by the currently connected agent + AgentOwned = 1 << 6, + /// + ForSale = 1 << 7, + /// Query the land holdings database for land which is owned by a Group + GroupOwned = 1 << 8, + // + //[Obsolete] + //Auction = 1 << 9, + /// Specifies the query should pre sort the results based upon traffic + /// when searching the Places database + DwellSort = 1 << 10, + /// + PgSimsOnly = 1 << 11, + /// + PicturesOnly = 1 << 12, + /// + PgEventsOnly = 1 << 13, + /// + MatureSimsOnly = 1 << 14, + /// Specifies the query should pre sort the results in an ascending order when searching the land sales database. + /// This flag is only used when searching the land sales database + SortAsc = 1 << 15, + /// Specifies the query should pre sort the results using the SalePrice field when searching the land sales database. + /// This flag is only used when searching the land sales database + PricesSort = 1 << 16, + /// Specifies the query should pre sort the results by calculating the average price/sq.m (SalePrice / Area) when searching the land sales database. + /// This flag is only used when searching the land sales database + PerMeterSort = 1 << 17, + /// Specifies the query should pre sort the results using the ParcelSize field when searching the land sales database. + /// This flag is only used when searching the land sales database + AreaSort = 1 << 18, + /// Specifies the query should pre sort the results using the Name field when searching the land sales database. + /// This flag is only used when searching the land sales database + NameSort = 1 << 19, + /// When set, only parcels less than the specified Price will be included when searching the land sales database. + /// This flag is only used when searching the land sales database + LimitByPrice = 1 << 20, + /// When set, only parcels greater than the specified Size will be included when searching the land sales database. + /// This flag is only used when searching the land sales database + LimitByArea = 1 << 21, + /// + FilterMature = 1 << 22, + /// + PGOnly = 1 << 23, + /// Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases + IncludePG = 1 << 24, + /// Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases + IncludeMature = 1 << 25, + /// Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases + IncludeAdult = 1 << 26, + /// + AdultOnly = 1 << 27 + } + + /// + /// Land types to search dataserver for + /// + [Flags] + public enum SearchTypeFlags + { + /// Search Auction, Mainland and Estate + Any = -1, + /// Land which is currently up for auction + Auction = 1 << 1, + // Land available to new landowners (formerly the FirstLand program) + //[Obsolete] + //Newbie = 1 << 2, + /// Parcels which are on the mainland (Linden owned) continents + Mainland = 1 << 3, + /// Parcels which are on privately owned simulators + Estate = 1 << 4 + } + + /// + /// The content rating of the event + /// + public enum EventFlags + { + /// Event is PG + PG = 0, + /// Event is Mature + Mature = 1, + /// Event is Adult + Adult = 2 + } + + /// + /// Classified Ad Options + /// + /// There appear to be two formats the flags are packed in. + /// This set of flags is for the newer style + [Flags] + public enum ClassifiedFlags : byte + { + /// + None = 1 << 0, + /// + Mature = 1 << 1, + /// + Enabled = 1 << 2, + // HasPrice = 1 << 3, // Deprecated + /// + UpdateTime = 1 << 4, + /// + AutoRenew = 1 << 5 + } + + /// + /// Classified ad query options + /// + [Flags] + public enum ClassifiedQueryFlags + { + /// Include all ads in results + All = PG | Mature | Adult, + /// Include PG ads in results + PG = 1 << 2, + /// Include Mature ads in results + Mature = 1 << 3, + /// Include Adult ads in results + Adult = 1 << 6, + } + + /// + /// The For Sale flag in PlacesReplyData + /// + public enum PlacesFlags : byte + { + /// Parcel is not listed for sale + NotForSale = 0, + /// Parcel is For Sale + ForSale = 128 + } + + #endregion + #region Structs + /// + /// A classified ad on the grid + /// + public struct Classified + { + /// UUID for this ad, useful for looking up detailed + /// information about it + public UUID ID; + /// The title of this classified ad + public string Name; + /// Flags that show certain options applied to the classified + public ClassifiedFlags Flags; + /// Creation date of the ad + public DateTime CreationDate; + /// Expiration date of the ad + public DateTime ExpirationDate; + /// Price that was paid for this ad + public int Price; + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// + /// A parcel retrieved from the dataserver such as results from the + /// "For-Sale" listings or "Places" Search + /// + public struct DirectoryParcel + { + /// The unique dataserver parcel ID + /// This id is used to obtain additional information from the entry + /// by using the method + public UUID ID; + /// A string containing the name of the parcel + public string Name; + /// The size of the parcel + /// This field is not returned for Places searches + public int ActualArea; + /// The price of the parcel + /// This field is not returned for Places searches + public int SalePrice; + /// If True, this parcel is flagged to be auctioned + public bool Auction; + /// If true, this parcel is currently set for sale + public bool ForSale; + /// Parcel traffic + public float Dwell; + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// + /// An Avatar returned from the dataserver + /// + public struct AgentSearchData + { + /// Online status of agent + /// This field appears to be obsolete and always returns false + public bool Online; + /// The agents first name + public string FirstName; + /// The agents last name + public string LastName; + /// The agents + public UUID AgentID; + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// + /// Response to a "Groups" Search + /// + public struct GroupSearchData + { + /// The Group ID + public UUID GroupID; + /// The name of the group + public string GroupName; + /// The current number of members + public int Members; + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// + /// Parcel information returned from a request + /// + /// Represents one of the following: + /// A parcel of land on the grid that has its Show In Search flag set + /// A parcel of land owned by the agent making the request + /// A parcel of land owned by a group the agent making the request is a member of + /// + /// + /// In a request for Group Land, the First record will contain an empty record + /// + /// Note: This is not the same as searching the land for sale data source + /// + public struct PlacesSearchData + { + /// The ID of the Agent of Group that owns the parcel + public UUID OwnerID; + /// The name + public string Name; + /// The description + public string Desc; + /// The Size of the parcel + public int ActualArea; + /// The billable Size of the parcel, for mainland + /// parcels this will match the ActualArea field. For Group owned land this will be 10 percent smaller + /// than the ActualArea. For Estate land this will always be 0 + public int BillableArea; + /// Indicates the ForSale status of the parcel + public PlacesFlags Flags; + /// The Gridwide X position + public float GlobalX; + /// The Gridwide Y position + public float GlobalY; + /// The Z position of the parcel, or 0 if no landing point set + public float GlobalZ; + /// The name of the Region the parcel is located in + public string SimName; + /// The Asset ID of the parcels Snapshot texture + public UUID SnapshotID; + /// The calculated visitor traffic + public float Dwell; + /// The billing product SKU + /// Known values are: + /// + /// 023Mainland / Full Region + /// 024Estate / Full Region + /// 027Estate / Openspace + /// 029Estate / Homestead + /// 129Mainland / Homestead (Linden Owned) + /// + /// + public string SKU; + /// No longer used, will always be 0 + public int Price; + + /// Get a SL URL for the parcel + /// A string, containing a standard SLURL + public string ToSLurl() + { + float x, y; + Helpers.GlobalPosToRegionHandle(this.GlobalX, this.GlobalY, out x, out y); + return "secondlife://" + this.SimName + "/" + x + "/" + y + "/" + this.GlobalZ; + } + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// + /// An "Event" Listing summary + /// + public struct EventsSearchData + { + /// The ID of the event creator + public UUID Owner; + /// The name of the event + public string Name; + /// The events ID + public uint ID; + /// A string containing the short date/time the event will begin + public string Date; + /// The event start time in Unixtime (seconds since epoch) + public uint Time; + /// The events maturity rating + public EventFlags Flags; + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + /// + /// The details of an "Event" + /// + public struct EventInfo + { + /// The events ID + public uint ID; + /// The ID of the event creator + public UUID Creator; + /// The name of the event + public string Name; + /// The category + public EventCategories Category; + /// The events description + public string Desc; + /// The short date/time the event will begin + public string Date; + /// The event start time in Unixtime (seconds since epoch) UTC adjusted + public uint DateUTC; + /// The length of the event in minutes + public uint Duration; + /// 0 if no cover charge applies + public uint Cover; + /// The cover charge amount in L$ if applicable + public uint Amount; + /// The name of the region where the event is being held + public string SimName; + /// The gridwide location of the event + public Vector3d GlobalPos; + /// The maturity rating + public EventFlags Flags; + + /// Get a SL URL for the parcel where the event is hosted + /// A string, containing a standard SLURL + public string ToSLurl() + { + float x, y; + Helpers.GlobalPosToRegionHandle((float)this.GlobalPos.X, (float)this.GlobalPos.Y, out x, out y); + return "secondlife://" + this.SimName + "/" + x + "/" + y + "/" + this.GlobalPos.Z; + } + + /// Print the struct data as a string + /// A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + } + + #endregion Structs + + #region Event delegates, Raise Events + + /// The event subscribers. null if no subcribers + private EventHandler m_EventInfoReply; + + /// Raises the EventInfoReply event + /// An EventInfoReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEventInfo(EventInfoReplyEventArgs e) + { + EventHandler handler = m_EventInfoReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EventDetailLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EventInfoReply + { + add { lock (m_EventDetailLock) { m_EventInfoReply += value; } } + remove { lock (m_EventDetailLock) { m_EventInfoReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_DirEvents; + + /// Raises the DirEventsReply event + /// An DirEventsReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnDirEvents(DirEventsReplyEventArgs e) + { + EventHandler handler = m_DirEvents; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DirEventsLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler DirEventsReply + { + add { lock (m_DirEventsLock) { m_DirEvents += value; } } + remove { lock (m_DirEventsLock) { m_DirEvents -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_Places; + + /// Raises the PlacesReply event + /// A PlacesReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnPlaces(PlacesReplyEventArgs e) + { + EventHandler handler = m_Places; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_PlacesLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler PlacesReply + { + add { lock (m_PlacesLock) { m_Places += value; } } + remove { lock (m_PlacesLock) { m_Places -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_DirPlaces; + + /// Raises the DirPlacesReply event + /// A DirPlacesReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnDirPlaces(DirPlacesReplyEventArgs e) + { + EventHandler handler = m_DirPlaces; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DirPlacesLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler DirPlacesReply + { + add { lock (m_DirPlacesLock) { m_DirPlaces += value; } } + remove { lock (m_DirPlacesLock) { m_DirPlaces -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_DirClassifieds; + + /// Raises the DirClassifiedsReply event + /// A DirClassifiedsReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnDirClassifieds(DirClassifiedsReplyEventArgs e) + { + EventHandler handler = m_DirClassifieds; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DirClassifiedsLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler DirClassifiedsReply + { + add { lock (m_DirClassifiedsLock) { m_DirClassifieds += value; } } + remove { lock (m_DirClassifiedsLock) { m_DirClassifieds -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_DirGroups; + + /// Raises the DirGroupsReply event + /// A DirGroupsReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnDirGroups(DirGroupsReplyEventArgs e) + { + EventHandler handler = m_DirGroups; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DirGroupsLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler DirGroupsReply + { + add { lock (m_DirGroupsLock) { m_DirGroups += value; } } + remove { lock (m_DirGroupsLock) { m_DirGroups -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_DirPeople; + + /// Raises the DirPeopleReply event + /// A DirPeopleReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnDirPeople(DirPeopleReplyEventArgs e) + { + EventHandler handler = m_DirPeople; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DirPeopleLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler DirPeopleReply + { + add { lock (m_DirPeopleLock) { m_DirPeople += value; } } + remove { lock (m_DirPeopleLock) { m_DirPeople -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_DirLandReply; + + /// Raises the DirLandReply event + /// A DirLandReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnDirLand(DirLandReplyEventArgs e) + { + EventHandler handler = m_DirLandReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DirLandLock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler DirLandReply + { + add { lock (m_DirLandLock) { m_DirLandReply += value; } } + remove { lock (m_DirLandLock) { m_DirLandReply -= value; } } + } + + #endregion + + #region Private Members + private GridClient Client; + #endregion + + #region Constructors + /// + /// Constructs a new instance of the DirectoryManager class + /// + /// An instance of GridClient + public DirectoryManager(GridClient client) + { + Client = client; + + Client.Network.RegisterCallback(PacketType.DirClassifiedReply, DirClassifiedReplyHandler); + // Deprecated, replies come in over capabilities + Client.Network.RegisterCallback(PacketType.DirLandReply, DirLandReplyHandler); + Client.Network.RegisterEventCallback("DirLandReply", DirLandReplyEventHandler); + Client.Network.RegisterCallback(PacketType.DirPeopleReply, DirPeopleReplyHandler); + Client.Network.RegisterCallback(PacketType.DirGroupsReply, DirGroupsReplyHandler); + // Deprecated as of viewer 1.2.3 + Client.Network.RegisterCallback(PacketType.PlacesReply, PlacesReplyHandler); + Client.Network.RegisterEventCallback("PlacesReply", PlacesReplyEventHandler); + Client.Network.RegisterCallback(PacketType.DirEventsReply, EventsReplyHandler); + Client.Network.RegisterCallback(PacketType.EventInfoReply, EventInfoReplyHandler); + Client.Network.RegisterCallback(PacketType.DirPlacesReply, DirPlacesReplyHandler); + } + + #endregion + + #region Public Methods + // Obsoleted due to new Adult search option + [Obsolete("Use Overload with ClassifiedQueryFlags option instead")] + public UUID StartClassifiedSearch(string searchText, ClassifiedCategories category, bool mature) + { + return UUID.Zero; + } + + /// + /// Query the data server for a list of classified ads containing the specified string. + /// Defaults to searching for classified placed in any category, and includes PG, Adult and Mature + /// results. + /// + /// Responses are sent 16 per response packet, there is no way to know how many results a query reply will contain however assuming + /// the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received + /// + /// The event is raised when a response is received from the simulator + /// + /// A string containing a list of keywords to search for + /// A UUID to correlate the results when the event is raised + public UUID StartClassifiedSearch(string searchText) + { + return StartClassifiedSearch(searchText, ClassifiedCategories.Any, ClassifiedQueryFlags.All); + } + + /// + /// Query the data server for a list of classified ads which contain specified keywords (Overload) + /// + /// The event is raised when a response is received from the simulator + /// + /// A string containing a list of keywords to search for + /// The category to search + /// A set of flags which can be ORed to modify query options + /// such as classified maturity rating. + /// A UUID to correlate the results when the event is raised + /// + /// Search classified ads containing the key words "foo" and "bar" in the "Any" category that are either PG or Mature + /// + /// UUID searchID = StartClassifiedSearch("foo bar", ClassifiedCategories.Any, ClassifiedQueryFlags.PG | ClassifiedQueryFlags.Mature); + /// + /// + /// + /// Responses are sent 16 at a time, there is no way to know how many results a query reply will contain however assuming + /// the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received + /// + public UUID StartClassifiedSearch(string searchText, ClassifiedCategories category, ClassifiedQueryFlags queryFlags) + { + DirClassifiedQueryPacket query = new DirClassifiedQueryPacket(); + UUID queryID = UUID.Random(); + + query.AgentData.AgentID = Client.Self.AgentID; + query.AgentData.SessionID = Client.Self.SessionID; + + query.QueryData.Category = (uint)category; + query.QueryData.QueryFlags = (uint)queryFlags; + query.QueryData.QueryID = queryID; + query.QueryData.QueryText = Utils.StringToBytes(searchText); + + Client.Network.SendPacket(query); + + return queryID; + } + + /// + /// Starts search for places (Overloaded) + /// + /// The event is raised when a response is received from the simulator + /// + /// Search text + /// Each request is limited to 100 places + /// being returned. To get the first 100 result entries of a request use 0, + /// from 100-199 use 1, 200-299 use 2, etc. + /// A UUID to correlate the results when the event is raised + public UUID StartDirPlacesSearch(string searchText, int queryStart) + { + return StartDirPlacesSearch(searchText, DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeMature + | DirFindFlags.IncludeAdult, ParcelCategory.Any, queryStart); + } + + /// + /// Queries the dataserver for parcels of land which are flagged to be shown in search + /// + /// The event is raised when a response is received from the simulator + /// + /// A string containing a list of keywords to search for separated by a space character + /// A set of flags which can be ORed to modify query options + /// such as classified maturity rating. + /// The category to search + /// Each request is limited to 100 places + /// being returned. To get the first 100 result entries of a request use 0, + /// from 100-199 use 1, 200-299 use 2, etc. + /// A UUID to correlate the results when the event is raised + /// + /// Search places containing the key words "foo" and "bar" in the "Any" category that are either PG or Adult + /// + /// UUID searchID = StartDirPlacesSearch("foo bar", DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeAdult, ParcelCategory.Any, 0); + /// + /// + /// + /// Additional information on the results can be obtained by using the ParcelManager.InfoRequest method + /// + public UUID StartDirPlacesSearch(string searchText, DirFindFlags queryFlags, ParcelCategory category, int queryStart) + { + DirPlacesQueryPacket query = new DirPlacesQueryPacket(); + + UUID queryID = UUID.Random(); + + query.AgentData.AgentID = Client.Self.AgentID; + query.AgentData.SessionID = Client.Self.SessionID; + + query.QueryData.Category = (sbyte)category; + query.QueryData.QueryFlags = (uint)queryFlags; + + query.QueryData.QueryID = queryID; + query.QueryData.QueryText = Utils.StringToBytes(searchText); + query.QueryData.QueryStart = queryStart; + query.QueryData.SimName = Utils.StringToBytes(string.Empty); + + Client.Network.SendPacket(query); + + return queryID; + + } + + /// + /// Starts a search for land sales using the directory + /// + /// The event is raised when a response is received from the simulator + /// + /// What type of land to search for. Auction, + /// estate, mainland, "first land", etc + /// The OnDirLandReply event handler must be registered before + /// calling this function. There is no way to determine how many + /// results will be returned, or how many times the callback will be + /// fired other than you won't get more than 100 total parcels from + /// each query. + public void StartLandSearch(SearchTypeFlags typeFlags) + { + StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort, typeFlags, 0, 0, 0); + } + + /// + /// Starts a search for land sales using the directory + /// + /// The event is raised when a response is received from the simulator + /// + /// What type of land to search for. Auction, + /// estate, mainland, "first land", etc + /// Maximum price to search for + /// Maximum area to search for + /// Each request is limited to 100 parcels + /// being returned. To get the first 100 parcels of a request use 0, + /// from 100-199 use 1, 200-299 use 2, etc. + /// The OnDirLandReply event handler must be registered before + /// calling this function. There is no way to determine how many + /// results will be returned, or how many times the callback will be + /// fired other than you won't get more than 100 total parcels from + /// each query. + public void StartLandSearch(SearchTypeFlags typeFlags, int priceLimit, int areaLimit, int queryStart) + { + StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort | DirFindFlags.LimitByPrice | + DirFindFlags.LimitByArea, typeFlags, priceLimit, areaLimit, queryStart); + } + + /// + /// Send a request to the data server for land sales listings + /// + /// + /// Flags sent to specify query options + /// + /// Available flags: + /// Specify the parcel rating with one or more of the following: + /// IncludePG IncludeMature IncludeAdult + /// + /// Specify the field to pre sort the results with ONLY ONE of the following: + /// PerMeterSort NameSort AreaSort PricesSort + /// + /// Specify the order the results are returned in, if not specified the results are pre sorted in a Descending Order + /// SortAsc + /// + /// Specify additional filters to limit the results with one or both of the following: + /// LimitByPrice LimitByArea + /// + /// Flags can be combined by separating them with the | (pipe) character + /// + /// Additional details can be found in + /// + /// What type of land to search for. Auction, + /// Estate or Mainland + /// Maximum price to search for when the + /// DirFindFlags.LimitByPrice flag is specified in findFlags + /// Maximum area to search for when the + /// DirFindFlags.LimitByArea flag is specified in findFlags + /// Each request is limited to 100 parcels + /// being returned. To get the first 100 parcels of a request use 0, + /// from 100-199 use 100, 200-299 use 200, etc. + /// The event will be raised with the response from the simulator + /// + /// There is no way to determine how many results will be returned, or how many times the callback will be + /// fired other than you won't get more than 100 total parcels from + /// each reply. + /// + /// Any land set for sale to either anybody or specific to the connected agent will be included in the + /// results if the land is included in the query + /// + /// + /// // request all mainland, any maturity rating that is larger than 512 sq.m + /// StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort | DirFindFlags.LimitByArea | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, SearchTypeFlags.Mainland, 0, 512, 0); + /// + public void StartLandSearch(DirFindFlags findFlags, SearchTypeFlags typeFlags, int priceLimit, + int areaLimit, int queryStart) + { + DirLandQueryPacket query = new DirLandQueryPacket(); + query.AgentData.AgentID = Client.Self.AgentID; + query.AgentData.SessionID = Client.Self.SessionID; + query.QueryData.Area = areaLimit; + query.QueryData.Price = priceLimit; + query.QueryData.QueryStart = queryStart; + query.QueryData.SearchType = (uint)typeFlags; + query.QueryData.QueryFlags = (uint)findFlags; + query.QueryData.QueryID = UUID.Random(); + + Client.Network.SendPacket(query); + } + + /// + /// Search for Groups + /// + /// The name or portion of the name of the group you wish to search for + /// Start from the match number + /// + public UUID StartGroupSearch(string searchText, int queryStart) + { + return StartGroupSearch(searchText, queryStart, DirFindFlags.Groups | DirFindFlags.IncludePG + | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult); + } + + /// + /// Search for Groups + /// + /// The name or portion of the name of the group you wish to search for + /// Start from the match number + /// Search flags + /// + public UUID StartGroupSearch(string searchText, int queryStart, DirFindFlags flags) + { + DirFindQueryPacket find = new DirFindQueryPacket(); + find.AgentData.AgentID = Client.Self.AgentID; + find.AgentData.SessionID = Client.Self.SessionID; + find.QueryData.QueryFlags = (uint)flags; + find.QueryData.QueryText = Utils.StringToBytes(searchText); + find.QueryData.QueryID = UUID.Random(); + find.QueryData.QueryStart = queryStart; + + Client.Network.SendPacket(find); + + return find.QueryData.QueryID; + } + + /// + /// Search the People directory for other avatars + /// + /// The name or portion of the name of the avatar you wish to search for + /// + /// + public UUID StartPeopleSearch(string searchText, int queryStart) + { + DirFindQueryPacket find = new DirFindQueryPacket(); + find.AgentData.AgentID = Client.Self.AgentID; + find.AgentData.SessionID = Client.Self.SessionID; + find.QueryData.QueryFlags = (uint)DirFindFlags.People; + find.QueryData.QueryText = Utils.StringToBytes(searchText); + find.QueryData.QueryID = UUID.Random(); + find.QueryData.QueryStart = queryStart; + + Client.Network.SendPacket(find); + + return find.QueryData.QueryID; + } + + /// + /// Search Places for parcels of land you personally own + /// + public UUID StartPlacesSearch() + { + return StartPlacesSearch(DirFindFlags.AgentOwned, ParcelCategory.Any, String.Empty, String.Empty, + UUID.Zero, UUID.Random()); + } + + /// + /// Searches Places for land owned by the specified group + /// + /// ID of the group you want to recieve land list for (You must be a member of the group) + /// Transaction (Query) ID which can be associated with results from your request. + public UUID StartPlacesSearch(UUID groupID) + { + return StartPlacesSearch(DirFindFlags.GroupOwned, ParcelCategory.Any, String.Empty, String.Empty, + groupID, UUID.Random()); + } + + /// + /// Search the Places directory for parcels that are listed in search and contain the specified keywords + /// + /// A string containing the keywords to search for + /// Transaction (Query) ID which can be associated with results from your request. + public UUID StartPlacesSearch(string searchText) + { + return StartPlacesSearch(DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, + ParcelCategory.Any, searchText, String.Empty, UUID.Zero, UUID.Random()); + } + + /// + /// Search Places - All Options + /// + /// One of the Values from the DirFindFlags struct, ie: AgentOwned, GroupOwned, etc. + /// One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer + /// A string containing a list of keywords to search for separated by a space character + /// String Simulator Name to search in + /// LLUID of group you want to recieve results for + /// Transaction (Query) ID which can be associated with results from your request. + /// Transaction (Query) ID which can be associated with results from your request. + public UUID StartPlacesSearch(DirFindFlags findFlags, ParcelCategory searchCategory, string searchText, string simulatorName, + UUID groupID, UUID transactionID) + { + PlacesQueryPacket find = new PlacesQueryPacket(); + find.AgentData.AgentID = Client.Self.AgentID; + find.AgentData.SessionID = Client.Self.SessionID; + find.AgentData.QueryID = groupID; + + find.TransactionData.TransactionID = transactionID; + + find.QueryData.QueryText = Utils.StringToBytes(searchText); + find.QueryData.QueryFlags = (uint)findFlags; + find.QueryData.Category = (sbyte)searchCategory; + find.QueryData.SimName = Utils.StringToBytes(simulatorName); + + Client.Network.SendPacket(find); + return transactionID; + } + + /// + /// Search All Events with specifid searchText in all categories, includes PG, Mature and Adult + /// + /// A string containing a list of keywords to search for separated by a space character + /// Each request is limited to 100 entries + /// being returned. To get the first group of entries of a request use 0, + /// from 100-199 use 100, 200-299 use 200, etc. + /// UUID of query to correlate results in callback. + public UUID StartEventsSearch(string searchText, uint queryStart) + { + return StartEventsSearch(searchText, DirFindFlags.DateEvents | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, + "u", queryStart, EventCategories.All); + } + + /// + /// Search Events + /// + /// A string containing a list of keywords to search for separated by a space character + /// One or more of the following flags: DateEvents, IncludePG, IncludeMature, IncludeAdult + /// from the Enum + /// + /// Multiple flags can be combined by separating the flags with the | (pipe) character + /// "u" for in-progress and upcoming events, -or- number of days since/until event is scheduled + /// For example "0" = Today, "1" = tomorrow, "2" = following day, "-1" = yesterday, etc. + /// Each request is limited to 100 entries + /// being returned. To get the first group of entries of a request use 0, + /// from 100-199 use 100, 200-299 use 200, etc. + /// EventCategory event is listed under. + /// UUID of query to correlate results in callback. + public UUID StartEventsSearch(string searchText, DirFindFlags queryFlags, string eventDay, uint queryStart, EventCategories category) + { + DirFindQueryPacket find = new DirFindQueryPacket(); + find.AgentData.AgentID = Client.Self.AgentID; + find.AgentData.SessionID = Client.Self.SessionID; + + UUID queryID = UUID.Random(); + + find.QueryData.QueryID = queryID; + find.QueryData.QueryText = Utils.StringToBytes(eventDay + "|" + (int)category + "|" + searchText); + find.QueryData.QueryFlags = (uint)queryFlags; + find.QueryData.QueryStart = (int)queryStart; + + Client.Network.SendPacket(find); + return queryID; + } + + /// Requests Event Details + /// ID of Event returned from the method + public void EventInfoRequest(uint eventID) + { + EventInfoRequestPacket find = new EventInfoRequestPacket(); + find.AgentData.AgentID = Client.Self.AgentID; + find.AgentData.SessionID = Client.Self.SessionID; + + find.EventData.EventID = eventID; + + Client.Network.SendPacket(find); + } + #endregion + + #region Blocking Functions + + [Obsolete("Use the async StartPeoplSearch method instead")] + public bool PeopleSearch(DirFindFlags findFlags, string searchText, int queryStart, + int timeoutMS, out List results) + { + AutoResetEvent searchEvent = new AutoResetEvent(false); + UUID id = UUID.Zero; + List people = null; + + EventHandler callback = + delegate(object sender, DirPeopleReplyEventArgs e) + { + if (id == e.QueryID) + { + people = e.MatchedPeople; + searchEvent.Set(); + } + }; + + DirPeopleReply += callback; + + id = StartPeopleSearch(searchText, queryStart); + searchEvent.WaitOne(timeoutMS, false); + DirPeopleReply -= callback; + + results = people; + return (results != null); + } + + #endregion Blocking Functions + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void DirClassifiedReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_DirClassifieds != null) + { + DirClassifiedReplyPacket reply = (DirClassifiedReplyPacket)e.Packet; + List classifieds = new List(); + + foreach (DirClassifiedReplyPacket.QueryRepliesBlock block in reply.QueryReplies) + { + Classified classified = new Classified(); + + classified.CreationDate = Utils.UnixTimeToDateTime(block.CreationDate); + classified.ExpirationDate = Utils.UnixTimeToDateTime(block.ExpirationDate); + classified.Flags = (ClassifiedFlags)block.ClassifiedFlags; + classified.ID = block.ClassifiedID; + classified.Name = Utils.BytesToString(block.Name); + classified.Price = block.PriceForListing; + + classifieds.Add(classified); + } + + OnDirClassifieds(new DirClassifiedsReplyEventArgs(classifieds)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void DirLandReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_DirLandReply != null) + { + List parcelsForSale = new List(); + DirLandReplyPacket reply = (DirLandReplyPacket)e.Packet; + + foreach (DirLandReplyPacket.QueryRepliesBlock block in reply.QueryReplies) + { + DirectoryParcel dirParcel = new DirectoryParcel(); + + dirParcel.ActualArea = block.ActualArea; + dirParcel.ID = block.ParcelID; + dirParcel.Name = Utils.BytesToString(block.Name); + dirParcel.SalePrice = block.SalePrice; + dirParcel.Auction = block.Auction; + dirParcel.ForSale = block.ForSale; + + parcelsForSale.Add(dirParcel); + } + OnDirLand(new DirLandReplyEventArgs(parcelsForSale)); + } + } + + /// Process an incoming event message + /// The Unique Capabilities Key + /// The event message containing the data + /// The simulator the message originated from + protected void DirLandReplyEventHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_DirLandReply != null) + { + List parcelsForSale = new List(); + + DirLandReplyMessage reply = (DirLandReplyMessage)message; + + foreach (DirLandReplyMessage.QueryReply block in reply.QueryReplies) + { + DirectoryParcel dirParcel = new DirectoryParcel(); + + dirParcel.ActualArea = block.ActualArea; + dirParcel.ID = block.ParcelID; + dirParcel.Name = block.Name; + dirParcel.SalePrice = block.SalePrice; + dirParcel.Auction = block.Auction; + dirParcel.ForSale = block.ForSale; + + parcelsForSale.Add(dirParcel); + } + + OnDirLand(new DirLandReplyEventArgs(parcelsForSale)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void DirPeopleReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_DirPeople != null) + { + DirPeopleReplyPacket peopleReply = e.Packet as DirPeopleReplyPacket; + List matches = new List(peopleReply.QueryReplies.Length); + foreach (DirPeopleReplyPacket.QueryRepliesBlock reply in peopleReply.QueryReplies) + { + AgentSearchData searchData = new AgentSearchData(); + searchData.Online = reply.Online; + searchData.FirstName = Utils.BytesToString(reply.FirstName); + searchData.LastName = Utils.BytesToString(reply.LastName); + searchData.AgentID = reply.AgentID; + matches.Add(searchData); + } + + OnDirPeople(new DirPeopleReplyEventArgs(peopleReply.QueryData.QueryID, matches)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void DirGroupsReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_DirGroups != null) + { + Packet packet = e.Packet; + DirGroupsReplyPacket groupsReply = (DirGroupsReplyPacket)packet; + List matches = new List(groupsReply.QueryReplies.Length); + foreach (DirGroupsReplyPacket.QueryRepliesBlock reply in groupsReply.QueryReplies) + { + GroupSearchData groupsData = new GroupSearchData(); + groupsData.GroupID = reply.GroupID; + groupsData.GroupName = Utils.BytesToString(reply.GroupName); + groupsData.Members = reply.Members; + matches.Add(groupsData); + } + + OnDirGroups(new DirGroupsReplyEventArgs(groupsReply.QueryData.QueryID, matches)); + } + } + + /// Process an incoming event message + /// The Unique Capabilities Key + /// The event message containing the data + /// The simulator the message originated from + protected void PlacesReplyEventHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_Places != null) + { + PlacesReplyMessage replyMessage = (PlacesReplyMessage)message; + List places = new List(); + + for (int i = 0; i < replyMessage.QueryDataBlocks.Length; i++) + { + PlacesSearchData place = new PlacesSearchData(); + place.ActualArea = replyMessage.QueryDataBlocks[i].ActualArea; + place.BillableArea = replyMessage.QueryDataBlocks[i].BillableArea; + place.Desc = replyMessage.QueryDataBlocks[i].Description; + place.Dwell = replyMessage.QueryDataBlocks[i].Dwell; + place.Flags = (DirectoryManager.PlacesFlags)(byte)replyMessage.QueryDataBlocks[i].Flags; + place.GlobalX = replyMessage.QueryDataBlocks[i].GlobalX; + place.GlobalY = replyMessage.QueryDataBlocks[i].GlobalY; + place.GlobalZ = replyMessage.QueryDataBlocks[i].GlobalZ; + place.Name = replyMessage.QueryDataBlocks[i].Name; + place.OwnerID = replyMessage.QueryDataBlocks[i].OwnerID; + place.Price = replyMessage.QueryDataBlocks[i].Price; + place.SimName = replyMessage.QueryDataBlocks[i].SimName; + place.SnapshotID = replyMessage.QueryDataBlocks[i].SnapShotID; + place.SKU = replyMessage.QueryDataBlocks[i].ProductSku; + places.Add(place); + } + + OnPlaces(new PlacesReplyEventArgs(replyMessage.QueryID, places)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void PlacesReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_Places != null) + { + Packet packet = e.Packet; + PlacesReplyPacket placesReply = packet as PlacesReplyPacket; + List places = new List(); + + foreach (PlacesReplyPacket.QueryDataBlock block in placesReply.QueryData) + { + PlacesSearchData place = new PlacesSearchData(); + place.OwnerID = block.OwnerID; + place.Name = Utils.BytesToString(block.Name); + place.Desc = Utils.BytesToString(block.Desc); + place.ActualArea = block.ActualArea; + place.BillableArea = block.BillableArea; + place.Flags = (PlacesFlags)block.Flags; + place.GlobalX = block.GlobalX; + place.GlobalY = block.GlobalY; + place.GlobalZ = block.GlobalZ; + place.SimName = Utils.BytesToString(block.SimName); + place.SnapshotID = block.SnapshotID; + place.Dwell = block.Dwell; + place.Price = block.Price; + + places.Add(place); + } + + OnPlaces(new PlacesReplyEventArgs(placesReply.TransactionData.TransactionID, places)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void EventsReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_DirEvents != null) + { + Packet packet = e.Packet; + DirEventsReplyPacket eventsReply = (DirEventsReplyPacket)packet; + List matches = new List(eventsReply.QueryReplies.Length); + + foreach (DirEventsReplyPacket.QueryRepliesBlock reply in eventsReply.QueryReplies) + { + EventsSearchData eventsData = new EventsSearchData(); + eventsData.Owner = reply.OwnerID; + eventsData.Name = Utils.BytesToString(reply.Name); + eventsData.ID = reply.EventID; + eventsData.Date = Utils.BytesToString(reply.Date); + eventsData.Time = reply.UnixTime; + eventsData.Flags = (EventFlags)reply.EventFlags; + matches.Add(eventsData); + } + + OnDirEvents(new DirEventsReplyEventArgs(eventsReply.QueryData.QueryID, matches)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void EventInfoReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_EventInfoReply != null) + { + Packet packet = e.Packet; + EventInfoReplyPacket eventReply = (EventInfoReplyPacket)packet; + EventInfo evinfo = new EventInfo(); + evinfo.ID = eventReply.EventData.EventID; + evinfo.Name = Utils.BytesToString(eventReply.EventData.Name); + evinfo.Desc = Utils.BytesToString(eventReply.EventData.Desc); + evinfo.Amount = eventReply.EventData.Amount; + evinfo.Category = (EventCategories)Utils.BytesToUInt(eventReply.EventData.Category); + evinfo.Cover = eventReply.EventData.Cover; + evinfo.Creator = (UUID)Utils.BytesToString(eventReply.EventData.Creator); + evinfo.Date = Utils.BytesToString(eventReply.EventData.Date); + evinfo.DateUTC = eventReply.EventData.DateUTC; + evinfo.Duration = eventReply.EventData.Duration; + evinfo.Flags = (EventFlags)eventReply.EventData.EventFlags; + evinfo.SimName = Utils.BytesToString(eventReply.EventData.SimName); + evinfo.GlobalPos = eventReply.EventData.GlobalPos; + + OnEventInfo(new EventInfoReplyEventArgs(evinfo)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void DirPlacesReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_DirPlaces != null) + { + Packet packet = e.Packet; + DirPlacesReplyPacket reply = (DirPlacesReplyPacket)packet; + List result = new List(); + + for (int i = 0; i < reply.QueryReplies.Length; i++) + { + DirectoryParcel p = new DirectoryParcel(); + + p.ID = reply.QueryReplies[i].ParcelID; + p.Name = Utils.BytesToString(reply.QueryReplies[i].Name); + p.Dwell = reply.QueryReplies[i].Dwell; + p.Auction = reply.QueryReplies[i].Auction; + p.ForSale = reply.QueryReplies[i].ForSale; + + result.Add(p); + } + + OnDirPlaces(new DirPlacesReplyEventArgs(reply.QueryData[0].QueryID, result)); + } + } + + #endregion Packet Handlers + } + + #region DirectoryManager EventArgs Classes + + /// Contains the Event data returned from the data server from an EventInfoRequest + public class EventInfoReplyEventArgs : EventArgs + { + private readonly DirectoryManager.EventInfo m_MatchedEvent; + + /// + /// A single EventInfo object containing the details of an event + /// + public DirectoryManager.EventInfo MatchedEvent { get { return m_MatchedEvent; } } + + /// Construct a new instance of the EventInfoReplyEventArgs class + /// A single EventInfo object containing the details of an event + public EventInfoReplyEventArgs(DirectoryManager.EventInfo matchedEvent) + { + this.m_MatchedEvent = matchedEvent; + } + } + + /// Contains the "Event" detail data returned from the data server + public class DirEventsReplyEventArgs : EventArgs + { + private readonly UUID m_QueryID; + /// The ID returned by + public UUID QueryID { get { return m_QueryID; } } + + private readonly List m_matchedEvents; + + /// A list of "Events" returned by the data server + public List MatchedEvents { get { return m_matchedEvents; } } + + /// Construct a new instance of the DirEventsReplyEventArgs class + /// The ID of the query returned by the data server. + /// This will correlate to the ID returned by the method + /// A list containing the "Events" returned by the search query + public DirEventsReplyEventArgs(UUID queryID, List matchedEvents) + { + this.m_QueryID = queryID; + this.m_matchedEvents = matchedEvents; + } + } + + /// Contains the "Event" list data returned from the data server + public class PlacesReplyEventArgs : EventArgs + { + private readonly UUID m_QueryID; + /// The ID returned by + public UUID QueryID { get { return m_QueryID; } } + + private readonly List m_MatchedPlaces; + + /// A list of "Places" returned by the data server + public List MatchedPlaces { get { return m_MatchedPlaces; } } + + /// Construct a new instance of PlacesReplyEventArgs class + /// The ID of the query returned by the data server. + /// This will correlate to the ID returned by the method + /// A list containing the "Places" returned by the data server query + public PlacesReplyEventArgs(UUID queryID, List matchedPlaces) + { + this.m_QueryID = queryID; + this.m_MatchedPlaces = matchedPlaces; + } + } + + /// Contains the places data returned from the data server + public class DirPlacesReplyEventArgs : EventArgs + { + private readonly UUID m_QueryID; + /// The ID returned by + public UUID QueryID { get { return m_QueryID; } } + + private readonly List m_MatchedParcels; + + /// A list containing Places data returned by the data server + public List MatchedParcels { get { return m_MatchedParcels; } } + + /// Construct a new instance of the DirPlacesReplyEventArgs class + /// The ID of the query returned by the data server. + /// This will correlate to the ID returned by the method + /// A list containing land data returned by the data server + public DirPlacesReplyEventArgs(UUID queryID, List matchedParcels) + { + this.m_QueryID = queryID; + this.m_MatchedParcels = matchedParcels; + } + } + + /// Contains the classified data returned from the data server + public class DirClassifiedsReplyEventArgs : EventArgs + { + private readonly List m_Classifieds; + /// A list containing Classified Ads returned by the data server + public List Classifieds { get { return m_Classifieds; } } + + /// Construct a new instance of the DirClassifiedsReplyEventArgs class + /// A list of classified ad data returned from the data server + public DirClassifiedsReplyEventArgs(List classifieds) + { + this.m_Classifieds = classifieds; + } + } + + /// Contains the group data returned from the data server + public class DirGroupsReplyEventArgs : EventArgs + { + private readonly UUID m_QueryID; + /// The ID returned by + public UUID QueryID { get { return m_QueryID; } } + + private readonly List m_matchedGroups; + + /// A list containing Groups data returned by the data server + public List MatchedGroups { get { return m_matchedGroups; } } + + /// Construct a new instance of the DirGroupsReplyEventArgs class + /// The ID of the query returned by the data server. + /// This will correlate to the ID returned by the method + /// A list of groups data returned by the data server + public DirGroupsReplyEventArgs(UUID queryID, List matchedGroups) + { + this.m_QueryID = queryID; + this.m_matchedGroups = matchedGroups; + } + } + + /// Contains the people data returned from the data server + public class DirPeopleReplyEventArgs : EventArgs + { + private readonly UUID m_QueryID; + /// The ID returned by + public UUID QueryID { get { return m_QueryID; } } + + private readonly List m_MatchedPeople; + + /// A list containing People data returned by the data server + public List MatchedPeople { get { return m_MatchedPeople; } } + + /// Construct a new instance of the DirPeopleReplyEventArgs class + /// The ID of the query returned by the data server. + /// This will correlate to the ID returned by the method + /// A list of people data returned by the data server + public DirPeopleReplyEventArgs(UUID queryID, List matchedPeople) + { + this.m_QueryID = queryID; + this.m_MatchedPeople = matchedPeople; + } + } + + /// Contains the land sales data returned from the data server + public class DirLandReplyEventArgs : EventArgs + { + private readonly List m_DirParcels; + + /// A list containing land forsale data returned by the data server + public List DirParcels { get { return m_DirParcels; } } + + /// Construct a new instance of the DirLandReplyEventArgs class + /// A list of parcels for sale returned by the data server + public DirLandReplyEventArgs(List dirParcels) + { + this.m_DirParcels = dirParcels; + } + } + #endregion +} diff --git a/OpenMetaverse/DownloadManager.cs b/OpenMetaverse/DownloadManager.cs new file mode 100644 index 0000000..145d2cf --- /dev/null +++ b/OpenMetaverse/DownloadManager.cs @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using OpenMetaverse.Http; + +namespace OpenMetaverse +{ + /// + /// Represends individual HTTP Download request + /// + public class DownloadRequest + { + /// URI of the item to fetch + public Uri Address; + /// Timout specified in milliseconds + public int MillisecondsTimeout; + /// Download progress callback + public CapsBase.DownloadProgressEventHandler DownloadProgressCallback; + /// Download completed callback + public CapsBase.RequestCompletedEventHandler CompletedCallback; + /// Accept the following content type + public string ContentType; + /// How many times will this request be retried + public int Retries = 5; + /// Current fetch attempt + public int Attempt = 0; + + /// Default constructor + public DownloadRequest() + { + } + + /// Constructor + public DownloadRequest(Uri address, int millisecondsTimeout, + string contentType, + CapsBase.DownloadProgressEventHandler downloadProgressCallback, + CapsBase.RequestCompletedEventHandler completedCallback) + { + this.Address = address; + this.MillisecondsTimeout = millisecondsTimeout; + this.DownloadProgressCallback = downloadProgressCallback; + this.CompletedCallback = completedCallback; + this.ContentType = contentType; + } + } + + internal class ActiveDownload + { + public List ProgresHadlers = new List(); + public List CompletedHandlers = new List(); + public HttpWebRequest Request; + } + + /// + /// Manages async HTTP downloads with a limit on maximum + /// concurrent downloads + /// + public class DownloadManager + { + Queue queue = new Queue(); + Dictionary activeDownloads = new Dictionary(); + + X509Certificate2 m_ClientCert; + + /// Maximum number of parallel downloads from a single endpoint + public int ParallelDownloads { get; set; } + + /// Client certificate + public X509Certificate2 ClientCert + { + get { return m_ClientCert; } + set { m_ClientCert = value; } + } + + /// Default constructor + public DownloadManager() + { + ParallelDownloads = 8; + } + + /// Cleanup method + public virtual void Dispose() + { + lock (activeDownloads) + { + foreach (ActiveDownload download in activeDownloads.Values) + { + try + { + if (download.Request != null) + { + download.Request.Abort(); + } + } + catch { } + } + activeDownloads.Clear(); + } + } + + /// Setup http download request + protected virtual HttpWebRequest SetupRequest(Uri address, string acceptHeader) + { + HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(address); + request.Method = "GET"; + + if (!string.IsNullOrEmpty(acceptHeader)) + request.Accept = acceptHeader; + + // Add the client certificate to the request if one was given + if (m_ClientCert != null) + request.ClientCertificates.Add(m_ClientCert); + + // Leave idle connections to this endpoint open for up to 60 seconds + request.ServicePoint.MaxIdleTime = 0; + // Disable stupid Expect-100: Continue header + request.ServicePoint.Expect100Continue = false; + // Crank up the max number of connections per endpoint + if (request.ServicePoint.ConnectionLimit < Settings.MAX_HTTP_CONNECTIONS) + { + Logger.Log(string.Format("In DownloadManager.SetupRequest() setting conn limit for {0}:{1} to {2}", address.Host, address.Port, Settings.MAX_HTTP_CONNECTIONS), Helpers.LogLevel.Debug); + request.ServicePoint.ConnectionLimit = Settings.MAX_HTTP_CONNECTIONS; + } + + return request; + } + + /// Check the queue for pending work + private void EnqueuePending() + { + lock (queue) + { + if (queue.Count > 0) + { + int nr = 0; + lock (activeDownloads) + { + nr = activeDownloads.Count; + } + + // Logger.DebugLog(nr.ToString() + " active downloads. Queued textures: " + queue.Count.ToString()); + + for (int i = nr; i < ParallelDownloads && queue.Count > 0; i++) + { + DownloadRequest item = queue.Dequeue(); + lock (activeDownloads) + { + string addr = item.Address.ToString(); + if (activeDownloads.ContainsKey(addr)) + { + activeDownloads[addr].CompletedHandlers.Add(item.CompletedCallback); + if (item.DownloadProgressCallback != null) + { + activeDownloads[addr].ProgresHadlers.Add(item.DownloadProgressCallback); + } + } + else + { + ActiveDownload activeDownload = new ActiveDownload(); + activeDownload.CompletedHandlers.Add(item.CompletedCallback); + if (item.DownloadProgressCallback != null) + { + activeDownload.ProgresHadlers.Add(item.DownloadProgressCallback); + } + + Logger.DebugLog("Requesting " + item.Address.ToString()); + activeDownload.Request = SetupRequest(item.Address, item.ContentType); + CapsBase.DownloadDataAsync( + activeDownload.Request, + item.MillisecondsTimeout, + (HttpWebRequest request, HttpWebResponse response, int bytesReceived, int totalBytesToReceive) => + { + foreach (CapsBase.DownloadProgressEventHandler handler in activeDownload.ProgresHadlers) + { + handler(request, response, bytesReceived, totalBytesToReceive); + } + }, + (HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) => + { + lock (activeDownloads) activeDownloads.Remove(addr); + if (error == null || item.Attempt >= item.Retries || (error != null && error.Message.Contains("404"))) + { + foreach (CapsBase.RequestCompletedEventHandler handler in activeDownload.CompletedHandlers) + { + handler(request, response, responseData, error); + } + } + else + { + item.Attempt++; + Logger.Log(string.Format("Texture {0} HTTP download failed, trying again retry {1}/{2}", + item.Address, item.Attempt, item.Retries), Helpers.LogLevel.Warning); + lock (queue) queue.Enqueue(item); + } + + EnqueuePending(); + } + ); + + activeDownloads[addr] = activeDownload; + } + } + } + } + } + } + + /// Enqueue a new HTTP download + public void QueueDownload(DownloadRequest req) + { + lock (activeDownloads) + { + string addr = req.Address.ToString(); + if (activeDownloads.ContainsKey(addr)) + { + activeDownloads[addr].CompletedHandlers.Add(req.CompletedCallback); + if (req.DownloadProgressCallback != null) + { + activeDownloads[addr].ProgresHadlers.Add(req.DownloadProgressCallback); + } + return; + } + } + + lock (queue) + { + queue.Enqueue(req); + } + EnqueuePending(); + } + } +} diff --git a/OpenMetaverse/EstateTools.cs b/OpenMetaverse/EstateTools.cs new file mode 100644 index 0000000..9e616df --- /dev/null +++ b/OpenMetaverse/EstateTools.cs @@ -0,0 +1,1235 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using OpenMetaverse.Packets; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; +using System.Collections.Generic; + +namespace OpenMetaverse +{ + /// Describes tasks returned in LandStatReply + public class EstateTask + { + public Vector3 Position; + public float Score; + public float MonoScore; + public UUID TaskID; + public uint TaskLocalID; + public string TaskName; + public string OwnerName; + } + + /// + /// Estate level administration and utilities + /// + public class EstateTools + { + private GridClient Client; + + /// Textures for each of the four terrain height levels + public GroundTextureSettings GroundTextures; + + /// Upper/lower texture boundaries for each corner of the sim + public GroundTextureHeightSettings GroundTextureLimits; + + /// + /// Constructor for EstateTools class + /// + /// + public EstateTools(GridClient client) + { + GroundTextures = new GroundTextureSettings(); + GroundTextureLimits = new GroundTextureHeightSettings(); + + Client = client; + Client.Network.RegisterCallback(PacketType.LandStatReply, LandStatReplyHandler); + Client.Network.RegisterCallback(PacketType.EstateOwnerMessage, EstateOwnerMessageHandler); + Client.Network.RegisterCallback(PacketType.EstateCovenantReply, EstateCovenantReplyHandler); + + Client.Network.RegisterEventCallback("LandStatReply", new Caps.EventQueueCallback(LandStatCapsReplyHandler)); + } + + #region Enums + /// Used in the ReportType field of a LandStatRequest + public enum LandStatReportType + { + TopScripts = 0, + TopColliders = 1 + } + + /// Used by EstateOwnerMessage packets + public enum EstateAccessDelta : uint + { + BanUser = 64, + BanUserAllEstates = 66, + UnbanUser = 128, + UnbanUserAllEstates = 130, + AddManager = 256, + AddManagerAllEstates = 257, + RemoveManager = 512, + RemoveManagerAllEstates = 513, + AddUserAsAllowed = 4, + AddAllowedAllEstates = 6, + RemoveUserAsAllowed = 8, + RemoveUserAllowedAllEstates = 10, + AddGroupAsAllowed = 16, + AddGroupAllowedAllEstates = 18, + RemoveGroupAsAllowed = 32, + RemoveGroupAllowedAllEstates = 34 + } + + /// Used by EstateOwnerMessage packets + public enum EstateAccessReplyDelta : uint + { + AllowedUsers = 17, + AllowedGroups = 18, + EstateBans = 20, + EstateManagers = 24 + } + + /// + /// + /// + [Flags] + public enum EstateReturnFlags : uint + { + /// No flags set + None = 2, + /// Only return targets scripted objects + ReturnScripted = 6, + /// Only return targets objects if on others land + ReturnOnOthersLand = 3, + /// Returns target's scripted objects and objects on other parcels + ReturnScriptedAndOnOthers = 7 + } + #endregion + #region Structs + /// Ground texture settings for each corner of the region + // TODO: maybe move this class to the Simulator object and implement it there too + public struct GroundTextureSettings + { + public UUID Low; + public UUID MidLow; + public UUID MidHigh; + public UUID High; + } + + /// Used by GroundTextureHeightSettings + public struct GroundTextureHeight + { + public float Low; + public float High; + } + + /// The high and low texture thresholds for each corner of the sim + public struct GroundTextureHeightSettings + { + public GroundTextureHeight SW; + public GroundTextureHeight NW; + public GroundTextureHeight SE; + public GroundTextureHeight NE; + } + #endregion + + #region Event delegates, Raise Events + + /// The event subscribers. null if no subcribers + private EventHandler m_TopCollidersReply; + + /// Raises the TopCollidersReply event + /// A TopCollidersReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnTopCollidersReply(TopCollidersReplyEventArgs e) + { + EventHandler handler = m_TopCollidersReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TopCollidersReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler TopCollidersReply + { + add { lock (m_TopCollidersReply_Lock) { m_TopCollidersReply += value; } } + remove { lock (m_TopCollidersReply_Lock) { m_TopCollidersReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_TopScriptsReply; + + /// Raises the TopScriptsReply event + /// A TopScriptsReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnTopScriptsReply(TopScriptsReplyEventArgs e) + { + EventHandler handler = m_TopScriptsReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TopScriptsReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler TopScriptsReply + { + add { lock (m_TopScriptsReply_Lock) { m_TopScriptsReply += value; } } + remove { lock (m_TopScriptsReply_Lock) { m_TopScriptsReply -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateUsersReply; + + /// Raises the EstateUsersReply event + /// A EstateUsersReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateUsersReply(EstateUsersReplyEventArgs e) + { + EventHandler handler = m_EstateUsersReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateUsersReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateUsersReply + { + add { lock (m_EstateUsersReply_Lock) { m_EstateUsersReply += value; } } + remove { lock (m_EstateUsersReply_Lock) { m_EstateUsersReply -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateGroupsReply; + + /// Raises the EstateGroupsReply event + /// A EstateGroupsReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateGroupsReply(EstateGroupsReplyEventArgs e) + { + EventHandler handler = m_EstateGroupsReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateGroupsReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateGroupsReply + { + add { lock (m_EstateGroupsReply_Lock) { m_EstateGroupsReply += value; } } + remove { lock (m_EstateGroupsReply_Lock) { m_EstateGroupsReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateManagersReply; + + /// Raises the EstateManagersReply event + /// A EstateManagersReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateManagersReply(EstateManagersReplyEventArgs e) + { + EventHandler handler = m_EstateManagersReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateManagersReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateManagersReply + { + add { lock (m_EstateManagersReply_Lock) { m_EstateManagersReply += value; } } + remove { lock (m_EstateManagersReply_Lock) { m_EstateManagersReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateBansReply; + + /// Raises the EstateBansReply event + /// A EstateBansReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateBansReply(EstateBansReplyEventArgs e) + { + EventHandler handler = m_EstateBansReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateBansReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateBansReply + { + add { lock (m_EstateBansReply_Lock) { m_EstateBansReply += value; } } + remove { lock (m_EstateBansReply_Lock) { m_EstateBansReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateCovenantReply; + + /// Raises the EstateCovenantReply event + /// A EstateCovenantReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateCovenantReply(EstateCovenantReplyEventArgs e) + { + EventHandler handler = m_EstateCovenantReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateCovenantReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateCovenantReply + { + add { lock (m_EstateCovenantReply_Lock) { m_EstateCovenantReply += value; } } + remove { lock (m_EstateCovenantReply_Lock) { m_EstateCovenantReply -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateUpdateInfoReply; + + /// Raises the EstateUpdateInfoReply event + /// A EstateUpdateInfoReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateUpdateInfoReply(EstateUpdateInfoReplyEventArgs e) + { + EventHandler handler = m_EstateUpdateInfoReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateUpdateInfoReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateUpdateInfoReply + { + add { lock (m_EstateUpdateInfoReply_Lock) { m_EstateUpdateInfoReply += value; } } + remove { lock (m_EstateUpdateInfoReply_Lock) { m_EstateUpdateInfoReply -= value; } } + } + #endregion + + #region Public Methods + /// + /// Requests estate information such as top scripts and colliders + /// + /// + /// + /// + /// + public void LandStatRequest(int parcelLocalID, LandStatReportType reportType, uint requestFlags, string filter) + { + LandStatRequestPacket p = new LandStatRequestPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + p.RequestData.Filter = Utils.StringToBytes(filter); + p.RequestData.ParcelLocalID = parcelLocalID; + p.RequestData.ReportType = (uint)reportType; + p.RequestData.RequestFlags = requestFlags; + Client.Network.SendPacket(p); + } + + /// Requests estate settings, including estate manager and access/ban lists + public void RequestInfo() + { + EstateOwnerMessage("getinfo", ""); + } + + /// Requests the "Top Scripts" list for the current region + public void RequestTopScripts() + { + //EstateOwnerMessage("scripts", ""); + LandStatRequest(0, LandStatReportType.TopScripts, 0, ""); + } + + /// Requests the "Top Colliders" list for the current region + public void RequestTopColliders() + { + //EstateOwnerMessage("colliders", ""); + LandStatRequest(0, LandStatReportType.TopColliders, 0, ""); + } + + /// + /// Set several estate specific configuration variables + /// + /// The Height of the waterlevel over the entire estate. Defaults to 20 + /// The maximum height change allowed above the baked terrain. Defaults to 4 + /// The minimum height change allowed below the baked terrain. Defaults to -4 + /// true to use + /// if True forces the sun position to the position in SunPosition + /// The current position of the sun on the estate, or when FixedSun is true the static position + /// the sun will remain. 6.0 = Sunrise, 30.0 = Sunset + public void SetTerrainVariables(float WaterHeight, float TerrainRaiseLimit, + float TerrainLowerLimit, bool UseEstateSun, bool FixedSun, float SunPosition) + { + List simVariables = new List(); + simVariables.Add(WaterHeight.ToString(Utils.EnUsCulture)); + simVariables.Add(TerrainRaiseLimit.ToString(Utils.EnUsCulture)); + simVariables.Add(TerrainLowerLimit.ToString(Utils.EnUsCulture)); + simVariables.Add(UseEstateSun ? "Y" : "N"); + simVariables.Add(FixedSun ? "Y" : "N"); + simVariables.Add(SunPosition.ToString(Utils.EnUsCulture)); + simVariables.Add("Y"); //Not used? + simVariables.Add("N"); //Not used? + simVariables.Add("0.00"); //Also not used? + EstateOwnerMessage("setregionterrain", simVariables); + } + + /// + /// Request return of objects owned by specified avatar + /// + /// The Agents owning the primitives to return + /// specify the coverage and type of objects to be included in the return + /// true to perform return on entire estate + public void SimWideReturn(UUID Target, EstateReturnFlags flag, bool EstateWide) + { + if (EstateWide) + { + List param = new List(); + param.Add(flag.ToString()); + param.Add(Target.ToString()); + EstateOwnerMessage("estateobjectreturn", param); + } + else + { + SimWideDeletesPacket simDelete = new SimWideDeletesPacket(); + simDelete.AgentData.AgentID = Client.Self.AgentID; + simDelete.AgentData.SessionID = Client.Self.SessionID; + simDelete.DataBlock.TargetID = Target; + simDelete.DataBlock.Flags = (uint)flag; + Client.Network.SendPacket(simDelete); + } + } + + /// + /// + /// + public void EstateOwnerMessage(string method, string param) + { + List listParams = new List(); + listParams.Add(param); + EstateOwnerMessage(method, listParams); + } + + /// + /// Used for setting and retrieving various estate panel settings + /// + /// EstateOwnerMessage Method field + /// List of parameters to include + public void EstateOwnerMessage(string method, List listParams) + { + EstateOwnerMessagePacket estate = new EstateOwnerMessagePacket(); + estate.AgentData.AgentID = Client.Self.AgentID; + estate.AgentData.SessionID = Client.Self.SessionID; + estate.AgentData.TransactionID = UUID.Zero; + estate.MethodData.Invoice = UUID.Random(); + estate.MethodData.Method = Utils.StringToBytes(method); + estate.ParamList = new EstateOwnerMessagePacket.ParamListBlock[listParams.Count]; + for (int i = 0; i < listParams.Count; i++) + { + estate.ParamList[i] = new EstateOwnerMessagePacket.ParamListBlock(); + estate.ParamList[i].Parameter = Utils.StringToBytes(listParams[i]); + } + Client.Network.SendPacket((Packet)estate); + } + + /// + /// Kick an avatar from an estate + /// + /// Key of Agent to remove + public void KickUser(UUID userID) + { + EstateOwnerMessage("kickestate", userID.ToString()); + } + + /// + /// Ban an avatar from an estate + /// Key of Agent to remove + /// Ban user from this estate and all others owned by the estate owner + public void BanUser(UUID userID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.BanUserAllEstates : (uint)EstateAccessDelta.BanUser; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(userID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + + /// Unban an avatar from an estate + /// Key of Agent to remove + /// /// Unban user from this estate and all others owned by the estate owner + public void UnbanUser(UUID userID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.UnbanUserAllEstates : (uint)EstateAccessDelta.UnbanUser; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(userID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + + /// + /// Send a message dialog to everyone in an entire estate + /// + /// Message to send all users in the estate + public void EstateMessage(string message) + { + List listParams = new List(); + listParams.Add(Client.Self.FirstName + " " + Client.Self.LastName); + listParams.Add(message); + EstateOwnerMessage("instantmessage", listParams); + } + + /// + /// Send a message dialog to everyone in a simulator + /// + /// Message to send all users in the simulator + public void SimulatorMessage(string message) + { + List listParams = new List(); + listParams.Add("-1"); + listParams.Add("-1"); + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(Client.Self.FirstName + " " + Client.Self.LastName); + listParams.Add(message); + EstateOwnerMessage("simulatormessage", listParams); + } + + /// + /// Send an avatar back to their home location + /// + /// Key of avatar to send home + public void TeleportHomeUser(UUID pest) + { + List listParams = new List(); + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(pest.ToString()); + EstateOwnerMessage("teleporthomeuser", listParams); + } + + /// + /// Begin the region restart process + /// + public void RestartRegion() + { + EstateOwnerMessage("restart", "120"); + } + + /// + /// Cancels a region restart + /// + public void CancelRestart() + { + EstateOwnerMessage("restart", "-1"); + } + + /// Estate panel "Region" tab settings + public void SetRegionInfo(bool blockTerraform, bool blockFly, bool allowDamage, bool allowLandResell, bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus, bool mature) + { + List listParams = new List(); + if (blockTerraform) listParams.Add("Y"); else listParams.Add("N"); + if (blockFly) listParams.Add("Y"); else listParams.Add("N"); + if (allowDamage) listParams.Add("Y"); else listParams.Add("N"); + if (allowLandResell) listParams.Add("Y"); else listParams.Add("N"); + listParams.Add(agentLimit.ToString()); + listParams.Add(objectBonus.ToString()); + if (mature) listParams.Add("21"); else listParams.Add("13"); //FIXME - enumerate these settings + if (restrictPushing) listParams.Add("Y"); else listParams.Add("N"); + if (allowParcelJoinDivide) listParams.Add("Y"); else listParams.Add("N"); + EstateOwnerMessage("setregioninfo", listParams); + } + + /// Estate panel "Debug" tab settings + public void SetRegionDebug(bool disableScripts, bool disableCollisions, bool disablePhysics) + { + List listParams = new List(); + if (disableScripts) listParams.Add("Y"); else listParams.Add("N"); + if (disableCollisions) listParams.Add("Y"); else listParams.Add("N"); + if (disablePhysics) listParams.Add("Y"); else listParams.Add("N"); + EstateOwnerMessage("setregiondebug", listParams); + } + + /// Used for setting the region's terrain textures for its four height levels + /// + /// + /// + /// + public void SetRegionTerrain(UUID low, UUID midLow, UUID midHigh, UUID high) + { + List listParams = new List(); + listParams.Add("0 " + low.ToString()); + listParams.Add("1 " + midLow.ToString()); + listParams.Add("2 " + midHigh.ToString()); + listParams.Add("3 " + high.ToString()); + EstateOwnerMessage("texturedetail", listParams); + EstateOwnerMessage("texturecommit", ""); + } + + /// Used for setting sim terrain texture heights + public void SetRegionTerrainHeights(float lowSW, float highSW, float lowNW, float highNW, float lowSE, float highSE, float lowNE, float highNE) + { + List listParams = new List(); + listParams.Add("0 " + lowSW.ToString(Utils.EnUsCulture) + " " + highSW.ToString(Utils.EnUsCulture)); //SW low-high + listParams.Add("1 " + lowNW.ToString(Utils.EnUsCulture) + " " + highNW.ToString(Utils.EnUsCulture)); //NW low-high + listParams.Add("2 " + lowSE.ToString(Utils.EnUsCulture) + " " + highSE.ToString(Utils.EnUsCulture)); //SE low-high + listParams.Add("3 " + lowNE.ToString(Utils.EnUsCulture) + " " + highNE.ToString(Utils.EnUsCulture)); //NE low-high + EstateOwnerMessage("textureheights", listParams); + EstateOwnerMessage("texturecommit", ""); + } + + /// Requests the estate covenant + public void RequestCovenant() + { + EstateCovenantRequestPacket req = new EstateCovenantRequestPacket(); + req.AgentData.AgentID = Client.Self.AgentID; + req.AgentData.SessionID = Client.Self.SessionID; + Client.Network.SendPacket(req); + } + + /// + /// Upload a terrain RAW file + /// + /// A byte array containing the encoded terrain data + /// The name of the file being uploaded + /// The Id of the transfer request + public UUID UploadTerrain(byte[] fileData, string fileName) + { + AssetUpload upload = new AssetUpload(); + upload.AssetData = fileData; + upload.AssetType = AssetType.Unknown; + upload.Size = fileData.Length; + upload.ID = UUID.Random(); + + // Tell the library we have a pending file to upload + Client.Assets.SetPendingAssetUploadData(upload); + + // Create and populate a list with commands specific to uploading a raw terrain file + List paramList = new List(); + paramList.Add("upload filename"); + paramList.Add(fileName); + + // Tell the simulator we have a new raw file to upload + Client.Estate.EstateOwnerMessage("terrain", paramList); + + return upload.ID; + } + + /// + /// Teleports all users home in current Estate + /// + public void TeleportHomeAllUsers() + { + List Params = new List(); + Params.Add(Client.Self.AgentID.ToString()); + EstateOwnerMessage("teleporthomeallusers", Params); + } + + /// + /// Remove estate manager + /// Key of Agent to Remove + /// removes manager to this estate and all others owned by the estate owner + public void RemoveEstateManager(UUID userID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.RemoveManagerAllEstates : (uint)EstateAccessDelta.RemoveManager; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(userID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + + /// + /// Add estate manager + /// Key of Agent to Add + /// Add agent as manager to this estate and all others owned by the estate owner + public void AddEstateManager(UUID userID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.AddManagerAllEstates : (uint)EstateAccessDelta.AddManager; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(userID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + + /// + /// Add's an agent to the estate Allowed list + /// Key of Agent to Add + /// Add agent as an allowed reisdent to All estates if true + public void AddAllowedUser(UUID userID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.AddAllowedAllEstates : (uint)EstateAccessDelta.AddUserAsAllowed; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(userID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + + /// + /// Removes an agent from the estate Allowed list + /// Key of Agent to Remove + /// Removes agent as an allowed reisdent from All estates if true + public void RemoveAllowedUser(UUID userID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.RemoveUserAllowedAllEstates : (uint)EstateAccessDelta.RemoveUserAsAllowed; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(userID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + /// + /// + /// Add's a group to the estate Allowed list + /// Key of Group to Add + /// Add Group as an allowed group to All estates if true + public void AddAllowedGroup(UUID groupID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.AddGroupAllowedAllEstates : (uint)EstateAccessDelta.AddGroupAsAllowed; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(groupID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + /// + /// + /// Removes a group from the estate Allowed list + /// Key of Group to Remove + /// Removes Group as an allowed Group from All estates if true + public void RemoveAllowedGroup(UUID groupID, bool allEstates) + { + List listParams = new List(); + uint flag = allEstates ? (uint)EstateAccessDelta.RemoveGroupAllowedAllEstates : (uint)EstateAccessDelta.RemoveGroupAsAllowed; + listParams.Add(Client.Self.AgentID.ToString()); + listParams.Add(flag.ToString()); + listParams.Add(groupID.ToString()); + EstateOwnerMessage("estateaccessdelta", listParams); + } + #endregion + + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void EstateCovenantReplyHandler(object sender, PacketReceivedEventArgs e) + { + EstateCovenantReplyPacket reply = (EstateCovenantReplyPacket)e.Packet; + OnEstateCovenantReply(new EstateCovenantReplyEventArgs( + reply.Data.CovenantID, + reply.Data.CovenantTimestamp, + Utils.BytesToString(reply.Data.EstateName), + reply.Data.EstateOwnerID)); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void EstateOwnerMessageHandler(object sender, PacketReceivedEventArgs e) + { + EstateOwnerMessagePacket message = (EstateOwnerMessagePacket)e.Packet; + uint estateID; + string method = Utils.BytesToString(message.MethodData.Method); + //List parameters = new List(); + + if (method == "estateupdateinfo") + { + string estateName = Utils.BytesToString(message.ParamList[0].Parameter); + UUID estateOwner = new UUID(Utils.BytesToString(message.ParamList[1].Parameter)); + estateID = Utils.BytesToUInt(message.ParamList[2].Parameter); + /* + foreach (EstateOwnerMessagePacket.ParamListBlock param in message.ParamList) + { + parameters.Add(Utils.BytesToString(param.Parameter)); + } + */ + bool denyNoPaymentInfo; + if (Utils.BytesToUInt(message.ParamList[8].Parameter) == 0) denyNoPaymentInfo = true; + else denyNoPaymentInfo = false; + + OnEstateUpdateInfoReply(new EstateUpdateInfoReplyEventArgs(estateName, estateOwner, estateID, denyNoPaymentInfo)); + } + + else if (method == "setaccess") + { + int count; + estateID = Utils.BytesToUInt(message.ParamList[0].Parameter); + if (message.ParamList.Length > 1) + { + //param comes in as a string for some reason + uint param; + if (!uint.TryParse(Utils.BytesToString(message.ParamList[1].Parameter), out param)) return; + + EstateAccessReplyDelta accessType = (EstateAccessReplyDelta)param; + + switch (accessType) + { + case EstateAccessReplyDelta.EstateManagers: + //if (OnGetEstateManagers != null) + { + if (message.ParamList.Length > 5) + { + if (!int.TryParse(Utils.BytesToString(message.ParamList[5].Parameter), out count)) return; + List managers = new List(); + for (int i = 6; i < message.ParamList.Length; i++) + { + try + { + UUID managerID = new UUID(message.ParamList[i].Parameter, 0); + managers.Add(managerID); + } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + OnEstateManagersReply(new EstateManagersReplyEventArgs(estateID, count, managers)); + } + } + break; + + case EstateAccessReplyDelta.EstateBans: + //if (OnGetEstateBans != null) + { + if (message.ParamList.Length > 5) + { + if (!int.TryParse(Utils.BytesToString(message.ParamList[4].Parameter), out count)) return; + List bannedUsers = new List(); + for (int i = 6; i < message.ParamList.Length; i++) + { + try + { + UUID bannedID = new UUID(message.ParamList[i].Parameter, 0); + bannedUsers.Add(bannedID); + } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + OnEstateBansReply(new EstateBansReplyEventArgs(estateID, count, bannedUsers)); + } + } + break; + + case EstateAccessReplyDelta.AllowedUsers: + //if (OnGetAllowedUsers != null) + { + if (message.ParamList.Length > 5) + { + if (!int.TryParse(Utils.BytesToString(message.ParamList[2].Parameter), out count)) return; + List allowedUsers = new List(); + for (int i = 6; i < message.ParamList.Length; i++) + { + try + { + UUID allowedID = new UUID(message.ParamList[i].Parameter, 0); + allowedUsers.Add(allowedID); + } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + OnEstateUsersReply(new EstateUsersReplyEventArgs(estateID, count, allowedUsers)); + } + } + break; + + case EstateAccessReplyDelta.AllowedGroups: + //if (OnGetAllowedGroups != null) + { + if (message.ParamList.Length > 5) + { + if (!int.TryParse(Utils.BytesToString(message.ParamList[3].Parameter), out count)) return; + List allowedGroups = new List(); + for (int i = 6; i < message.ParamList.Length; i++) + { + try + { + UUID groupID = new UUID(message.ParamList[i].Parameter, 0); + allowedGroups.Add(groupID); + } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + OnEstateGroupsReply(new EstateGroupsReplyEventArgs(estateID, count, allowedGroups)); + } + } + break; + } + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void LandStatReplyHandler(object sender, PacketReceivedEventArgs e) + { + //if (OnLandStatReply != null || OnGetTopScripts != null || OnGetTopColliders != null) + //if (OnGetTopScripts != null || OnGetTopColliders != null) + { + LandStatReplyPacket p = (LandStatReplyPacket)e.Packet; + Dictionary Tasks = new Dictionary(); + + foreach (LandStatReplyPacket.ReportDataBlock rep in p.ReportData) + { + EstateTask task = new EstateTask(); + task.Position = new Vector3(rep.LocationX, rep.LocationY, rep.LocationZ); + task.Score = rep.Score; + task.TaskID = rep.TaskID; + task.TaskLocalID = rep.TaskLocalID; + task.TaskName = Utils.BytesToString(rep.TaskName); + task.OwnerName = Utils.BytesToString(rep.OwnerName); + Tasks.Add(task.TaskID, task); + } + + LandStatReportType type = (LandStatReportType)p.RequestData.ReportType; + + if (type == LandStatReportType.TopScripts) + { + OnTopScriptsReply(new TopScriptsReplyEventArgs((int)p.RequestData.TotalObjectCount, Tasks)); + } + else if (type == LandStatReportType.TopColliders) + { + OnTopCollidersReply(new TopCollidersReplyEventArgs((int) p.RequestData.TotalObjectCount, Tasks)); + } + + /* + if (OnGetTopColliders != null) + { + //FIXME - System.UnhandledExceptionEventArgs + OnLandStatReply( + type, + p.RequestData.RequestFlags, + (int)p.RequestData.TotalObjectCount, + Tasks + ); + } + */ + + } + } + + private void LandStatCapsReplyHandler(string capsKey, IMessage message, Simulator simulator) + { + LandStatReplyMessage m = (LandStatReplyMessage)message; + Dictionary Tasks = new Dictionary(); + + foreach (LandStatReplyMessage.ReportDataBlock rep in m.ReportDataBlocks) + { + EstateTask task = new EstateTask(); + task.Position = rep.Location; + task.Score = rep.Score; + task.MonoScore = rep.MonoScore; + task.TaskID = rep.TaskID; + task.TaskLocalID = rep.TaskLocalID; + task.TaskName = rep.TaskName; + task.OwnerName = rep.OwnerName; + Tasks.Add(task.TaskID, task); + } + + LandStatReportType type = (LandStatReportType)m.ReportType; + + if (type == LandStatReportType.TopScripts) + { + OnTopScriptsReply(new TopScriptsReplyEventArgs((int)m.TotalObjectCount, Tasks)); + } + else if (type == LandStatReportType.TopColliders) + { + OnTopCollidersReply(new TopCollidersReplyEventArgs((int)m.TotalObjectCount, Tasks)); + } + } + #endregion + } + #region EstateTools EventArgs Classes + + /// Raised on LandStatReply when the report type is for "top colliders" + public class TopCollidersReplyEventArgs : EventArgs + { + private readonly int m_objectCount; + private readonly Dictionary m_Tasks; + + /// + /// The number of returned items in LandStatReply + /// + public int ObjectCount { get { return m_objectCount; } } + /// + /// A Dictionary of Object UUIDs to tasks returned in LandStatReply + /// + public Dictionary Tasks { get { return m_Tasks; } } + + /// Construct a new instance of the TopCollidersReplyEventArgs class + /// The number of returned items in LandStatReply + /// Dictionary of Object UUIDs to tasks returned in LandStatReply + public TopCollidersReplyEventArgs(int objectCount, Dictionary tasks) + { + this.m_objectCount = objectCount; + this.m_Tasks = tasks; + } + } + + /// Raised on LandStatReply when the report type is for "top Scripts" + public class TopScriptsReplyEventArgs : EventArgs + { + private readonly int m_objectCount; + private readonly Dictionary m_Tasks; + + /// + /// The number of scripts returned in LandStatReply + /// + public int ObjectCount { get { return m_objectCount; } } + /// + /// A Dictionary of Object UUIDs to tasks returned in LandStatReply + /// + public Dictionary Tasks { get { return m_Tasks; } } + + /// Construct a new instance of the TopScriptsReplyEventArgs class + /// The number of returned items in LandStatReply + /// Dictionary of Object UUIDs to tasks returned in LandStatReply + public TopScriptsReplyEventArgs(int objectCount, Dictionary tasks) + { + this.m_objectCount = objectCount; + this.m_Tasks = tasks; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateBansReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_banned; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned itmes + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of Banned Users + /// + public List Banned { get { return m_banned; } } + + /// Construct a new instance of the EstateBansReplyEventArgs class + /// The estate's identifier on the grid + /// The number of returned items in LandStatReply + /// User UUIDs banned + public EstateBansReplyEventArgs(uint estateID, int count, List banned) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_banned = banned; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateUsersReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_allowedUsers; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned items + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of Allowed Users + /// + public List AllowedUsers { get { return m_allowedUsers; } } + + /// Construct a new instance of the EstateUsersReplyEventArgs class + /// The estate's identifier on the grid + /// The number of users + /// Allowed users UUIDs + public EstateUsersReplyEventArgs(uint estateID, int count, List allowedUsers) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_allowedUsers = allowedUsers; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateGroupsReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_allowedGroups; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned items + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of Allowed Groups + /// + public List AllowedGroups { get { return m_allowedGroups; } } + + /// Construct a new instance of the EstateGroupsReplyEventArgs class + /// The estate's identifier on the grid + /// The number of Groups + /// Allowed Groups UUIDs + public EstateGroupsReplyEventArgs(uint estateID, int count, List allowedGroups) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_allowedGroups = allowedGroups; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateManagersReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_Managers; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned items + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of the Estate's Managers + /// + public List Managers { get { return m_Managers; } } + + /// Construct a new instance of the EstateManagersReplyEventArgs class + /// The estate's identifier on the grid + /// The number of Managers + /// Managers UUIDs + public EstateManagersReplyEventArgs(uint estateID, int count, List managers) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_Managers = managers; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateCovenantReplyEventArgs : EventArgs + { + private readonly UUID m_covenantID; + private readonly long m_timestamp; + private readonly string m_estateName; + private readonly UUID m_estateOwnerID; + + /// + /// The Covenant + /// + public UUID CovenantID { get { return m_covenantID; } } + /// + /// The timestamp + /// + public long Timestamp { get { return m_timestamp; } } + /// + /// The Estate name + /// + public String EstateName { get { return m_estateName; } } + /// + /// The Estate Owner's ID (can be a GroupID) + /// + public UUID EstateOwnerID { get { return m_estateOwnerID; } } + + /// Construct a new instance of the EstateCovenantReplyEventArgs class + /// The Covenant ID + /// The timestamp + /// The estate's name + /// The Estate Owner's ID (can be a GroupID) + public EstateCovenantReplyEventArgs(UUID covenantID, long timestamp, string estateName, UUID estateOwnerID) + { + this.m_covenantID = covenantID; + this.m_timestamp = timestamp; + this.m_estateName = estateName; + this.m_estateOwnerID = estateOwnerID; + + } + } + + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateUpdateInfoReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly bool m_denyNoPaymentInfo; + private readonly string m_estateName; + private readonly UUID m_estateOwner; + + /// + /// The estate's name + /// + public String EstateName { get { return m_estateName; } } + /// + /// The Estate Owner's ID (can be a GroupID) + /// + public UUID EstateOwner { get { return m_estateOwner; } } + /// + /// The identifier of the estate on the grid + /// + public uint EstateID { get { return m_estateID; } } + /// + public bool DenyNoPaymentInfo { get { return m_denyNoPaymentInfo; } } + + /// Construct a new instance of the EstateUpdateInfoReplyEventArgs class + /// The estate's name + /// The Estate Owners ID (can be a GroupID) + /// The estate's identifier on the grid + /// + public EstateUpdateInfoReplyEventArgs(string estateName, UUID estateOwner, uint estateID, bool denyNoPaymentInfo) + { + this.m_estateName = estateName; + this.m_estateOwner = estateOwner; + this.m_estateID = estateID; + this.m_denyNoPaymentInfo = denyNoPaymentInfo; + + } + } + #endregion +} diff --git a/OpenMetaverse/EventDictionary.cs b/OpenMetaverse/EventDictionary.cs new file mode 100644 index 0000000..0d17073 --- /dev/null +++ b/OpenMetaverse/EventDictionary.cs @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using OpenMetaverse.Packets; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.Interfaces; + +namespace OpenMetaverse +{ + /// + /// Registers, unregisters, and fires events generated by incoming packets + /// + public class PacketEventDictionary + { + private sealed class PacketCallback + { + public EventHandler Callback; + public bool IsAsync; + + public PacketCallback(EventHandler callback, bool isAsync) + { + Callback = callback; + IsAsync = isAsync; + } + } + + /// + /// Object that is passed to worker threads in the ThreadPool for + /// firing packet callbacks + /// + private struct PacketCallbackWrapper + { + /// Callback to fire for this packet + public EventHandler Callback; + /// Reference to the simulator that this packet came from + public Simulator Simulator; + /// The packet that needs to be processed + public Packet Packet; + } + + /// Reference to the GridClient object + public GridClient Client; + + private Dictionary _EventTable = new Dictionary(); + + /// + /// Default constructor + /// + /// + public PacketEventDictionary(GridClient client) + { + Client = client; + } + + /// + /// Register an event handler + /// + /// Use PacketType.Default to fire this event on every + /// incoming packet + /// Packet type to register the handler for + /// Callback to be fired + /// True if this callback should be ran + /// asynchronously, false to run it synchronous + public void RegisterEvent(PacketType packetType, EventHandler eventHandler, bool isAsync) + { + lock (_EventTable) + { + PacketCallback callback; + if (_EventTable.TryGetValue(packetType, out callback)) + { + callback.Callback += eventHandler; + callback.IsAsync = callback.IsAsync || isAsync; + } + else + { + callback = new PacketCallback(eventHandler, isAsync); + _EventTable[packetType] = callback; + } + } + } + + /// + /// Unregister an event handler + /// + /// Packet type to unregister the handler for + /// Callback to be unregistered + public void UnregisterEvent(PacketType packetType, EventHandler eventHandler) + { + lock (_EventTable) + { + PacketCallback callback; + if (_EventTable.TryGetValue(packetType, out callback)) + { + callback.Callback -= eventHandler; + if (callback.Callback == null || callback.Callback.GetInvocationList().Length == 0) + _EventTable.Remove(packetType); + } + } + } + + /// + /// Fire the events registered for this packet type + /// + /// Incoming packet type + /// Incoming packet + /// Simulator this packet was received from + internal void RaiseEvent(PacketType packetType, Packet packet, Simulator simulator) + { + PacketCallback callback; + + // Default handler first, if one exists + if (_EventTable.TryGetValue(PacketType.Default, out callback) && callback.Callback != null) + { + if (callback.IsAsync) + { + PacketCallbackWrapper wrapper; + wrapper.Callback = callback.Callback; + wrapper.Packet = packet; + wrapper.Simulator = simulator; + WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); + } + else + { + try { callback.Callback(this, new PacketReceivedEventArgs(packet, simulator)); } + catch (Exception ex) + { + Logger.Log("Default packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); + } + } + } + + if (_EventTable.TryGetValue(packetType, out callback) && callback.Callback != null) + { + if (callback.IsAsync) + { + PacketCallbackWrapper wrapper; + wrapper.Callback = callback.Callback; + wrapper.Packet = packet; + wrapper.Simulator = simulator; + WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); + } + else + { + try { callback.Callback(this, new PacketReceivedEventArgs(packet, simulator)); } + catch (Exception ex) + { + Logger.Log("Packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); + } + } + + return; + } + + if (packetType != PacketType.Default && packetType != PacketType.PacketAck) + { + Logger.DebugLog("No handler registered for packet event " + packetType, Client); + } + } + + private void ThreadPoolDelegate(Object state) + { + PacketCallbackWrapper wrapper = (PacketCallbackWrapper)state; + + try + { + wrapper.Callback(this, new PacketReceivedEventArgs(wrapper.Packet, wrapper.Simulator)); + } + catch (Exception ex) + { + Logger.Log("Async Packet Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); + } + } + } + + /// + /// Registers, unregisters, and fires events generated by the Capabilities + /// event queue + /// + public class CapsEventDictionary + { + /// + /// Object that is passed to worker threads in the ThreadPool for + /// firing CAPS callbacks + /// + private struct CapsCallbackWrapper + { + /// Callback to fire for this packet + public Caps.EventQueueCallback Callback; + /// Name of the CAPS event + public string CapsEvent; + /// Strongly typed decoded data + public IMessage Message; + /// Reference to the simulator that generated this event + public Simulator Simulator; + } + + /// Reference to the GridClient object + public GridClient Client; + + private Dictionary _EventTable = + new Dictionary(); + private WaitCallback _ThreadPoolCallback; + + /// + /// Default constructor + /// + /// Reference to the GridClient object + public CapsEventDictionary(GridClient client) + { + Client = client; + _ThreadPoolCallback = new WaitCallback(ThreadPoolDelegate); + } + + /// + /// Register an new event handler for a capabilities event sent via the EventQueue + /// + /// Use String.Empty to fire this event on every CAPS event + /// Capability event name to register the + /// handler for + /// Callback to fire + public void RegisterEvent(string capsEvent, Caps.EventQueueCallback eventHandler) + { + // TODO: Should we add support for synchronous CAPS handlers? + lock (_EventTable) + { + if (_EventTable.ContainsKey(capsEvent)) + _EventTable[capsEvent] += eventHandler; + else + _EventTable[capsEvent] = eventHandler; + } + } + + /// + /// Unregister a previously registered capabilities handler + /// + /// Capability event name unregister the + /// handler for + /// Callback to unregister + public void UnregisterEvent(string capsEvent, Caps.EventQueueCallback eventHandler) + { + lock (_EventTable) + { + if (_EventTable.ContainsKey(capsEvent) && _EventTable[capsEvent] != null) + _EventTable[capsEvent] -= eventHandler; + } + } + + /// + /// Fire the events registered for this event type synchronously + /// + /// Capability name + /// Decoded event body + /// Reference to the simulator that + /// generated this event + internal void RaiseEvent(string capsEvent, IMessage message, Simulator simulator) + { + bool specialHandler = false; + Caps.EventQueueCallback callback; + + // Default handler first, if one exists + if (_EventTable.TryGetValue(capsEvent, out callback)) + { + if (callback != null) + { + try { callback(capsEvent, message, simulator); } + catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } + } + } + + // Explicit handler next + if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null) + { + try { callback(capsEvent, message, simulator); } + catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } + + specialHandler = true; + } + + if (!specialHandler) + Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client); + } + + /// + /// Fire the events registered for this event type asynchronously + /// + /// Capability name + /// Decoded event body + /// Reference to the simulator that + /// generated this event + internal void BeginRaiseEvent(string capsEvent, IMessage message, Simulator simulator) + { + bool specialHandler = false; + Caps.EventQueueCallback callback; + + // Default handler first, if one exists + if (_EventTable.TryGetValue(String.Empty, out callback)) + { + if (callback != null) + { + callback(capsEvent, message, simulator); +// CapsCallbackWrapper wrapper; +// wrapper.Callback = callback; +// wrapper.CapsEvent = capsEvent; +// wrapper.Message = message; +// wrapper.Simulator = simulator; +// WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); + } + } + + // Explicit handler next + if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null) + { + callback(capsEvent, message, simulator); + +// CapsCallbackWrapper wrapper; +// wrapper.Callback = callback; +// wrapper.CapsEvent = capsEvent; +// wrapper.Message = message; +// wrapper.Simulator = simulator; +// WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); + + specialHandler = true; + } + + if (!specialHandler) + Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client); + } + + private void ThreadPoolDelegate(Object state) + { + CapsCallbackWrapper wrapper = (CapsCallbackWrapper)state; + + try + { + wrapper.Callback(wrapper.CapsEvent, wrapper.Message, wrapper.Simulator); + } + catch (Exception ex) + { + Logger.Log("Async CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); + } + } + } +} diff --git a/OpenMetaverse/FriendsManager.cs b/OpenMetaverse/FriendsManager.cs new file mode 100644 index 0000000..32d978b --- /dev/null +++ b/OpenMetaverse/FriendsManager.cs @@ -0,0 +1,1076 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Text; +using System.Collections.Generic; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + /// + /// + /// + [Flags] + public enum FriendRights : int + { + /// The avatar has no rights + None = 0, + /// The avatar can see the online status of the target avatar + CanSeeOnline = 1, + /// The avatar can see the location of the target avatar on the map + CanSeeOnMap = 2, + /// The avatar can modify the ojects of the target avatar + CanModifyObjects = 4 + } + + /// + /// This class holds information about an avatar in the friends list. There are two ways + /// to interface to this class. The first is through the set of boolean properties. This is the typical + /// way clients of this class will use it. The second interface is through two bitflag properties, + /// TheirFriendsRights and MyFriendsRights + /// + public class FriendInfo + { + private UUID m_id; + private string m_name; + private bool m_isOnline; + private bool m_canSeeMeOnline; + private bool m_canSeeMeOnMap; + private bool m_canModifyMyObjects; + private bool m_canSeeThemOnline; + private bool m_canSeeThemOnMap; + private bool m_canModifyTheirObjects; + + #region Properties + + /// + /// System ID of the avatar + /// + public UUID UUID { get { return m_id; } } + + /// + /// full name of the avatar + /// + public string Name + { + get { return m_name; } + set { m_name = value; } + } + + /// + /// True if the avatar is online + /// + public bool IsOnline + { + get { return m_isOnline; } + set { m_isOnline = value; } + } + + /// + /// True if the friend can see if I am online + /// + public bool CanSeeMeOnline + { + get { return m_canSeeMeOnline; } + set + { + m_canSeeMeOnline = value; + + // if I can't see them online, then I can't see them on the map + if (!m_canSeeMeOnline) + m_canSeeMeOnMap = false; + } + } + + /// + /// True if the friend can see me on the map + /// + public bool CanSeeMeOnMap + { + get { return m_canSeeMeOnMap; } + set + { + // if I can't see them online, then I can't see them on the map + if (m_canSeeMeOnline) + m_canSeeMeOnMap = value; + } + } + + /// + /// True if the freind can modify my objects + /// + public bool CanModifyMyObjects + { + get { return m_canModifyMyObjects; } + set { m_canModifyMyObjects = value; } + } + + /// + /// True if I can see if my friend is online + /// + public bool CanSeeThemOnline { get { return m_canSeeThemOnline; } } + + /// + /// True if I can see if my friend is on the map + /// + public bool CanSeeThemOnMap { get { return m_canSeeThemOnMap; } } + + /// + /// True if I can modify my friend's objects + /// + public bool CanModifyTheirObjects { get { return m_canModifyTheirObjects; } } + + /// + /// My friend's rights represented as bitmapped flags + /// + public FriendRights TheirFriendRights + { + get + { + FriendRights results = FriendRights.None; + if (m_canSeeMeOnline) + results |= FriendRights.CanSeeOnline; + if (m_canSeeMeOnMap) + results |= FriendRights.CanSeeOnMap; + if (m_canModifyMyObjects) + results |= FriendRights.CanModifyObjects; + + return results; + } + set + { + m_canSeeMeOnline = (value & FriendRights.CanSeeOnline) != 0; + m_canSeeMeOnMap = (value & FriendRights.CanSeeOnMap) != 0; + m_canModifyMyObjects = (value & FriendRights.CanModifyObjects) != 0; + } + } + + /// + /// My rights represented as bitmapped flags + /// + public FriendRights MyFriendRights + { + get + { + FriendRights results = FriendRights.None; + if (m_canSeeThemOnline) + results |= FriendRights.CanSeeOnline; + if (m_canSeeThemOnMap) + results |= FriendRights.CanSeeOnMap; + if (m_canModifyTheirObjects) + results |= FriendRights.CanModifyObjects; + + return results; + } + set + { + m_canSeeThemOnline = (value & FriendRights.CanSeeOnline) != 0; + m_canSeeThemOnMap = (value & FriendRights.CanSeeOnMap) != 0; + m_canModifyTheirObjects = (value & FriendRights.CanModifyObjects) != 0; + } + } + + #endregion Properties + + /// + /// Used internally when building the initial list of friends at login time + /// + /// System ID of the avatar being prepesented + /// Rights the friend has to see you online and to modify your objects + /// Rights you have to see your friend online and to modify their objects + internal FriendInfo(UUID id, FriendRights theirRights, FriendRights myRights) + { + m_id = id; + m_canSeeMeOnline = (theirRights & FriendRights.CanSeeOnline) != 0; + m_canSeeMeOnMap = (theirRights & FriendRights.CanSeeOnMap) != 0; + m_canModifyMyObjects = (theirRights & FriendRights.CanModifyObjects) != 0; + + m_canSeeThemOnline = (myRights & FriendRights.CanSeeOnline) != 0; + m_canSeeThemOnMap = (myRights & FriendRights.CanSeeOnMap) != 0; + m_canModifyTheirObjects = (myRights & FriendRights.CanModifyObjects) != 0; + } + + /// + /// FriendInfo represented as a string + /// + /// A string reprentation of both my rights and my friends rights + public override string ToString() + { + if (!String.IsNullOrEmpty(m_name)) + return String.Format("{0} (Their Rights: {1}, My Rights: {2})", m_name, TheirFriendRights, + MyFriendRights); + else + return String.Format("{0} (Their Rights: {1}, My Rights: {2})", m_id, TheirFriendRights, + MyFriendRights); + } + } + + /// + /// This class is used to add and remove avatars from your friends list and to manage their permission. + /// + public class FriendsManager + { + #region Delegates + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendOnline; + + /// Raises the FriendOnline event + /// A FriendInfoEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendOnline(FriendInfoEventArgs e) + { + EventHandler handler = m_FriendOnline; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendOnlineLock = new object(); + + /// Raised when the simulator sends notification one of the members in our friends list comes online + public event EventHandler FriendOnline + { + add { lock (m_FriendOnlineLock) { m_FriendOnline += value; } } + remove { lock (m_FriendOnlineLock) { m_FriendOnline -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendOffline; + + /// Raises the FriendOffline event + /// A FriendInfoEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendOffline(FriendInfoEventArgs e) + { + EventHandler handler = m_FriendOffline; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendOfflineLock = new object(); + + /// Raised when the simulator sends notification one of the members in our friends list goes offline + public event EventHandler FriendOffline + { + add { lock (m_FriendOfflineLock) { m_FriendOffline += value; } } + remove { lock (m_FriendOfflineLock) { m_FriendOffline -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendRights; + + /// Raises the FriendRightsUpdate event + /// A FriendInfoEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendRights(FriendInfoEventArgs e) + { + EventHandler handler = m_FriendRights; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendRightsLock = new object(); + + /// Raised when the simulator sends notification one of the members in our friends list grants or revokes permissions + public event EventHandler FriendRightsUpdate + { + add { lock (m_FriendRightsLock) { m_FriendRights += value; } } + remove { lock (m_FriendRightsLock) { m_FriendRights -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendNames; + + /// Raises the FriendNames event + /// A FriendNamesEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendNames(FriendNamesEventArgs e) + { + EventHandler handler = m_FriendNames; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendNamesLock = new object(); + + /// Raised when the simulator sends us the names on our friends list + public event EventHandler FriendNames + { + add { lock (m_FriendNamesLock) { m_FriendNames += value; } } + remove { lock (m_FriendNamesLock) { m_FriendNames -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendshipOffered; + + /// Raises the FriendshipOffered event + /// A FriendshipOfferedEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendshipOffered(FriendshipOfferedEventArgs e) + { + EventHandler handler = m_FriendshipOffered; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendshipOfferedLock = new object(); + + /// Raised when the simulator sends notification another agent is offering us friendship + public event EventHandler FriendshipOffered + { + add { lock (m_FriendshipOfferedLock) { m_FriendshipOffered += value; } } + remove { lock (m_FriendshipOfferedLock) { m_FriendshipOffered -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendshipResponse; + + /// Raises the FriendshipResponse event + /// A FriendshipResponseEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendshipResponse(FriendshipResponseEventArgs e) + { + EventHandler handler = m_FriendshipResponse; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendshipResponseLock = new object(); + + /// Raised when a request we sent to friend another agent is accepted or declined + public event EventHandler FriendshipResponse + { + add { lock (m_FriendshipResponseLock) { m_FriendshipResponse += value; } } + remove { lock (m_FriendshipResponseLock) { m_FriendshipResponse -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendshipTerminated; + + /// Raises the FriendshipTerminated event + /// A FriendshipTerminatedEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendshipTerminated(FriendshipTerminatedEventArgs e) + { + EventHandler handler = m_FriendshipTerminated; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendshipTerminatedLock = new object(); + + /// Raised when the simulator sends notification one of the members in our friends list has terminated + /// our friendship + public event EventHandler FriendshipTerminated + { + add { lock (m_FriendshipTerminatedLock) { m_FriendshipTerminated += value; } } + remove { lock (m_FriendshipTerminatedLock) { m_FriendshipTerminated -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_FriendFound; + + /// Raises the FriendFoundReply event + /// A FriendFoundReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnFriendFoundReply(FriendFoundReplyEventArgs e) + { + EventHandler handler = m_FriendFound; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FriendFoundLock = new object(); + + /// Raised when the simulator sends the location of a friend we have + /// requested map location info for + public event EventHandler FriendFoundReply + { + add { lock (m_FriendFoundLock) { m_FriendFound += value; } } + remove { lock (m_FriendFoundLock) { m_FriendFound -= value; } } + } + + #endregion Delegates + + #region Events + + #endregion Events + + private GridClient Client; + /// + /// A dictionary of key/value pairs containing known friends of this avatar. + /// + /// The Key is the of the friend, the value is a + /// object that contains detailed information including permissions you have and have given to the friend + /// + public InternalDictionary FriendList = new InternalDictionary(); + + /// + /// A Dictionary of key/value pairs containing current pending frienship offers. + /// + /// The key is the of the avatar making the request, + /// the value is the of the request which is used to accept + /// or decline the friendship offer + /// + public InternalDictionary FriendRequests = new InternalDictionary(); + + /// + /// Internal constructor + /// + /// A reference to the GridClient Object + internal FriendsManager(GridClient client) + { + Client = client; + + Client.Network.LoginProgress += Network_OnConnect; + Client.Avatars.UUIDNameReply += new EventHandler(Avatars_OnAvatarNames); + Client.Self.IM += Self_IM; + + Client.Network.RegisterCallback(PacketType.OnlineNotification, OnlineNotificationHandler); + Client.Network.RegisterCallback(PacketType.OfflineNotification, OfflineNotificationHandler); + Client.Network.RegisterCallback(PacketType.ChangeUserRights, ChangeUserRightsHandler); + Client.Network.RegisterCallback(PacketType.TerminateFriendship, TerminateFriendshipHandler); + Client.Network.RegisterCallback(PacketType.FindAgent, OnFindAgentReplyHandler); + + Client.Network.RegisterLoginResponseCallback(new NetworkManager.LoginResponseCallback(Network_OnLoginResponse), + new string[] { "buddy-list" }); + } + + #region Public Methods + + /// + /// Accept a friendship request + /// + /// agentID of avatatar to form friendship with + /// imSessionID of the friendship request message + public void AcceptFriendship(UUID fromAgentID, UUID imSessionID) + { + UUID callingCardFolder = Client.Inventory.FindFolderForType(AssetType.CallingCard); + + AcceptFriendshipPacket request = new AcceptFriendshipPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.TransactionBlock.TransactionID = imSessionID; + request.FolderData = new AcceptFriendshipPacket.FolderDataBlock[1]; + request.FolderData[0] = new AcceptFriendshipPacket.FolderDataBlock(); + request.FolderData[0].FolderID = callingCardFolder; + + Client.Network.SendPacket(request); + + FriendInfo friend = new FriendInfo(fromAgentID, FriendRights.CanSeeOnline, + FriendRights.CanSeeOnline); + + if (!FriendList.ContainsKey(fromAgentID)) + FriendList.Add(friend.UUID, friend); + + if (FriendRequests.ContainsKey(fromAgentID)) + FriendRequests.Remove(fromAgentID); + + Client.Avatars.RequestAvatarName(fromAgentID); + } + + /// + /// Decline a friendship request + /// + /// of friend + /// imSessionID of the friendship request message + public void DeclineFriendship(UUID fromAgentID, UUID imSessionID) + { + DeclineFriendshipPacket request = new DeclineFriendshipPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.TransactionBlock.TransactionID = imSessionID; + Client.Network.SendPacket(request); + + if (FriendRequests.ContainsKey(fromAgentID)) + FriendRequests.Remove(fromAgentID); + } + + /// + /// Overload: Offer friendship to an avatar. + /// + /// System ID of the avatar you are offering friendship to + public void OfferFriendship(UUID agentID) + { + OfferFriendship(agentID, "Do ya wanna be my buddy?"); + } + + /// + /// Offer friendship to an avatar. + /// + /// System ID of the avatar you are offering friendship to + /// A message to send with the request + public void OfferFriendship(UUID agentID, string message) + { + Client.Self.InstantMessage(Client.Self.Name, + agentID, + message, + UUID.Random(), + InstantMessageDialog.FriendshipOffered, + InstantMessageOnline.Offline, + Client.Self.SimPosition, + Client.Network.CurrentSim.ID, + null); + } + + + /// + /// Terminate a friendship with an avatar + /// + /// System ID of the avatar you are terminating the friendship with + public void TerminateFriendship(UUID agentID) + { + if (FriendList.ContainsKey(agentID)) + { + TerminateFriendshipPacket request = new TerminateFriendshipPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.ExBlock.OtherID = agentID; + + Client.Network.SendPacket(request); + + if (FriendList.ContainsKey(agentID)) + FriendList.Remove(agentID); + } + } + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + private void TerminateFriendshipHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + TerminateFriendshipPacket itsOver = (TerminateFriendshipPacket)packet; + string name = String.Empty; + + if (FriendList.ContainsKey(itsOver.ExBlock.OtherID)) + { + name = FriendList[itsOver.ExBlock.OtherID].Name; + FriendList.Remove(itsOver.ExBlock.OtherID); + } + + if (m_FriendshipTerminated != null) + { + OnFriendshipTerminated(new FriendshipTerminatedEventArgs(itsOver.ExBlock.OtherID, name)); + } + } + + /// + /// Change the rights of a friend avatar. + /// + /// the of the friend + /// the new rights to give the friend + /// This method will implicitly set the rights to those passed in the rights parameter. + public void GrantRights(UUID friendID, FriendRights rights) + { + GrantUserRightsPacket request = new GrantUserRightsPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.Rights = new GrantUserRightsPacket.RightsBlock[1]; + request.Rights[0] = new GrantUserRightsPacket.RightsBlock(); + request.Rights[0].AgentRelated = friendID; + request.Rights[0].RelatedRights = (int)rights; + + Client.Network.SendPacket(request); + } + + /// + /// Use to map a friends location on the grid. + /// + /// Friends UUID to find + /// + public void MapFriend(UUID friendID) + { + FindAgentPacket stalk = new FindAgentPacket(); + stalk.AgentBlock.Hunter = Client.Self.AgentID; + stalk.AgentBlock.Prey = friendID; + stalk.AgentBlock.SpaceIP = 0; // Will be filled in by the simulator + stalk.LocationBlock = new FindAgentPacket.LocationBlockBlock[1]; + stalk.LocationBlock[0] = new FindAgentPacket.LocationBlockBlock(); + stalk.LocationBlock[0].GlobalX = 0.0; // Filled in by the simulator + stalk.LocationBlock[0].GlobalY = 0.0; + + Client.Network.SendPacket(stalk); + } + + /// + /// Use to track a friends movement on the grid + /// + /// Friends Key + public void TrackFriend(UUID friendID) + { + TrackAgentPacket stalk = new TrackAgentPacket(); + stalk.AgentData.AgentID = Client.Self.AgentID; + stalk.AgentData.SessionID = Client.Self.SessionID; + stalk.TargetData.PreyID = friendID; + + Client.Network.SendPacket(stalk); + } + + /// + /// Ask for a notification of friend's online status + /// + /// Friend's UUID + public void RequestOnlineNotification(UUID friendID) + { + GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = Client.Self.AgentID; + gmp.AgentData.SessionID = Client.Self.SessionID; + gmp.AgentData.TransactionID = UUID.Zero; + + gmp.MethodData.Method = Utils.StringToBytes("requestonlinenotification"); + gmp.MethodData.Invoice = UUID.Zero; + gmp.ParamList = new GenericMessagePacket.ParamListBlock[1]; + gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); + gmp.ParamList[0].Parameter = Utils.StringToBytes(friendID.ToString()); + + Client.Network.SendPacket(gmp); + } + + #endregion + + #region Internal events + + private void Network_OnConnect(object sender, LoginProgressEventArgs e) + { + if (e.Status != LoginStatus.Success) + { + return; + } + + List names = new List(); + + if (FriendList.Count > 0) + { + FriendList.ForEach( + delegate(KeyValuePair kvp) + { + if (String.IsNullOrEmpty(kvp.Value.Name)) + names.Add(kvp.Key); + } + ); + + Client.Avatars.RequestAvatarNames(names); + } + } + + + /// + /// This handles the asynchronous response of a RequestAvatarNames call. + /// + /// + /// names cooresponding to the the list of IDs sent the the RequestAvatarNames call. + private void Avatars_OnAvatarNames(object sender, UUIDNameReplyEventArgs e) + { + Dictionary newNames = new Dictionary(); + + foreach (KeyValuePair kvp in e.Names) + { + FriendInfo friend; + lock (FriendList.Dictionary) + { + if (FriendList.TryGetValue(kvp.Key, out friend)) + { + if (friend.Name == null) + newNames.Add(kvp.Key, e.Names[kvp.Key]); + + friend.Name = e.Names[kvp.Key]; + FriendList[kvp.Key] = friend; + } + } + } + + if (newNames.Count > 0 && m_FriendNames != null) + { + OnFriendNames(new FriendNamesEventArgs(newNames)); + } + } + #endregion + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void OnlineNotificationHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + if (packet.Type == PacketType.OnlineNotification) + { + OnlineNotificationPacket notification = ((OnlineNotificationPacket)packet); + + foreach (OnlineNotificationPacket.AgentBlockBlock block in notification.AgentBlock) + { + FriendInfo friend; + lock (FriendList.Dictionary) + { + if (!FriendList.ContainsKey(block.AgentID)) + { + friend = new FriendInfo(block.AgentID, FriendRights.CanSeeOnline, + FriendRights.CanSeeOnline); + FriendList.Add(block.AgentID, friend); + } + else + { + friend = FriendList[block.AgentID]; + } + } + + bool doNotify = !friend.IsOnline; + friend.IsOnline = true; + + if (m_FriendOnline != null && doNotify) + { + OnFriendOnline(new FriendInfoEventArgs(friend)); + } + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void OfflineNotificationHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + if (packet.Type == PacketType.OfflineNotification) + { + OfflineNotificationPacket notification = (OfflineNotificationPacket)packet; + + foreach (OfflineNotificationPacket.AgentBlockBlock block in notification.AgentBlock) + { + FriendInfo friend = new FriendInfo(block.AgentID, FriendRights.CanSeeOnline, FriendRights.CanSeeOnline); + + lock (FriendList.Dictionary) + { + if (!FriendList.Dictionary.ContainsKey(block.AgentID)) + FriendList.Dictionary[block.AgentID] = friend; + + friend = FriendList.Dictionary[block.AgentID]; + } + + friend.IsOnline = false; + + if (m_FriendOffline != null) + { + OnFriendOffline(new FriendInfoEventArgs(friend)); + } + } + } + } + + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + private void ChangeUserRightsHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + if (packet.Type == PacketType.ChangeUserRights) + { + FriendInfo friend; + ChangeUserRightsPacket rights = (ChangeUserRightsPacket)packet; + + foreach (ChangeUserRightsPacket.RightsBlock block in rights.Rights) + { + FriendRights newRights = (FriendRights)block.RelatedRights; + if (FriendList.TryGetValue(block.AgentRelated, out friend)) + { + friend.TheirFriendRights = newRights; + if (m_FriendRights != null) + { + OnFriendRights(new FriendInfoEventArgs(friend)); + } + } + else if (block.AgentRelated == Client.Self.AgentID) + { + if (FriendList.TryGetValue(rights.AgentData.AgentID, out friend)) + { + friend.MyFriendRights = newRights; + if (m_FriendRights != null) + { + OnFriendRights(new FriendInfoEventArgs(friend)); + } + } + } + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + public void OnFindAgentReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_FriendFound != null) + { + Packet packet = e.Packet; + FindAgentPacket reply = (FindAgentPacket)packet; + + float x, y; + UUID prey = reply.AgentBlock.Prey; + ulong regionHandle = Helpers.GlobalPosToRegionHandle((float)reply.LocationBlock[0].GlobalX, + (float)reply.LocationBlock[0].GlobalY, out x, out y); + Vector3 xyz = new Vector3(x, y, 0f); + + OnFriendFoundReply(new FriendFoundReplyEventArgs(prey, regionHandle, xyz)); + } + } + + #endregion + + private void Self_IM(object sender, InstantMessageEventArgs e) + { + if (e.IM.Dialog == InstantMessageDialog.FriendshipOffered) + { + if (m_FriendshipOffered != null) + { + if (FriendRequests.ContainsKey(e.IM.FromAgentID)) + FriendRequests[e.IM.FromAgentID] = e.IM.IMSessionID; + else + FriendRequests.Add(e.IM.FromAgentID, e.IM.IMSessionID); + + OnFriendshipOffered(new FriendshipOfferedEventArgs(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.IMSessionID)); + } + } + else if (e.IM.Dialog == InstantMessageDialog.FriendshipAccepted) + { + FriendInfo friend = new FriendInfo(e.IM.FromAgentID, FriendRights.CanSeeOnline, + FriendRights.CanSeeOnline); + friend.Name = e.IM.FromAgentName; + lock (FriendList.Dictionary) FriendList[friend.UUID] = friend; + + if (m_FriendshipResponse != null) + { + OnFriendshipResponse(new FriendshipResponseEventArgs(e.IM.FromAgentID, e.IM.FromAgentName, true)); + } + RequestOnlineNotification(e.IM.FromAgentID); + } + else if (e.IM.Dialog == InstantMessageDialog.FriendshipDeclined) + { + if (m_FriendshipResponse != null) + { + OnFriendshipResponse(new FriendshipResponseEventArgs(e.IM.FromAgentID, e.IM.FromAgentName, false)); + } + } + } + + /// + /// Populate FriendList with data from the login reply + /// + /// true if login was successful + /// true if login request is requiring a redirect + /// A string containing the response to the login request + /// A string containing the reason for the request + /// A object containing the decoded + /// reply from the login server + private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason, + LoginResponseData replyData) + { + int uuidLength = UUID.Zero.ToString().Length; + + if (loginSuccess && replyData.BuddyList != null) + { + foreach (BuddyListEntry buddy in replyData.BuddyList) + { + UUID bubid; + string id = buddy.buddy_id.Length > uuidLength ? buddy.buddy_id.Substring(0, uuidLength) : buddy.buddy_id; + if (UUID.TryParse(id, out bubid)) + { + lock (FriendList.Dictionary) + { + if (!FriendList.ContainsKey(bubid)) + { + FriendList[bubid] = new FriendInfo(bubid, + (FriendRights)buddy.buddy_rights_given, + (FriendRights)buddy.buddy_rights_has); + } + } + } + } + } + } + } + #region EventArgs + + /// Contains information on a member of our friends list + public class FriendInfoEventArgs : EventArgs + { + private readonly FriendInfo m_Friend; + + /// Get the FriendInfo + public FriendInfo Friend { get { return m_Friend; } } + + /// + /// Construct a new instance of the FriendInfoEventArgs class + /// + /// The FriendInfo + public FriendInfoEventArgs(FriendInfo friend) + { + this.m_Friend = friend; + } + } + + /// Contains Friend Names + public class FriendNamesEventArgs : EventArgs + { + private readonly Dictionary m_Names; + + /// A dictionary where the Key is the ID of the Agent, + /// and the Value is a string containing their name + public Dictionary Names { get { return m_Names; } } + + /// + /// Construct a new instance of the FriendNamesEventArgs class + /// + /// A dictionary where the Key is the ID of the Agent, + /// and the Value is a string containing their name + public FriendNamesEventArgs(Dictionary names) + { + this.m_Names = names; + } + } + + /// Sent when another agent requests a friendship with our agent + public class FriendshipOfferedEventArgs : EventArgs + { + private readonly UUID m_AgentID; + private readonly string m_AgentName; + private readonly UUID m_SessionID; + + /// Get the ID of the agent requesting friendship + public UUID AgentID { get { return m_AgentID; } } + /// Get the name of the agent requesting friendship + public string AgentName { get { return m_AgentName; } } + /// Get the ID of the session, used in accepting or declining the + /// friendship offer + public UUID SessionID { get { return m_SessionID; } } + + /// + /// Construct a new instance of the FriendshipOfferedEventArgs class + /// + /// The ID of the agent requesting friendship + /// The name of the agent requesting friendship + /// The ID of the session, used in accepting or declining the + /// friendship offer + public FriendshipOfferedEventArgs(UUID agentID, string agentName, UUID imSessionID) + { + this.m_AgentID = agentID; + this.m_AgentName = agentName; + this.m_SessionID = imSessionID; + } + } + + /// A response containing the results of our request to form a friendship with another agent + public class FriendshipResponseEventArgs : EventArgs + { + private readonly UUID m_AgentID; + private readonly string m_AgentName; + private readonly bool m_Accepted; + + /// Get the ID of the agent we requested a friendship with + public UUID AgentID { get { return m_AgentID; } } + /// Get the name of the agent we requested a friendship with + public string AgentName { get { return m_AgentName; } } + /// true if the agent accepted our friendship offer + public bool Accepted { get { return m_Accepted; } } + + /// + /// Construct a new instance of the FriendShipResponseEventArgs class + /// + /// The ID of the agent we requested a friendship with + /// The name of the agent we requested a friendship with + /// true if the agent accepted our friendship offer + public FriendshipResponseEventArgs(UUID agentID, string agentName, bool accepted) + { + this.m_AgentID = agentID; + this.m_AgentName = agentName; + this.m_Accepted = accepted; + } + } + + /// Contains data sent when a friend terminates a friendship with us + public class FriendshipTerminatedEventArgs : EventArgs + { + private readonly UUID m_AgentID; + private readonly string m_AgentName; + + /// Get the ID of the agent that terminated the friendship with us + public UUID AgentID { get { return m_AgentID; } } + /// Get the name of the agent that terminated the friendship with us + public string AgentName { get { return m_AgentName; } } + + /// + /// Construct a new instance of the FrindshipTerminatedEventArgs class + /// + /// The ID of the friend who terminated the friendship with us + /// The name of the friend who terminated the friendship with us + public FriendshipTerminatedEventArgs(UUID agentID, string agentName) + { + this.m_AgentID = agentID; + this.m_AgentName = agentName; + } + } + + /// + /// Data sent in response to a request which contains the information to allow us to map the friends location + /// + public class FriendFoundReplyEventArgs : EventArgs + { + private readonly UUID m_AgentID; + private readonly ulong m_RegionHandle; + private readonly Vector3 m_Location; + + /// Get the ID of the agent we have received location information for + public UUID AgentID { get { return m_AgentID; } } + /// Get the region handle where our mapped friend is located + public ulong RegionHandle { get { return m_RegionHandle; } } + /// Get the simulator local position where our friend is located + public Vector3 Location { get { return m_Location; } } + + /// + /// Construct a new instance of the FriendFoundReplyEventArgs class + /// + /// The ID of the agent we have requested location information for + /// The region handle where our friend is located + /// The simulator local position our friend is located + public FriendFoundReplyEventArgs(UUID agentID, ulong regionHandle, Vector3 location) + { + this.m_AgentID = agentID; + this.m_RegionHandle = regionHandle; + this.m_Location = location; + } + } + #endregion +} diff --git a/OpenMetaverse/GridClient.cs b/OpenMetaverse/GridClient.cs new file mode 100644 index 0000000..8b53a6c --- /dev/null +++ b/OpenMetaverse/GridClient.cs @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + /// + /// Main class to expose grid functionality to clients. All of the + /// classes needed for sending and receiving data are accessible through + /// this class. + /// + /// + /// + /// // Example minimum code required to instantiate class and + /// // connect to a simulator. + /// using System; + /// using System.Collections.Generic; + /// using System.Text; + /// using OpenMetaverse; + /// + /// namespace FirstBot + /// { + /// class Bot + /// { + /// public static GridClient Client; + /// static void Main(string[] args) + /// { + /// Client = new GridClient(); // instantiates the GridClient class + /// // to the global Client object + /// // Login to Simulator + /// Client.Network.Login("FirstName", "LastName", "Password", "FirstBot", "1.0"); + /// // Wait for a Keypress + /// Console.ReadLine(); + /// // Logout of simulator + /// Client.Network.Logout(); + /// } + /// } + /// } + /// + /// + public class GridClient + { + /// Networking subsystem + public NetworkManager Network; + /// Settings class including constant values and changeable + /// parameters for everything + public Settings Settings; + /// Parcel (subdivided simulator lots) subsystem + public ParcelManager Parcels; + /// Our own avatars subsystem + public AgentManager Self; + /// Other avatars subsystem + public AvatarManager Avatars; + /// Estate subsystem + public EstateTools Estate; + /// Friends list subsystem + public FriendsManager Friends; + /// Grid (aka simulator group) subsystem + public GridManager Grid; + /// Object subsystem + public ObjectManager Objects; + /// Group subsystem + public GroupManager Groups; + /// Asset subsystem + public AssetManager Assets; + /// Appearance subsystem + public AppearanceManager Appearance; + /// Inventory subsystem + public InventoryManager Inventory; + /// Directory searches including classifieds, people, land + /// sales, etc + public DirectoryManager Directory; + /// Handles land, wind, and cloud heightmaps + public TerrainManager Terrain; + /// Handles sound-related networking + public SoundManager Sound; + /// Throttling total bandwidth usage, or allocating bandwidth + /// for specific data stream types + public AgentThrottle Throttle; + + public Stats.UtilizationStatistics Stats; + /// + /// Default constructor + /// + public GridClient() + { + // Initialise SmartThreadPool when using mono + if (Type.GetType("Mono.Runtime") != null) + { + WorkPool.Init(true); + } + + // These are order-dependant + Network = new NetworkManager(this); + Settings = new Settings(this); + Parcels = new ParcelManager(this); + Self = new AgentManager(this); + Avatars = new AvatarManager(this); + Estate = new EstateTools(this); + Friends = new FriendsManager(this); + Grid = new GridManager(this); + Objects = new ObjectManager(this); + Groups = new GroupManager(this); + Assets = new AssetManager(this); + Appearance = new AppearanceManager(this); + Inventory = new InventoryManager(this); + Directory = new DirectoryManager(this); + Terrain = new TerrainManager(this); + Sound = new SoundManager(this); + Throttle = new AgentThrottle(this); + Stats = new OpenMetaverse.Stats.UtilizationStatistics(); + } + + /// + /// Return the full name of this instance + /// + /// Client avatars full name + public override string ToString() + { + return Self.Name; + } + } +} diff --git a/OpenMetaverse/GridManager.cs b/OpenMetaverse/GridManager.cs new file mode 100644 index 0000000..4c66fdd --- /dev/null +++ b/OpenMetaverse/GridManager.cs @@ -0,0 +1,933 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// Map layer request type + /// + public enum GridLayerType : uint + { + /// Objects and terrain are shown + Objects = 0, + /// Only the terrain is shown, no objects + Terrain = 1, + /// Overlay showing land for sale and for auction + LandForSale = 2 + } + + /// + /// Type of grid item, such as telehub, event, populator location, etc. + /// + public enum GridItemType : uint + { + /// Telehub + Telehub = 1, + /// PG rated event + PgEvent = 2, + /// Mature rated event + MatureEvent = 3, + /// Popular location + Popular = 4, + /// Locations of avatar groups in a region + AgentLocations = 6, + /// Land for sale + LandForSale = 7, + /// Classified ad + Classified = 8, + /// Adult rated event + AdultEvent = 9, + /// Adult land for sale + AdultLandForSale = 10 + } + + #endregion Enums + + #region Structs + + /// + /// Information about a region on the grid map + /// + public struct GridRegion + { + /// Sim X position on World Map + public int X; + /// Sim Y position on World Map + public int Y; + /// Sim Name (NOTE: In lowercase!) + public string Name; + /// + public SimAccess Access; + /// Appears to always be zero (None) + public RegionFlags RegionFlags; + /// Sim's defined Water Height + public byte WaterHeight; + /// + public byte Agents; + /// UUID of the World Map image + public UUID MapImageID; + /// Unique identifier for this region, a combination of the X + /// and Y position + public ulong RegionHandle; + + + /// + /// + /// + /// + public override string ToString() + { + return String.Format("{0} ({1}/{2}), Handle: {3}, MapImage: {4}, Access: {5}, Flags: {6}", + Name, X, Y, RegionHandle, MapImageID, Access, RegionFlags); + } + + /// + /// + /// + /// + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + + /// + /// + /// + /// + /// + public override bool Equals(object obj) + { + if (obj is GridRegion) + return Equals((GridRegion)obj); + else + return false; + } + + private bool Equals(GridRegion region) + { + return (this.X == region.X && this.Y == region.Y); + } + } + + /// + /// Visual chunk of the grid map + /// + public struct GridLayer + { + public int Bottom; + public int Left; + public int Top; + public int Right; + public UUID ImageID; + + public bool ContainsRegion(int x, int y) + { + return (x >= Left && x <= Right && y >= Bottom && y <= Top); + } + } + + #endregion Structs + + #region Map Item Classes + + /// + /// Base class for Map Items + /// + public abstract class MapItem + { + /// The Global X position of the item + public uint GlobalX; + /// The Global Y position of the item + public uint GlobalY; + + /// Get the Local X position of the item + public uint LocalX { get { return GlobalX % 256; } } + /// Get the Local Y position of the item + public uint LocalY { get { return GlobalY % 256; } } + + /// Get the Handle of the region + public ulong RegionHandle + { + get { return Utils.UIntsToLong((uint)(GlobalX - (GlobalX % 256)), (uint)(GlobalY - (GlobalY % 256))); } + } + } + + /// + /// Represents an agent or group of agents location + /// + public class MapAgentLocation : MapItem + { + public int AvatarCount; + public string Identifier; + } + + /// + /// Represents a Telehub location + /// + public class MapTelehub : MapItem + { + } + + /// + /// Represents a non-adult parcel of land for sale + /// + public class MapLandForSale : MapItem + { + public int Size; + public int Price; + public string Name; + public UUID ID; + } + + /// + /// Represents an Adult parcel of land for sale + /// + public class MapAdultLandForSale : MapItem + { + public int Size; + public int Price; + public string Name; + public UUID ID; + } + + /// + /// Represents a PG Event + /// + public class MapPGEvent : MapItem + { + public DirectoryManager.EventFlags Flags; // Extra + public DirectoryManager.EventCategories Category; // Extra2 + public string Description; + } + + /// + /// Represents a Mature event + /// + public class MapMatureEvent : MapItem + { + public DirectoryManager.EventFlags Flags; // Extra + public DirectoryManager.EventCategories Category; // Extra2 + public string Description; + } + + /// + /// Represents an Adult event + /// + public class MapAdultEvent : MapItem + { + public DirectoryManager.EventFlags Flags; // Extra + public DirectoryManager.EventCategories Category; // Extra2 + public string Description; + } + #endregion Grid Item Classes + + /// + /// Manages grid-wide tasks such as the world map + /// + public class GridManager + { + #region Delegates + + /// The event subscribers. null if no subcribers + private EventHandler m_CoarseLocationUpdate; + + /// Raises the CoarseLocationUpdate event + /// A CoarseLocationUpdateEventArgs object containing the + /// data sent by simulator + protected virtual void OnCoarseLocationUpdate(CoarseLocationUpdateEventArgs e) + { + EventHandler handler = m_CoarseLocationUpdate; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_CoarseLocationUpdateLock = new object(); + + /// Raised when the simulator sends a + /// containing the location of agents in the simulator + public event EventHandler CoarseLocationUpdate + { + add { lock (m_CoarseLocationUpdateLock) { m_CoarseLocationUpdate += value; } } + remove { lock (m_CoarseLocationUpdateLock) { m_CoarseLocationUpdate -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GridRegion; + + /// Raises the GridRegion event + /// A GridRegionEventArgs object containing the + /// data sent by simulator + protected virtual void OnGridRegion(GridRegionEventArgs e) + { + EventHandler handler = m_GridRegion; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GridRegionLock = new object(); + + /// Raised when the simulator sends a Region Data in response to + /// a Map request + public event EventHandler GridRegion + { + add { lock (m_GridRegionLock) { m_GridRegion += value; } } + remove { lock (m_GridRegionLock) { m_GridRegion -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GridLayer; + + /// Raises the GridLayer event + /// A GridLayerEventArgs object containing the + /// data sent by simulator + protected virtual void OnGridLayer(GridLayerEventArgs e) + { + EventHandler handler = m_GridLayer; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GridLayerLock = new object(); + + /// Raised when the simulator sends GridLayer object containing + /// a map tile coordinates and texture information + public event EventHandler GridLayer + { + add { lock (m_GridLayerLock) { m_GridLayer += value; } } + remove { lock (m_GridLayerLock) { m_GridLayer -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GridItems; + + /// Raises the GridItems event + /// A GridItemEventArgs object containing the + /// data sent by simulator + protected virtual void OnGridItems(GridItemsEventArgs e) + { + EventHandler handler = m_GridItems; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GridItemsLock = new object(); + + /// Raised when the simulator sends GridItems object containing + /// details on events, land sales at a specific location + public event EventHandler GridItems + { + add { lock (m_GridItemsLock) { m_GridItems += value; } } + remove { lock (m_GridItemsLock) { m_GridItems -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_RegionHandleReply; + + /// Raises the RegionHandleReply event + /// A RegionHandleReplyEventArgs object containing the + /// data sent by simulator + protected virtual void OnRegionHandleReply(RegionHandleReplyEventArgs e) + { + EventHandler handler = m_RegionHandleReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_RegionHandleReplyLock = new object(); + + /// Raised in response to a Region lookup + public event EventHandler RegionHandleReply + { + add { lock (m_RegionHandleReplyLock) { m_RegionHandleReply += value; } } + remove { lock (m_RegionHandleReplyLock) { m_RegionHandleReply -= value; } } + } + + #endregion Delegates + + /// Unknown + public float SunPhase { get { return sunPhase; } } + /// Current direction of the sun + public Vector3 SunDirection { get { return sunDirection; } } + /// Current angular velocity of the sun + public Vector3 SunAngVelocity { get { return sunAngVelocity; } } + /// Microseconds since the start of SL 4-hour day + public ulong TimeOfDay { get { return timeOfDay; } } + + /// A dictionary of all the regions, indexed by region name + internal Dictionary Regions = new Dictionary(); + /// A dictionary of all the regions, indexed by region handle + internal Dictionary RegionsByHandle = new Dictionary(); + + private GridClient Client; + private float sunPhase; + private Vector3 sunDirection; + private Vector3 sunAngVelocity; + private ulong timeOfDay; + + /// + /// Constructor + /// + /// Instance of GridClient object to associate with this GridManager instance + public GridManager(GridClient client) + { + Client = client; + + //Client.Network.RegisterCallback(PacketType.MapLayerReply, MapLayerReplyHandler); + Client.Network.RegisterCallback(PacketType.MapBlockReply, MapBlockReplyHandler); + Client.Network.RegisterCallback(PacketType.MapItemReply, MapItemReplyHandler); + Client.Network.RegisterCallback(PacketType.SimulatorViewerTimeMessage, SimulatorViewerTimeMessageHandler); + Client.Network.RegisterCallback(PacketType.CoarseLocationUpdate, CoarseLocationHandler, false); + Client.Network.RegisterCallback(PacketType.RegionIDAndHandleReply, RegionHandleReplyHandler); + } + + /// + /// + /// + /// + public void RequestMapLayer(GridLayerType layer) + { + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("MapLayer"); + + if (url != null) + { + OSDMap body = new OSDMap(); + body["Flags"] = OSD.FromInteger((int)layer); + + CapsClient request = new CapsClient(url); + request.OnComplete += new CapsClient.CompleteCallback(MapLayerResponseHandler); + request.BeginGetResponse(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + } + + /// + /// Request a map layer + /// + /// The name of the region + /// The type of layer + public void RequestMapRegion(string regionName, GridLayerType layer) + { + MapNameRequestPacket request = new MapNameRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.AgentData.Flags = (uint)layer; + request.AgentData.EstateID = 0; // Filled in on the sim + request.AgentData.Godlike = false; // Filled in on the sim + request.NameData.Name = Utils.StringToBytes(regionName); + + Client.Network.SendPacket(request); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void RequestMapBlocks(GridLayerType layer, ushort minX, ushort minY, ushort maxX, ushort maxY, + bool returnNonExistent) + { + MapBlockRequestPacket request = new MapBlockRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.AgentData.Flags = (uint)layer; + request.AgentData.Flags |= (uint)(returnNonExistent ? 0x10000 : 0); + request.AgentData.EstateID = 0; // Filled in at the simulator + request.AgentData.Godlike = false; // Filled in at the simulator + + request.PositionData.MinX = minX; + request.PositionData.MinY = minY; + request.PositionData.MaxX = maxX; + request.PositionData.MaxY = maxY; + + Client.Network.SendPacket(request); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public List MapItems(ulong regionHandle, GridItemType item, GridLayerType layer, int timeoutMS) + { + List itemList = null; + AutoResetEvent itemsEvent = new AutoResetEvent(false); + + EventHandler callback = + delegate(object sender, GridItemsEventArgs e) + { + if (e.Type == GridItemType.AgentLocations) + { + itemList = e.Items; + itemsEvent.Set(); + } + }; + + GridItems += callback; + + RequestMapItems(regionHandle, item, layer); + itemsEvent.WaitOne(timeoutMS, false); + + GridItems -= callback; + + return itemList; + } + + /// + /// + /// + /// + /// + /// + public void RequestMapItems(ulong regionHandle, GridItemType item, GridLayerType layer) + { + MapItemRequestPacket request = new MapItemRequestPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.AgentData.Flags = (uint)layer; + request.AgentData.Godlike = false; // Filled in on the sim + request.AgentData.EstateID = 0; // Filled in on the sim + + request.RequestData.ItemType = (uint)item; + request.RequestData.RegionHandle = regionHandle; + + Client.Network.SendPacket(request); + } + + /// + /// Request data for all mainland (Linden managed) simulators + /// + public void RequestMainlandSims(GridLayerType layer) + { + RequestMapBlocks(layer, 0, 0, 65535, 65535, false); + } + + /// + /// Request the region handle for the specified region UUID + /// + /// UUID of the region to look up + public void RequestRegionHandle(UUID regionID) + { + RegionHandleRequestPacket request = new RegionHandleRequestPacket(); + request.RequestBlock = new RegionHandleRequestPacket.RequestBlockBlock(); + request.RequestBlock.RegionID = regionID; + Client.Network.SendPacket(request); + } + + /// + /// Get grid region information using the region name, this function + /// will block until it can find the region or gives up + /// + /// Name of sim you're looking for + /// Layer that you are requesting + /// Will contain a GridRegion for the sim you're + /// looking for if successful, otherwise an empty structure + /// True if the GridRegion was successfully fetched, otherwise + /// false + public bool GetGridRegion(string name, GridLayerType layer, out GridRegion region) + { + if (String.IsNullOrEmpty(name)) + { + Logger.Log("GetGridRegion called with a null or empty region name", Helpers.LogLevel.Error, Client); + region = new GridRegion(); + return false; + } + + if (Regions.ContainsKey(name)) + { + // We already have this GridRegion structure + region = Regions[name]; + return true; + } + else + { + AutoResetEvent regionEvent = new AutoResetEvent(false); + EventHandler callback = + delegate(object sender, GridRegionEventArgs e) + { + if (e.Region.Name == name) + regionEvent.Set(); + }; + GridRegion += callback; + + RequestMapRegion(name, layer); + regionEvent.WaitOne(Client.Settings.MAP_REQUEST_TIMEOUT, false); + + GridRegion -= callback; + + if (Regions.ContainsKey(name)) + { + // The region was found after our request + region = Regions[name]; + return true; + } + else + { + Logger.Log("Couldn't find region " + name, Helpers.LogLevel.Warning, Client); + region = new GridRegion(); + return false; + } + } + } + + protected void MapLayerResponseHandler(CapsClient client, OSD result, Exception error) + { + if (result == null) + { + Logger.Log("MapLayerResponseHandler error: " + error.Message + ": " + error.StackTrace, Helpers.LogLevel.Error, Client); + return; + } + OSDMap body = (OSDMap)result; + OSDArray layerData = (OSDArray)body["LayerData"]; + + if (m_GridLayer != null) + { + for (int i = 0; i < layerData.Count; i++) + { + OSDMap thisLayerData = (OSDMap)layerData[i]; + + GridLayer layer; + layer.Bottom = thisLayerData["Bottom"].AsInteger(); + layer.Left = thisLayerData["Left"].AsInteger(); + layer.Top = thisLayerData["Top"].AsInteger(); + layer.Right = thisLayerData["Right"].AsInteger(); + layer.ImageID = thisLayerData["ImageID"].AsUUID(); + + OnGridLayer(new GridLayerEventArgs(layer)); + } + } + + if (body.ContainsKey("MapBlocks")) + { + // TODO: At one point this will become activated + Logger.Log("Got MapBlocks through CAPS, please finish this function!", Helpers.LogLevel.Error, Client); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void MapBlockReplyHandler(object sender, PacketReceivedEventArgs e) + { + MapBlockReplyPacket map = (MapBlockReplyPacket)e.Packet; + + foreach (MapBlockReplyPacket.DataBlock block in map.Data) + { + if (block.X != 0 || block.Y != 0) + { + GridRegion region; + + region.X = block.X; + region.Y = block.Y; + region.Name = Utils.BytesToString(block.Name); + // RegionFlags seems to always be zero here? + region.RegionFlags = (RegionFlags)block.RegionFlags; + region.WaterHeight = block.WaterHeight; + region.Agents = block.Agents; + region.Access = (SimAccess)block.Access; + region.MapImageID = block.MapImageID; + region.RegionHandle = Utils.UIntsToLong((uint)(region.X * 256), (uint)(region.Y * 256)); + + lock (Regions) + { + Regions[region.Name] = region; + RegionsByHandle[region.RegionHandle] = region; + } + + if (m_GridRegion != null) + { + OnGridRegion(new GridRegionEventArgs(region)); + } + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void MapItemReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GridItems != null) + { + MapItemReplyPacket reply = (MapItemReplyPacket)e.Packet; + GridItemType type = (GridItemType)reply.RequestData.ItemType; + List items = new List(); + + for (int i = 0; i < reply.Data.Length; i++) + { + string name = Utils.BytesToString(reply.Data[i].Name); + + switch (type) + { + case GridItemType.AgentLocations: + MapAgentLocation location = new MapAgentLocation(); + location.GlobalX = reply.Data[i].X; + location.GlobalY = reply.Data[i].Y; + location.Identifier = name; + location.AvatarCount = reply.Data[i].Extra; + items.Add(location); + break; + case GridItemType.Classified: + //FIXME: + Logger.Log("FIXME", Helpers.LogLevel.Error, Client); + break; + case GridItemType.LandForSale: + MapLandForSale landsale = new MapLandForSale(); + landsale.GlobalX = reply.Data[i].X; + landsale.GlobalY = reply.Data[i].Y; + landsale.ID = reply.Data[i].ID; + landsale.Name = name; + landsale.Size = reply.Data[i].Extra; + landsale.Price = reply.Data[i].Extra2; + items.Add(landsale); + break; + case GridItemType.MatureEvent: + MapMatureEvent matureEvent = new MapMatureEvent(); + matureEvent.GlobalX = reply.Data[i].X; + matureEvent.GlobalY = reply.Data[i].Y; + matureEvent.Description = name; + matureEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2; + items.Add(matureEvent); + break; + case GridItemType.PgEvent: + MapPGEvent PGEvent = new MapPGEvent(); + PGEvent.GlobalX = reply.Data[i].X; + PGEvent.GlobalY = reply.Data[i].Y; + PGEvent.Description = name; + PGEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2; + items.Add(PGEvent); + break; + case GridItemType.Popular: + //FIXME: + Logger.Log("FIXME", Helpers.LogLevel.Error, Client); + break; + case GridItemType.Telehub: + MapTelehub teleHubItem = new MapTelehub(); + teleHubItem.GlobalX = reply.Data[i].X; + teleHubItem.GlobalY = reply.Data[i].Y; + items.Add(teleHubItem); + break; + case GridItemType.AdultLandForSale: + MapAdultLandForSale adultLandsale = new MapAdultLandForSale(); + adultLandsale.GlobalX = reply.Data[i].X; + adultLandsale.GlobalY = reply.Data[i].Y; + adultLandsale.ID = reply.Data[i].ID; + adultLandsale.Name = name; + adultLandsale.Size = reply.Data[i].Extra; + adultLandsale.Price = reply.Data[i].Extra2; + items.Add(adultLandsale); + break; + case GridItemType.AdultEvent: + MapAdultEvent adultEvent = new MapAdultEvent(); + adultEvent.GlobalX = reply.Data[i].X; + adultEvent.GlobalY = reply.Data[i].Y; + adultEvent.Description = Utils.BytesToString(reply.Data[i].Name); + adultEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2; + items.Add(adultEvent); + break; + default: + Logger.Log("Unknown map item type " + type, Helpers.LogLevel.Warning, Client); + break; + } + } + + OnGridItems(new GridItemsEventArgs(type, items)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void SimulatorViewerTimeMessageHandler(object sender, PacketReceivedEventArgs e) + { + SimulatorViewerTimeMessagePacket time = (SimulatorViewerTimeMessagePacket)e.Packet; + + sunPhase = time.TimeInfo.SunPhase; + sunDirection = time.TimeInfo.SunDirection; + sunAngVelocity = time.TimeInfo.SunAngVelocity; + timeOfDay = time.TimeInfo.UsecSinceStart; + // TODO: Does anyone have a use for the time stuff? + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void CoarseLocationHandler(object sender, PacketReceivedEventArgs e) + { + CoarseLocationUpdatePacket coarse = (CoarseLocationUpdatePacket)e.Packet; + + // populate a dictionary from the packet, for local use + Dictionary coarseEntries = new Dictionary(); + for (int i = 0; i < coarse.AgentData.Length; i++) + { + if(coarse.Location.Length > 0) + coarseEntries[coarse.AgentData[i].AgentID] = new Vector3((int)coarse.Location[i].X, (int)coarse.Location[i].Y, (int)coarse.Location[i].Z * 4); + + // the friend we are tracking on radar + if (i == coarse.Index.Prey) + e.Simulator.preyID = coarse.AgentData[i].AgentID; + } + + // find stale entries (people who left the sim) + List removedEntries = e.Simulator.avatarPositions.FindAll(delegate(UUID findID) { return !coarseEntries.ContainsKey(findID); }); + + // anyone who was not listed in the previous update + List newEntries = new List(); + + lock (e.Simulator.avatarPositions.Dictionary) + { + // remove stale entries + foreach(UUID trackedID in removedEntries) + e.Simulator.avatarPositions.Dictionary.Remove(trackedID); + + // add or update tracked info, and record who is new + foreach (KeyValuePair entry in coarseEntries) + { + if (!e.Simulator.avatarPositions.Dictionary.ContainsKey(entry.Key)) + newEntries.Add(entry.Key); + + e.Simulator.avatarPositions.Dictionary[entry.Key] = entry.Value; + } + } + + if (m_CoarseLocationUpdate != null) + { + WorkPool.QueueUserWorkItem(delegate(object o) + { OnCoarseLocationUpdate(new CoarseLocationUpdateEventArgs(e.Simulator, newEntries, removedEntries)); }); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void RegionHandleReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_RegionHandleReply != null) + { + RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)e.Packet; + OnRegionHandleReply(new RegionHandleReplyEventArgs(reply.ReplyBlock.RegionID, reply.ReplyBlock.RegionHandle)); + } + } + + } + #region EventArgs classes + + public class CoarseLocationUpdateEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly List m_NewEntries; + private readonly List m_RemovedEntries; + + public Simulator Simulator { get { return m_Simulator; } } + public List NewEntries { get { return m_NewEntries; } } + public List RemovedEntries { get { return m_RemovedEntries; } } + + public CoarseLocationUpdateEventArgs(Simulator simulator, List newEntries, List removedEntries) + { + this.m_Simulator = simulator; + this.m_NewEntries = newEntries; + this.m_RemovedEntries = removedEntries; + } + } + + public class GridRegionEventArgs : EventArgs + { + private readonly GridRegion m_Region; + public GridRegion Region { get { return m_Region; } } + + public GridRegionEventArgs(GridRegion region) + { + this.m_Region = region; + } + } + + public class GridLayerEventArgs : EventArgs + { + private readonly GridLayer m_Layer; + + public GridLayer Layer { get { return m_Layer; } } + + public GridLayerEventArgs(GridLayer layer) + { + this.m_Layer = layer; + } + } + + public class GridItemsEventArgs : EventArgs + { + private readonly GridItemType m_Type; + private readonly List m_Items; + + public GridItemType Type { get { return m_Type; } } + public List Items { get { return m_Items; } } + + public GridItemsEventArgs(GridItemType type, List items) + { + this.m_Type = type; + this.m_Items = items; + } + } + + public class RegionHandleReplyEventArgs : EventArgs + { + private readonly UUID m_RegionID; + private readonly ulong m_RegionHandle; + + public UUID RegionID { get { return m_RegionID; } } + public ulong RegionHandle { get { return m_RegionHandle; } } + + public RegionHandleReplyEventArgs(UUID regionID, ulong regionHandle) + { + this.m_RegionID = regionID; + this.m_RegionHandle = regionHandle; + } + } + + #endregion +} diff --git a/OpenMetaverse/GroupManager.cs b/OpenMetaverse/GroupManager.cs new file mode 100644 index 0000000..ba02282 --- /dev/null +++ b/OpenMetaverse/GroupManager.cs @@ -0,0 +1,2420 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Http; + +namespace OpenMetaverse +{ + #region Structs + + /// + /// Avatar group management + /// + public struct GroupMember + { + /// Key of Group Member + public UUID ID; + /// Total land contribution + public int Contribution; + /// Online status information + public string OnlineStatus; + /// Abilities that the Group Member has + public GroupPowers Powers; + /// Current group title + public string Title; + /// Is a group owner + public bool IsOwner; + } + + /// + /// Role manager for a group + /// + public struct GroupRole + { + /// Key of the group + public UUID GroupID; + /// Key of Role + public UUID ID; + /// Name of Role + public string Name; + /// Group Title associated with Role + public string Title; + /// Description of Role + public string Description; + /// Abilities Associated with Role + public GroupPowers Powers; + /// Returns the role's title + /// The role's title + public override string ToString() + { + return Name; + } + } + + /// + /// Class to represent Group Title + /// + public struct GroupTitle + { + /// Key of the group + public UUID GroupID; + /// ID of the role title belongs to + public UUID RoleID; + /// Group Title + public string Title; + /// Whether title is Active + public bool Selected; + /// Returns group title + public override string ToString() + { + return Title; + } + } + + /// + /// Represents a group on the grid + /// + public struct Group + { + /// Key of Group + public UUID ID; + /// Key of Group Insignia + public UUID InsigniaID; + /// Key of Group Founder + public UUID FounderID; + /// Key of Group Role for Owners + public UUID OwnerRole; + /// Name of Group + public string Name; + /// Text of Group Charter + public string Charter; + /// Title of "everyone" role + public string MemberTitle; + /// Is the group open for enrolement to everyone + public bool OpenEnrollment; + /// Will group show up in search + public bool ShowInList; + /// + public GroupPowers Powers; + /// + public bool AcceptNotices; + /// + public bool AllowPublish; + /// Is the group Mature + public bool MaturePublish; + /// Cost of group membership + public int MembershipFee; + /// + public int Money; + /// + public int Contribution; + /// The total number of current members this group has + public int GroupMembershipCount; + /// The number of roles this group has configured + public int GroupRolesCount; + /// Show this group in agent's profile + public bool ListInProfile; + + /// Returns the name of the group + /// A string containing the name of the group + public override string ToString() + { + return Name; + } + } + + /// + /// A group Vote + /// + public struct Vote + { + /// Key of Avatar who created Vote + public UUID Candidate; + /// Text of the Vote proposal + public string VoteString; + /// Total number of votes + public int NumVotes; + } + + /// + /// A group proposal + /// + public struct GroupProposal + { + /// The Text of the proposal + public string VoteText; + /// The minimum number of members that must vote before proposal passes or failes + public int Quorum; + /// The required ration of yes/no votes required for vote to pass + /// The three options are Simple Majority, 2/3 Majority, and Unanimous + /// TODO: this should be an enum + public float Majority; + /// The duration in days votes are accepted + public int Duration; + } + + /// + /// + /// + public struct GroupAccountSummary + { + /// + public int IntervalDays; + /// + public int CurrentInterval; + /// + public string StartDate; + /// + public int Balance; + /// + public int TotalCredits; + /// + public int TotalDebits; + /// + public int ObjectTaxCurrent; + /// + public int LightTaxCurrent; + /// + public int LandTaxCurrent; + /// + public int GroupTaxCurrent; + /// + public int ParcelDirFeeCurrent; + /// + public int ObjectTaxEstimate; + /// + public int LightTaxEstimate; + /// + public int LandTaxEstimate; + /// + public int GroupTaxEstimate; + /// + public int ParcelDirFeeEstimate; + /// + public int NonExemptMembers; + /// + public string LastTaxDate; + /// + public string TaxDate; + } + + /// + /// Struct representing a group notice + /// + public struct GroupNotice + { + /// + public string Subject; + /// + public string Message; + /// + public UUID AttachmentID; + /// + public UUID OwnerID; + + /// + /// + /// + /// + public byte[] SerializeAttachment() + { + if (OwnerID == UUID.Zero || AttachmentID == UUID.Zero) + return Utils.EmptyBytes; + + OpenMetaverse.StructuredData.OSDMap att = new OpenMetaverse.StructuredData.OSDMap(); + att.Add("item_id", OpenMetaverse.StructuredData.OSD.FromUUID(AttachmentID)); + att.Add("owner_id", OpenMetaverse.StructuredData.OSD.FromUUID(OwnerID)); + + return OpenMetaverse.StructuredData.OSDParser.SerializeLLSDXmlBytes(att); + + /* + //I guess this is how this works, no gaurentees + string lsd = "" + AttachmentID.ToString() + "" + + OwnerID.ToString() + ""; + return Utils.StringToBytes(lsd); + */ + } + } + + /// + /// Struct representing a group notice list entry + /// + public struct GroupNoticesListEntry + { + /// Notice ID + public UUID NoticeID; + /// Creation timestamp of notice + public uint Timestamp; + /// Agent name who created notice + public string FromName; + /// Notice subject + public string Subject; + /// Is there an attachment? + public bool HasAttachment; + /// Attachment Type + public AssetType AssetType; + + } + + /// + /// Struct representing a member of a group chat session and their settings + /// + public struct ChatSessionMember + { + /// The of the Avatar + public UUID AvatarKey; + /// True if user has voice chat enabled + public bool CanVoiceChat; + /// True of Avatar has moderator abilities + public bool IsModerator; + /// True if a moderator has muted this avatars chat + public bool MuteText; + /// True if a moderator has muted this avatars voice + public bool MuteVoice; + } + + #endregion Structs + + #region Enums + + /// + /// Role update flags + /// + public enum GroupRoleUpdate : uint + { + /// + NoUpdate, + /// + UpdateData, + /// + UpdatePowers, + /// + UpdateAll, + /// + Create, + /// + Delete + } + + [Flags] + public enum GroupPowers : ulong + { + /// + None = 0, + + // Membership + /// Can send invitations to groups default role + Invite = 1UL << 1, + /// Can eject members from group + Eject = 1UL << 2, + /// Can toggle 'Open Enrollment' and change 'Signup fee' + ChangeOptions = 1UL << 3, + /// Member is visible in the public member list + MemberVisible = 1UL << 47, + + // Roles + /// Can create new roles + CreateRole = 1UL << 4, + /// Can delete existing roles + DeleteRole = 1UL << 5, + /// Can change Role names, titles and descriptions + RoleProperties = 1UL << 6, + /// Can assign other members to assigners role + AssignMemberLimited = 1UL << 7, + /// Can assign other members to any role + AssignMember = 1UL << 8, + /// Can remove members from roles + RemoveMember = 1UL << 9, + /// Can assign and remove abilities in roles + ChangeActions = 1UL << 10, + + // Identity + /// Can change group Charter, Insignia, 'Publish on the web' and which + /// members are publicly visible in group member listings + ChangeIdentity = 1UL << 11, + + // Parcel management + /// Can buy land or deed land to group + LandDeed = 1UL << 12, + /// Can abandon group owned land to Governor Linden on mainland, or Estate owner for + /// private estates + LandRelease = 1UL << 13, + /// Can set land for-sale information on group owned parcels + LandSetSale = 1UL << 14, + /// Can subdivide and join parcels + LandDivideJoin = 1UL << 15, + + + // Chat + /// Can join group chat sessions + JoinChat = 1UL << 16, + /// Can use voice chat in Group Chat sessions + AllowVoiceChat = 1UL << 27, + /// Can moderate group chat sessions + ModerateChat = 1UL << 37, + + // Parcel identity + /// Can toggle "Show in Find Places" and set search category + FindPlaces = 1UL << 17, + /// Can change parcel name, description, and 'Publish on web' settings + LandChangeIdentity = 1UL << 18, + /// Can set the landing point and teleport routing on group land + SetLandingPoint = 1UL << 19, + + // Parcel settings + /// Can change music and media settings + ChangeMedia = 1UL << 20, + /// Can toggle 'Edit Terrain' option in Land settings + LandEdit = 1UL << 21, + /// Can toggle various About Land > Options settings + LandOptions = 1UL << 22, + + // Parcel powers + /// Can always terraform land, even if parcel settings have it turned off + AllowEditLand = 1UL << 23, + /// Can always fly while over group owned land + AllowFly = 1UL << 24, + /// Can always rez objects on group owned land + AllowRez = 1UL << 25, + /// Can always create landmarks for group owned parcels + AllowLandmark = 1UL << 26, + /// Can set home location on any group owned parcel + AllowSetHome = 1UL << 28, + + + // Parcel access + /// Can modify public access settings for group owned parcels + LandManageAllowed = 1UL << 29, + /// Can manager parcel ban lists on group owned land + LandManageBanned = 1UL << 30, + /// Can manage pass list sales information + LandManagePasses = 1UL << 31, + /// Can eject and freeze other avatars on group owned land + LandEjectAndFreeze = 1UL << 32, + + // Parcel content + /// Can return objects set to group + ReturnGroupSet = 1UL << 33, + /// Can return non-group owned/set objects + ReturnNonGroup = 1UL << 34, + /// Can return group owned objects + ReturnGroupOwned = 1UL << 48, + + /// Can landscape using Linden plants + LandGardening = 1UL << 35, + + // Objects + /// Can deed objects to group + DeedObject = 1UL << 36, + /// Can move group owned objects + ObjectManipulate = 1UL << 38, + /// Can set group owned objects for-sale + ObjectSetForSale = 1UL << 39, + + /// Pay group liabilities and receive group dividends + Accountable = 1UL << 40, + + /// List and Host group events + HostEvent = 1UL << 41, + + // Notices and proposals + /// Can send group notices + SendNotices = 1UL << 42, + /// Can receive group notices + ReceiveNotices = 1UL << 43, + /// Can create group proposals + StartProposal = 1UL << 44, + /// Can vote on group proposals + VoteOnProposal = 1UL << 45 + } + + /// + /// Ban actions available for group members + /// + public enum GroupBanAction : int + { + /// Ban agent from joining a group + Ban = 1, + /// Remove restriction on agent jointing a group + Unban = 2, + } + + #endregion Enums + + /// + /// Handles all network traffic related to reading and writing group + /// information + /// + public class GroupManager + { + #region Delegates + + /// The event subscribers. null if no subcribers + private EventHandler m_CurrentGroups; + + /// Raises the CurrentGroups event + /// A CurrentGroupsEventArgs object containing the + /// data sent from the simulator + protected virtual void OnCurrentGroups(CurrentGroupsEventArgs e) + { + EventHandler handler = m_CurrentGroups; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_CurrentGroupsLock = new object(); + + /// Raised when the simulator sends us data containing + /// our current group membership + public event EventHandler CurrentGroups + { + add { lock (m_CurrentGroupsLock) { m_CurrentGroups += value; } } + remove { lock (m_CurrentGroupsLock) { m_CurrentGroups -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupNames; + + /// Raises the GroupNamesReply event + /// A GroupNamesEventArgs object containing the + /// data response from the simulator + protected virtual void OnGroupNamesReply(GroupNamesEventArgs e) + { + EventHandler handler = m_GroupNames; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupNamesLock = new object(); + + /// Raised when the simulator responds to a RequestGroupName + /// or RequestGroupNames request + public event EventHandler GroupNamesReply + { + add { lock (m_GroupNamesLock) { m_GroupNames += value; } } + remove { lock (m_GroupNamesLock) { m_GroupNames -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupProfile; + + /// Raises the GroupProfile event + /// An GroupProfileEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupProfile(GroupProfileEventArgs e) + { + EventHandler handler = m_GroupProfile; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupProfileLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler GroupProfile + { + add { lock (m_GroupProfileLock) { m_GroupProfile += value; } } + remove { lock (m_GroupProfileLock) { m_GroupProfile -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupMembers; + + /// Raises the GroupMembers event + /// A GroupMembersEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupMembersReply(GroupMembersReplyEventArgs e) + { + EventHandler handler = m_GroupMembers; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupMembersLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler GroupMembersReply + { + add { lock (m_GroupMembersLock) { m_GroupMembers += value; } } + remove { lock (m_GroupMembersLock) { m_GroupMembers -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupRoles; + + /// Raises the GroupRolesDataReply event + /// A GroupRolesDataReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupRoleDataReply(GroupRolesDataReplyEventArgs e) + { + EventHandler handler = m_GroupRoles; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupRolesLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler GroupRoleDataReply + { + add { lock (m_GroupRolesLock) { m_GroupRoles += value; } } + remove { lock (m_GroupRolesLock) { m_GroupRoles -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupRoleMembers; + + /// Raises the GroupRoleMembersReply event + /// A GroupRolesRoleMembersReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupRoleMembers(GroupRolesMembersReplyEventArgs e) + { + EventHandler handler = m_GroupRoleMembers; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupRolesMembersLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler GroupRoleMembersReply + { + add { lock (m_GroupRolesMembersLock) { m_GroupRoleMembers += value; } } + remove { lock (m_GroupRolesMembersLock) { m_GroupRoleMembers -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupTitles; + + + /// Raises the GroupTitlesReply event + /// A GroupTitlesReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupTitles(GroupTitlesReplyEventArgs e) + { + EventHandler handler = m_GroupTitles; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupTitlesLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler GroupTitlesReply + { + add { lock (m_GroupTitlesLock) { m_GroupTitles += value; } } + remove { lock (m_GroupTitlesLock) { m_GroupTitles -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupAccountSummary; + + /// Raises the GroupAccountSummary event + /// A GroupAccountSummaryReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupAccountSummaryReply(GroupAccountSummaryReplyEventArgs e) + { + EventHandler handler = m_GroupAccountSummary; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupAccountSummaryLock = new object(); + + /// Raised when a response to a RequestGroupAccountSummary is returned + /// by the simulator + public event EventHandler GroupAccountSummaryReply + { + add { lock (m_GroupAccountSummaryLock) { m_GroupAccountSummary += value; } } + remove { lock (m_GroupAccountSummaryLock) { m_GroupAccountSummary -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupCreated; + + /// Raises the GroupCreated event + /// An GroupCreatedEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupCreatedReply(GroupCreatedReplyEventArgs e) + { + EventHandler handler = m_GroupCreated; + if (handler != null) + handler(this, e); + } + /// Thread sync lock object + private readonly object m_GroupCreatedLock = new object(); + + /// Raised when a request to create a group is successful + public event EventHandler GroupCreatedReply + { + add { lock (m_GroupCreatedLock) { m_GroupCreated += value; } } + remove { lock (m_GroupCreatedLock) { m_GroupCreated -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupJoined; + + /// Raises the GroupJoined event + /// A GroupOperationEventArgs object containing the + /// result of the operation returned from the simulator + protected virtual void OnGroupJoinedReply(GroupOperationEventArgs e) + { + EventHandler handler = m_GroupJoined; + if (handler != null) + handler(this, e); + } + /// Thread sync lock object + private readonly object m_GroupJoinedLock = new object(); + + /// Raised when a request to join a group either + /// fails or succeeds + public event EventHandler GroupJoinedReply + { + add { lock (m_GroupJoinedLock) { m_GroupJoined += value; } } + remove { lock (m_GroupJoinedLock) { m_GroupJoined -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupLeft; + + /// Raises the GroupLeft event + /// A GroupOperationEventArgs object containing the + /// result of the operation returned from the simulator + protected virtual void OnGroupLeaveReply(GroupOperationEventArgs e) + { + EventHandler handler = m_GroupLeft; + if (handler != null) + handler(this, e); + } + /// Thread sync lock object + private readonly object m_GroupLeftLock = new object(); + + /// Raised when a request to leave a group either + /// fails or succeeds + public event EventHandler GroupLeaveReply + { + add { lock (m_GroupLeftLock) { m_GroupLeft += value; } } + remove { lock (m_GroupLeftLock) { m_GroupLeft -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupDropped; + + /// Raises the GroupDropped event + /// An GroupDroppedEventArgs object containing the + /// the group your agent left + protected virtual void OnGroupDropped(GroupDroppedEventArgs e) + { + EventHandler handler = m_GroupDropped; + if (handler != null) + handler(this, e); + } + /// Thread sync lock object + private readonly object m_GroupDroppedLock = new object(); + + /// Raised when A group is removed from the group server + public event EventHandler GroupDropped + { + add { lock (m_GroupDroppedLock) { m_GroupDropped += value; } } + remove { lock (m_GroupDroppedLock) { m_GroupDropped -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupMemberEjected; + + /// Raises the GroupMemberEjected event + /// An GroupMemberEjectedEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupMemberEjected(GroupOperationEventArgs e) + { + EventHandler handler = m_GroupMemberEjected; + if (handler != null) + handler(this, e); + } + /// Thread sync lock object + private readonly object m_GroupMemberEjectedLock = new object(); + + /// Raised when a request to eject a member from a group either + /// fails or succeeds + public event EventHandler GroupMemberEjected + { + add { lock (m_GroupMemberEjectedLock) { m_GroupMemberEjected += value; } } + remove { lock (m_GroupMemberEjectedLock) { m_GroupMemberEjected -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupNoticesListReply; + + /// Raises the GroupNoticesListReply event + /// An GroupNoticesListReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupNoticesListReply(GroupNoticesListReplyEventArgs e) + { + EventHandler handler = m_GroupNoticesListReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupNoticesListReplyLock = new object(); + + /// Raised when the simulator sends us group notices + /// + public event EventHandler GroupNoticesListReply + { + add { lock (m_GroupNoticesListReplyLock) { m_GroupNoticesListReply += value; } } + remove { lock (m_GroupNoticesListReplyLock) { m_GroupNoticesListReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_GroupInvitation; + + /// Raises the GroupInvitation event + /// An GroupInvitationEventArgs object containing the + /// data returned from the simulator + protected virtual void OnGroupInvitation(GroupInvitationEventArgs e) + { + EventHandler handler = m_GroupInvitation; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_GroupInvitationLock = new object(); + + /// Raised when another agent invites our avatar to join a group + public event EventHandler GroupInvitation + { + add { lock (m_GroupInvitationLock) { m_GroupInvitation += value; } } + remove { lock (m_GroupInvitationLock) { m_GroupInvitation -= value; } } + } + + + + + + + /// The event subscribers. null if no subcribers + private EventHandler m_BannedAgents; + + /// Raises the BannedAgents event + /// An BannedAgentsEventArgs object containing the + /// data returned from the simulator + protected virtual void OnBannedAgents(BannedAgentsEventArgs e) + { + EventHandler handler = m_BannedAgents; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_BannedAgentsLock = new object(); + + /// Raised when another agent invites our avatar to join a group + public event EventHandler BannedAgents + { + add { lock (m_BannedAgentsLock) { m_BannedAgents += value; } } + remove { lock (m_BannedAgentsLock) { m_BannedAgents -= value; } } + } + + #endregion Delegates + + + /// A reference to the current instance + private GridClient Client; + /// Currently-active group members requests + private List GroupMembersRequests; + /// Currently-active group roles requests + private List GroupRolesRequests; + /// Currently-active group role-member requests + private List GroupRolesMembersRequests; + /// Dictionary keeping group members while request is in progress + private InternalDictionary> TempGroupMembers; + /// Dictionary keeping mebmer/role mapping while request is in progress + private InternalDictionary>> TempGroupRolesMembers; + /// Dictionary keeping GroupRole information while request is in progress + private InternalDictionary> TempGroupRoles; + /// Caches group name lookups + public InternalDictionary GroupName2KeyCache; + + /// + /// Construct a new instance of the GroupManager class + /// + /// A reference to the current instance + public GroupManager(GridClient client) + { + Client = client; + + TempGroupMembers = new InternalDictionary>(); + GroupMembersRequests = new List(); + TempGroupRoles = new InternalDictionary>(); + GroupRolesRequests = new List(); + TempGroupRolesMembers = new InternalDictionary>>(); + GroupRolesMembersRequests = new List(); + GroupName2KeyCache = new InternalDictionary(); + + Client.Self.IM += Self_IM; + + Client.Network.RegisterEventCallback("AgentGroupDataUpdate", new Caps.EventQueueCallback(AgentGroupDataUpdateMessageHandler)); + // deprecated in simulator v1.27 + Client.Network.RegisterCallback(PacketType.AgentDropGroup, AgentDropGroupHandler); + Client.Network.RegisterCallback(PacketType.GroupTitlesReply, GroupTitlesReplyHandler); + Client.Network.RegisterCallback(PacketType.GroupProfileReply, GroupProfileReplyHandler); + Client.Network.RegisterCallback(PacketType.GroupMembersReply, GroupMembersHandler); + Client.Network.RegisterCallback(PacketType.GroupRoleDataReply, GroupRoleDataReplyHandler); + Client.Network.RegisterCallback(PacketType.GroupRoleMembersReply, GroupRoleMembersReplyHandler); + Client.Network.RegisterCallback(PacketType.GroupActiveProposalItemReply, GroupActiveProposalItemHandler); + Client.Network.RegisterCallback(PacketType.GroupVoteHistoryItemReply, GroupVoteHistoryItemHandler); + Client.Network.RegisterCallback(PacketType.GroupAccountSummaryReply, GroupAccountSummaryReplyHandler); + Client.Network.RegisterCallback(PacketType.CreateGroupReply, CreateGroupReplyHandler); + Client.Network.RegisterCallback(PacketType.JoinGroupReply, JoinGroupReplyHandler); + Client.Network.RegisterCallback(PacketType.LeaveGroupReply, LeaveGroupReplyHandler); + Client.Network.RegisterCallback(PacketType.UUIDGroupNameReply, UUIDGroupNameReplyHandler); + Client.Network.RegisterCallback(PacketType.EjectGroupMemberReply, EjectGroupMemberReplyHandler); + Client.Network.RegisterCallback(PacketType.GroupNoticesListReply, GroupNoticesListReplyHandler); + + Client.Network.RegisterEventCallback("AgentDropGroup", new Caps.EventQueueCallback(AgentDropGroupMessageHandler)); + } + + void Self_IM(object sender, InstantMessageEventArgs e) + { + if (m_GroupInvitation != null && e.IM.Dialog == InstantMessageDialog.GroupInvitation) + { + GroupInvitationEventArgs args = new GroupInvitationEventArgs(e.Simulator, e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message); + OnGroupInvitation(args); + + if (args.Accept) + { + Client.Self.InstantMessage("name", e.IM.FromAgentID, "message", e.IM.IMSessionID, InstantMessageDialog.GroupInvitationAccept, + InstantMessageOnline.Online, Client.Self.SimPosition, UUID.Zero, Utils.EmptyBytes); + } + else + { + Client.Self.InstantMessage("name", e.IM.FromAgentID, "message", e.IM.IMSessionID, InstantMessageDialog.GroupInvitationDecline, + InstantMessageOnline.Online, Client.Self.SimPosition, UUID.Zero, new byte[1] { 0 }); + } + } + } + + + #region Public Methods + + /// + /// Request a current list of groups the avatar is a member of. + /// + /// CAPS Event Queue must be running for this to work since the results + /// come across CAPS. + public void RequestCurrentGroups() + { + AgentDataUpdateRequestPacket request = new AgentDataUpdateRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + Client.Network.SendPacket(request); + } + + /// + /// Lookup name of group based on groupID + /// + /// groupID of group to lookup name for. + public void RequestGroupName(UUID groupID) + { + // if we already have this in the cache, return from cache instead of making a request + if (GroupName2KeyCache.ContainsKey(groupID)) + { + Dictionary groupNames = new Dictionary(); + lock (GroupName2KeyCache.Dictionary) + groupNames.Add(groupID, GroupName2KeyCache.Dictionary[groupID]); + + if (m_GroupNames != null) + { + OnGroupNamesReply(new GroupNamesEventArgs(groupNames)); + } + } + + else + { + UUIDGroupNameRequestPacket req = new UUIDGroupNameRequestPacket(); + UUIDGroupNameRequestPacket.UUIDNameBlockBlock[] block = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock[1]; + block[0] = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock(); + block[0].ID = groupID; + req.UUIDNameBlock = block; + Client.Network.SendPacket(req); + } + } + + /// + /// Request lookup of multiple group names + /// + /// List of group IDs to request. + public void RequestGroupNames(List groupIDs) + { + Dictionary groupNames = new Dictionary(); + lock (GroupName2KeyCache.Dictionary) + { + foreach (UUID groupID in groupIDs) + { + if (GroupName2KeyCache.ContainsKey(groupID)) + groupNames[groupID] = GroupName2KeyCache.Dictionary[groupID]; + } + } + + if (groupIDs.Count > 0) + { + UUIDGroupNameRequestPacket req = new UUIDGroupNameRequestPacket(); + UUIDGroupNameRequestPacket.UUIDNameBlockBlock[] block = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock[groupIDs.Count]; + + for (int i = 0; i < groupIDs.Count; i++) + { + block[i] = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock(); + block[i].ID = groupIDs[i]; + } + + req.UUIDNameBlock = block; + Client.Network.SendPacket(req); + } + + // fire handler from cache + if (groupNames.Count > 0 && m_GroupNames != null) + { + OnGroupNamesReply(new GroupNamesEventArgs(groupNames)); + } + } + + /// Lookup group profile data such as name, enrollment, founder, logo, etc + /// Subscribe to OnGroupProfile event to receive the results. + /// group ID (UUID) + public void RequestGroupProfile(UUID group) + { + GroupProfileRequestPacket request = new GroupProfileRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.GroupData.GroupID = group; + + Client.Network.SendPacket(request); + } + + /// Request a list of group members. + /// Subscribe to OnGroupMembers event to receive the results. + /// group ID (UUID) + /// UUID of the request, use to index into cache + public UUID RequestGroupMembers(UUID group) + { + UUID requestID = UUID.Random(); + Uri url = null; + + if (Client.Network.CurrentSim != null && Client.Network.CurrentSim.Caps != null && + null != (url = Client.Network.CurrentSim.Caps.CapabilityURI("GroupMemberData"))) + { + CapsClient req = new CapsClient(url); + req.OnComplete += (client, result, error) => + { + if (error == null) + { + GroupMembersHandlerCaps(requestID, result); + } + }; + + OSDMap requestData = new OSDMap(1); + requestData["group_id"] = group; + req.BeginGetResponse(requestData, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT * 4); + + return requestID; + } + + lock (GroupMembersRequests) GroupMembersRequests.Add(requestID); + + GroupMembersRequestPacket request = new GroupMembersRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.GroupData.GroupID = group; + request.GroupData.RequestID = requestID; + + Client.Network.SendPacket(request); + return requestID; + } + + /// Request group roles + /// Subscribe to OnGroupRoles event to receive the results. + /// group ID (UUID) + /// UUID of the request, use to index into cache + public UUID RequestGroupRoles(UUID group) + { + UUID requestID = UUID.Random(); + lock (GroupRolesRequests) GroupRolesRequests.Add(requestID); + + GroupRoleDataRequestPacket request = new GroupRoleDataRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.GroupData.GroupID = group; + request.GroupData.RequestID = requestID; + + Client.Network.SendPacket(request); + return requestID; + } + + /// Request members (members,role) role mapping for a group. + /// Subscribe to OnGroupRolesMembers event to receive the results. + /// group ID (UUID) + /// UUID of the request, use to index into cache + public UUID RequestGroupRolesMembers(UUID group) + { + UUID requestID = UUID.Random(); + lock (GroupRolesRequests) GroupRolesMembersRequests.Add(requestID); + + GroupRoleMembersRequestPacket request = new GroupRoleMembersRequestPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.GroupData.GroupID = group; + request.GroupData.RequestID = requestID; + Client.Network.SendPacket(request); + return requestID; + } + + /// Request a groups Titles + /// Subscribe to OnGroupTitles event to receive the results. + /// group ID (UUID) + /// UUID of the request, use to index into cache + public UUID RequestGroupTitles(UUID group) + { + UUID requestID = UUID.Random(); + + GroupTitlesRequestPacket request = new GroupTitlesRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.AgentData.GroupID = group; + request.AgentData.RequestID = requestID; + + Client.Network.SendPacket(request); + return requestID; + } + + /// Begin to get the group account summary + /// Subscribe to the OnGroupAccountSummary event to receive the results. + /// group ID (UUID) + /// How long of an interval + /// Which interval (0 for current, 1 for last) + public void RequestGroupAccountSummary(UUID group, int intervalDays, int currentInterval) + { + GroupAccountSummaryRequestPacket p = new GroupAccountSummaryRequestPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + p.AgentData.GroupID = group; + p.MoneyData.RequestID = UUID.Random(); + p.MoneyData.CurrentInterval = currentInterval; + p.MoneyData.IntervalDays = intervalDays; + Client.Network.SendPacket(p); + } + + /// Invites a user to a group + /// The group to invite to + /// A list of roles to invite a person to + /// Key of person to invite + public void Invite(UUID group, List roles, UUID personkey) + { + InviteGroupRequestPacket igp = new InviteGroupRequestPacket(); + + igp.AgentData = new InviteGroupRequestPacket.AgentDataBlock(); + igp.AgentData.AgentID = Client.Self.AgentID; + igp.AgentData.SessionID = Client.Self.SessionID; + + igp.GroupData = new InviteGroupRequestPacket.GroupDataBlock(); + igp.GroupData.GroupID = group; + + igp.InviteData = new InviteGroupRequestPacket.InviteDataBlock[roles.Count]; + + for (int i = 0; i < roles.Count; i++) + { + igp.InviteData[i] = new InviteGroupRequestPacket.InviteDataBlock(); + igp.InviteData[i].InviteeID = personkey; + igp.InviteData[i].RoleID = roles[i]; + } + + Client.Network.SendPacket(igp); + } + + /// Set a group as the current active group + /// group ID (UUID) + public void ActivateGroup(UUID id) + { + ActivateGroupPacket activate = new ActivateGroupPacket(); + activate.AgentData.AgentID = Client.Self.AgentID; + activate.AgentData.SessionID = Client.Self.SessionID; + activate.AgentData.GroupID = id; + + Client.Network.SendPacket(activate); + } + + /// Change the role that determines your active title + /// Group ID to use + /// Role ID to change to + public void ActivateTitle(UUID group, UUID role) + { + GroupTitleUpdatePacket gtu = new GroupTitleUpdatePacket(); + gtu.AgentData.AgentID = Client.Self.AgentID; + gtu.AgentData.SessionID = Client.Self.SessionID; + gtu.AgentData.TitleRoleID = role; + gtu.AgentData.GroupID = group; + + Client.Network.SendPacket(gtu); + } + + /// Set this avatar's tier contribution + /// Group ID to change tier in + /// amount of tier to donate + public void SetGroupContribution(UUID group, int contribution) + { + SetGroupContributionPacket sgp = new SetGroupContributionPacket(); + sgp.AgentData.AgentID = Client.Self.AgentID; + sgp.AgentData.SessionID = Client.Self.SessionID; + sgp.Data.GroupID = group; + sgp.Data.Contribution = contribution; + + Client.Network.SendPacket(sgp); + } + + /// + /// Save wheather agent wants to accept group notices and list this group in their profile + /// + /// Group + /// Accept notices from this group + /// List this group in the profile + public void SetGroupAcceptNotices(UUID groupID, bool acceptNotices, bool listInProfile) + { + SetGroupAcceptNoticesPacket p = new SetGroupAcceptNoticesPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + p.Data.GroupID = groupID; + p.Data.AcceptNotices = acceptNotices; + p.NewData.ListInProfile = listInProfile; + + Client.Network.SendPacket(p); + } + + /// Request to join a group + /// Subscribe to OnGroupJoined event for confirmation. + /// group ID (UUID) to join. + public void RequestJoinGroup(UUID id) + { + JoinGroupRequestPacket join = new JoinGroupRequestPacket(); + join.AgentData.AgentID = Client.Self.AgentID; + join.AgentData.SessionID = Client.Self.SessionID; + + join.GroupData.GroupID = id; + + Client.Network.SendPacket(join); + } + + /// + /// Request to create a new group. If the group is successfully + /// created, L$100 will automatically be deducted + /// + /// Subscribe to OnGroupCreated event to receive confirmation. + /// Group struct containing the new group info + public void RequestCreateGroup(Group group) + { + OpenMetaverse.Packets.CreateGroupRequestPacket cgrp = new CreateGroupRequestPacket(); + cgrp.AgentData = new CreateGroupRequestPacket.AgentDataBlock(); + cgrp.AgentData.AgentID = Client.Self.AgentID; + cgrp.AgentData.SessionID = Client.Self.SessionID; + + cgrp.GroupData = new CreateGroupRequestPacket.GroupDataBlock(); + cgrp.GroupData.AllowPublish = group.AllowPublish; + cgrp.GroupData.Charter = Utils.StringToBytes(group.Charter); + cgrp.GroupData.InsigniaID = group.InsigniaID; + cgrp.GroupData.MaturePublish = group.MaturePublish; + cgrp.GroupData.MembershipFee = group.MembershipFee; + cgrp.GroupData.Name = Utils.StringToBytes(group.Name); + cgrp.GroupData.OpenEnrollment = group.OpenEnrollment; + cgrp.GroupData.ShowInList = group.ShowInList; + + Client.Network.SendPacket(cgrp); + } + + /// Update a group's profile and other information + /// Groups ID (UUID) to update. + /// Group struct to update. + public void UpdateGroup(UUID id, Group group) + { + OpenMetaverse.Packets.UpdateGroupInfoPacket cgrp = new UpdateGroupInfoPacket(); + cgrp.AgentData = new UpdateGroupInfoPacket.AgentDataBlock(); + cgrp.AgentData.AgentID = Client.Self.AgentID; + cgrp.AgentData.SessionID = Client.Self.SessionID; + + cgrp.GroupData = new UpdateGroupInfoPacket.GroupDataBlock(); + cgrp.GroupData.GroupID = id; + cgrp.GroupData.AllowPublish = group.AllowPublish; + cgrp.GroupData.Charter = Utils.StringToBytes(group.Charter); + cgrp.GroupData.InsigniaID = group.InsigniaID; + cgrp.GroupData.MaturePublish = group.MaturePublish; + cgrp.GroupData.MembershipFee = group.MembershipFee; + cgrp.GroupData.OpenEnrollment = group.OpenEnrollment; + cgrp.GroupData.ShowInList = group.ShowInList; + + Client.Network.SendPacket(cgrp); + } + + /// Eject a user from a group + /// Group ID to eject the user from + /// Avatar's key to eject + public void EjectUser(UUID group, UUID member) + { + OpenMetaverse.Packets.EjectGroupMemberRequestPacket eject = new EjectGroupMemberRequestPacket(); + eject.AgentData = new EjectGroupMemberRequestPacket.AgentDataBlock(); + eject.AgentData.AgentID = Client.Self.AgentID; + eject.AgentData.SessionID = Client.Self.SessionID; + + eject.GroupData = new EjectGroupMemberRequestPacket.GroupDataBlock(); + eject.GroupData.GroupID = group; + + eject.EjectData = new EjectGroupMemberRequestPacket.EjectDataBlock[1]; + eject.EjectData[0] = new EjectGroupMemberRequestPacket.EjectDataBlock(); + eject.EjectData[0].EjecteeID = member; + + Client.Network.SendPacket(eject); + } + + /// Update role information + /// Modified role to be updated + public void UpdateRole(GroupRole role) + { + OpenMetaverse.Packets.GroupRoleUpdatePacket gru = new GroupRoleUpdatePacket(); + gru.AgentData.AgentID = Client.Self.AgentID; + gru.AgentData.SessionID = Client.Self.SessionID; + gru.AgentData.GroupID = role.GroupID; + gru.RoleData = new GroupRoleUpdatePacket.RoleDataBlock[1]; + gru.RoleData[0] = new GroupRoleUpdatePacket.RoleDataBlock(); + gru.RoleData[0].Name = Utils.StringToBytes(role.Name); + gru.RoleData[0].Description = Utils.StringToBytes(role.Description); + gru.RoleData[0].Powers = (ulong)role.Powers; + gru.RoleData[0].RoleID = role.ID; + gru.RoleData[0].Title = Utils.StringToBytes(role.Title); + gru.RoleData[0].UpdateType = (byte)GroupRoleUpdate.UpdateAll; + Client.Network.SendPacket(gru); + } + + /// Create a new group role + /// Group ID to update + /// Role to create + public void CreateRole(UUID group, GroupRole role) + { + OpenMetaverse.Packets.GroupRoleUpdatePacket gru = new GroupRoleUpdatePacket(); + gru.AgentData.AgentID = Client.Self.AgentID; + gru.AgentData.SessionID = Client.Self.SessionID; + gru.AgentData.GroupID = group; + gru.RoleData = new GroupRoleUpdatePacket.RoleDataBlock[1]; + gru.RoleData[0] = new GroupRoleUpdatePacket.RoleDataBlock(); + gru.RoleData[0].RoleID = UUID.Random(); + gru.RoleData[0].Name = Utils.StringToBytes(role.Name); + gru.RoleData[0].Description = Utils.StringToBytes(role.Description); + gru.RoleData[0].Powers = (ulong)role.Powers; + gru.RoleData[0].Title = Utils.StringToBytes(role.Title); + gru.RoleData[0].UpdateType = (byte)GroupRoleUpdate.Create; + Client.Network.SendPacket(gru); + } + + /// Delete a group role + /// Group ID to update + /// Role to delete + public void DeleteRole(UUID group, UUID roleID) + { + OpenMetaverse.Packets.GroupRoleUpdatePacket gru = new GroupRoleUpdatePacket(); + gru.AgentData.AgentID = Client.Self.AgentID; + gru.AgentData.SessionID = Client.Self.SessionID; + gru.AgentData.GroupID = group; + gru.RoleData = new GroupRoleUpdatePacket.RoleDataBlock[1]; + gru.RoleData[0] = new GroupRoleUpdatePacket.RoleDataBlock(); + gru.RoleData[0].RoleID = roleID; + gru.RoleData[0].Name = Utils.StringToBytes(string.Empty); + gru.RoleData[0].Description = Utils.StringToBytes(string.Empty); + gru.RoleData[0].Powers = 0u; + gru.RoleData[0].Title = Utils.StringToBytes(string.Empty); + gru.RoleData[0].UpdateType = (byte)GroupRoleUpdate.Delete; + Client.Network.SendPacket(gru); + } + + /// Remove an avatar from a role + /// Group ID to update + /// Role ID to be removed from + /// Avatar's Key to remove + public void RemoveFromRole(UUID group, UUID role, UUID member) + { + OpenMetaverse.Packets.GroupRoleChangesPacket grc = new GroupRoleChangesPacket(); + grc.AgentData.AgentID = Client.Self.AgentID; + grc.AgentData.SessionID = Client.Self.SessionID; + grc.AgentData.GroupID = group; + grc.RoleChange = new GroupRoleChangesPacket.RoleChangeBlock[1]; + grc.RoleChange[0] = new GroupRoleChangesPacket.RoleChangeBlock(); + //Add to members and role + grc.RoleChange[0].MemberID = member; + grc.RoleChange[0].RoleID = role; + //1 = Remove From Role TODO: this should be in an enum + grc.RoleChange[0].Change = 1; + Client.Network.SendPacket(grc); + } + + /// Assign an avatar to a role + /// Group ID to update + /// Role ID to assign to + /// Avatar's ID to assign to role + public void AddToRole(UUID group, UUID role, UUID member) + { + OpenMetaverse.Packets.GroupRoleChangesPacket grc = new GroupRoleChangesPacket(); + grc.AgentData.AgentID = Client.Self.AgentID; + grc.AgentData.SessionID = Client.Self.SessionID; + grc.AgentData.GroupID = group; + grc.RoleChange = new GroupRoleChangesPacket.RoleChangeBlock[1]; + grc.RoleChange[0] = new GroupRoleChangesPacket.RoleChangeBlock(); + //Add to members and role + grc.RoleChange[0].MemberID = member; + grc.RoleChange[0].RoleID = role; + //0 = Add to Role TODO: this should be in an enum + grc.RoleChange[0].Change = 0; + Client.Network.SendPacket(grc); + } + + /// Request the group notices list + /// Group ID to fetch notices for + public void RequestGroupNoticesList(UUID group) + { + OpenMetaverse.Packets.GroupNoticesListRequestPacket gnl = new GroupNoticesListRequestPacket(); + gnl.AgentData.AgentID = Client.Self.AgentID; + gnl.AgentData.SessionID = Client.Self.SessionID; + gnl.Data.GroupID = group; + Client.Network.SendPacket(gnl); + } + + /// Request a group notice by key + /// ID of group notice + public void RequestGroupNotice(UUID noticeID) + { + OpenMetaverse.Packets.GroupNoticeRequestPacket gnr = new GroupNoticeRequestPacket(); + gnr.AgentData.AgentID = Client.Self.AgentID; + gnr.AgentData.SessionID = Client.Self.SessionID; + gnr.Data.GroupNoticeID = noticeID; + Client.Network.SendPacket(gnr); + } + + /// Send out a group notice + /// Group ID to update + /// GroupNotice structure containing notice data + public void SendGroupNotice(UUID group, GroupNotice notice) + { + Client.Self.InstantMessage(Client.Self.Name, group, notice.Subject + "|" + notice.Message, + UUID.Zero, InstantMessageDialog.GroupNotice, InstantMessageOnline.Online, + Vector3.Zero, UUID.Zero, notice.SerializeAttachment()); + } + + /// Start a group proposal (vote) + /// The Group ID to send proposal to + /// GroupProposal structure containing the proposal + public void StartProposal(UUID group, GroupProposal prop) + { + StartGroupProposalPacket p = new StartGroupProposalPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + p.ProposalData.GroupID = group; + p.ProposalData.ProposalText = Utils.StringToBytes(prop.VoteText); + p.ProposalData.Quorum = prop.Quorum; + p.ProposalData.Majority = prop.Majority; + p.ProposalData.Duration = prop.Duration; + Client.Network.SendPacket(p); + } + + /// Request to leave a group + /// Subscribe to OnGroupLeft event to receive confirmation + /// The group to leave + public void LeaveGroup(UUID groupID) + { + LeaveGroupRequestPacket p = new LeaveGroupRequestPacket(); + p.AgentData.AgentID = Client.Self.AgentID; + p.AgentData.SessionID = Client.Self.SessionID; + p.GroupData.GroupID = groupID; + + Client.Network.SendPacket(p); + } + + /// + /// Gets the URI of the cpability for handling group bans + /// + /// Group ID + /// null, if the feature is not supported, or URI of the capability + public Uri GetGroupAPIUri(UUID groupID) + { + Uri ret = null; + + if (Client.Network.Connected + && Client.Network.CurrentSim != null + && Client.Network.CurrentSim.Caps != null) + { + ret = Client.Network.CurrentSim.Caps.CapabilityURI("GroupAPIv1"); + if (ret != null) + { + ret = new Uri(string.Format("{0}?group_id={1}", ret.ToString(), groupID.ToString())); + } + } + + return ret; + } + + /// + /// Request a list of residents banned from joining a group + /// + /// UUID of the group + public void RequestBannedAgents(UUID groupID) + { + RequestBannedAgents(groupID, null); + } + + /// + /// Request a list of residents banned from joining a group + /// + /// UUID of the group + /// Callback on request completition + public void RequestBannedAgents(UUID groupID, EventHandler callback) + { + Uri uri = GetGroupAPIUri(groupID); + if (uri == null) return; + + CapsClient req = new CapsClient(uri); + req.OnComplete += (client, result, error) => + { + try + { + + if (error != null) + { + throw error; + } + else + { + UUID gid = ((OSDMap)result)["group_id"]; + var banList = (OSDMap)((OSDMap)result)["ban_list"]; + Dictionary bannedAgents = new Dictionary(banList.Count); + + foreach (var id in banList.Keys) + { + bannedAgents[new UUID(id)] = ((OSDMap)banList[id])["ban_date"].AsDate(); + } + + var ret = new BannedAgentsEventArgs(groupID, true, bannedAgents); + OnBannedAgents(ret); + if (callback != null) try { callback(this, ret); } + catch { } + } + + } + catch (Exception ex) + { + Logger.Log("Failed to get a list of banned group members: " + ex.Message, Helpers.LogLevel.Warning, Client); + var ret = new BannedAgentsEventArgs(groupID, false, null); + OnBannedAgents(ret); + if (callback != null) try { callback(this, ret); } + catch { } + } + + }; + + req.BeginGetResponse(Client.Settings.CAPS_TIMEOUT); + } + + /// + /// Request that group of agents be banned or unbanned from the group + /// + /// Group ID + /// Ban/Unban action + /// Array of agents UUIDs to ban + public void RequestBanAction(UUID groupID, GroupBanAction action, UUID[] agents) + { + RequestBanAction(groupID, action, agents, null); + } + + /// + /// Request that group of agents be banned or unbanned from the group + /// + /// Group ID + /// Ban/Unban action + /// Array of agents UUIDs to ban + /// Callback + public void RequestBanAction(UUID groupID, GroupBanAction action, UUID[] agents, EventHandler callback) + { + Uri uri = GetGroupAPIUri(groupID); + if (uri == null) return; + + CapsClient req = new CapsClient(uri); + req.OnComplete += (client, result, error) => + { + if (callback != null) try { callback(this, EventArgs.Empty); } + catch { } + }; + + OSDMap OSDRequest = new OSDMap(); + OSDRequest["ban_action"] = (int)action; + OSDArray banIDs = new OSDArray(agents.Length); + foreach (var agent in agents) + { + banIDs.Add(agent); + } + OSDRequest["ban_ids"] = banIDs; + + req.BeginGetResponse(OSDRequest, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + + + + #endregion + + #region Packet Handlers + + protected void AgentGroupDataUpdateMessageHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_CurrentGroups != null) + { + AgentGroupDataUpdateMessage msg = (AgentGroupDataUpdateMessage)message; + + Dictionary currentGroups = new Dictionary(); + for (int i = 0; i < msg.GroupDataBlock.Length; i++) + { + Group group = new Group(); + group.ID = msg.GroupDataBlock[i].GroupID; + group.InsigniaID = msg.GroupDataBlock[i].GroupInsigniaID; + group.Name = msg.GroupDataBlock[i].GroupName; + group.Contribution = msg.GroupDataBlock[i].Contribution; + group.AcceptNotices = msg.GroupDataBlock[i].AcceptNotices; + group.Powers = msg.GroupDataBlock[i].GroupPowers; + group.ListInProfile = msg.NewGroupDataBlock[i].ListInProfile; + + currentGroups.Add(group.ID, group); + + lock (GroupName2KeyCache.Dictionary) + { + if (!GroupName2KeyCache.Dictionary.ContainsKey(group.ID)) + GroupName2KeyCache.Dictionary.Add(group.ID, group.Name); + } + } + OnCurrentGroups(new CurrentGroupsEventArgs(currentGroups)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AgentDropGroupHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupDropped != null) + { + Packet packet = e.Packet; + OnGroupDropped(new GroupDroppedEventArgs(((AgentDropGroupPacket)packet).AgentData.GroupID)); + } + } + + protected void AgentDropGroupMessageHandler(string capsKey, IMessage message, Simulator simulator) + { + + if (m_GroupDropped != null) + { + AgentDropGroupMessage msg = (AgentDropGroupMessage)message; + for (int i = 0; i < msg.AgentDataBlock.Length; i++) + { + OnGroupDropped(new GroupDroppedEventArgs(msg.AgentDataBlock[i].GroupID)); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupProfileReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupProfile != null) + { + Packet packet = e.Packet; + GroupProfileReplyPacket profile = (GroupProfileReplyPacket)packet; + Group group = new Group(); + + group.ID = profile.GroupData.GroupID; + group.AllowPublish = profile.GroupData.AllowPublish; + group.Charter = Utils.BytesToString(profile.GroupData.Charter); + group.FounderID = profile.GroupData.FounderID; + group.GroupMembershipCount = profile.GroupData.GroupMembershipCount; + group.GroupRolesCount = profile.GroupData.GroupRolesCount; + group.InsigniaID = profile.GroupData.InsigniaID; + group.MaturePublish = profile.GroupData.MaturePublish; + group.MembershipFee = profile.GroupData.MembershipFee; + group.MemberTitle = Utils.BytesToString(profile.GroupData.MemberTitle); + group.Money = profile.GroupData.Money; + group.Name = Utils.BytesToString(profile.GroupData.Name); + group.OpenEnrollment = profile.GroupData.OpenEnrollment; + group.OwnerRole = profile.GroupData.OwnerRole; + group.Powers = (GroupPowers)profile.GroupData.PowersMask; + group.ShowInList = profile.GroupData.ShowInList; + + OnGroupProfile(new GroupProfileEventArgs(group)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupNoticesListReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupNoticesListReply != null) + { + Packet packet = e.Packet; + GroupNoticesListReplyPacket reply = (GroupNoticesListReplyPacket)packet; + + List notices = new List(); + + foreach (GroupNoticesListReplyPacket.DataBlock entry in reply.Data) + { + GroupNoticesListEntry notice = new GroupNoticesListEntry(); + notice.FromName = Utils.BytesToString(entry.FromName); + notice.Subject = Utils.BytesToString(entry.Subject); + notice.NoticeID = entry.NoticeID; + notice.Timestamp = entry.Timestamp; + notice.HasAttachment = entry.HasAttachment; + notice.AssetType = (AssetType)entry.AssetType; + + notices.Add(notice); + } + + OnGroupNoticesListReply(new GroupNoticesListReplyEventArgs(reply.AgentData.GroupID, notices)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupTitlesReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupTitles != null) + { + Packet packet = e.Packet; + GroupTitlesReplyPacket titles = (GroupTitlesReplyPacket)packet; + Dictionary groupTitleCache = new Dictionary(); + + foreach (GroupTitlesReplyPacket.GroupDataBlock block in titles.GroupData) + { + GroupTitle groupTitle = new GroupTitle(); + + groupTitle.GroupID = titles.AgentData.GroupID; + groupTitle.RoleID = block.RoleID; + groupTitle.Title = Utils.BytesToString(block.Title); + groupTitle.Selected = block.Selected; + + groupTitleCache[block.RoleID] = groupTitle; + } + OnGroupTitles(new GroupTitlesReplyEventArgs(titles.AgentData.RequestID, titles.AgentData.GroupID, groupTitleCache)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupMembersHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + GroupMembersReplyPacket members = (GroupMembersReplyPacket)packet; + Dictionary groupMemberCache = null; + + lock (GroupMembersRequests) + { + // If nothing is registered to receive this RequestID drop the data + if (GroupMembersRequests.Contains(members.GroupData.RequestID)) + { + lock (TempGroupMembers.Dictionary) + { + if (!TempGroupMembers.TryGetValue(members.GroupData.RequestID, out groupMemberCache)) + { + groupMemberCache = new Dictionary(); + TempGroupMembers[members.GroupData.RequestID] = groupMemberCache; + } + + foreach (GroupMembersReplyPacket.MemberDataBlock block in members.MemberData) + { + GroupMember groupMember = new GroupMember(); + + groupMember.ID = block.AgentID; + groupMember.Contribution = block.Contribution; + groupMember.IsOwner = block.IsOwner; + groupMember.OnlineStatus = Utils.BytesToString(block.OnlineStatus); + groupMember.Powers = (GroupPowers)block.AgentPowers; + groupMember.Title = Utils.BytesToString(block.Title); + + groupMemberCache[block.AgentID] = groupMember; + } + + if (groupMemberCache.Count >= members.GroupData.MemberCount) + { + GroupMembersRequests.Remove(members.GroupData.RequestID); + TempGroupMembers.Remove(members.GroupData.RequestID); + } + } + } + } + + if (m_GroupMembers != null && groupMemberCache != null && groupMemberCache.Count >= members.GroupData.MemberCount) + { + OnGroupMembersReply(new GroupMembersReplyEventArgs(members.GroupData.RequestID, members.GroupData.GroupID, groupMemberCache)); + } + } + + protected void GroupMembersHandlerCaps(UUID requestID, OSD result) + { + try + { + OSDMap res = (OSDMap)result; + int memberCount = res["member_count"]; + OSDArray titlesOSD = (OSDArray)res["titles"]; + string[] titles = new string[titlesOSD.Count]; + for (int i = 0; i < titlesOSD.Count; i++) + { + titles[i] = titlesOSD[i]; + } + UUID groupID = res["group_id"]; + GroupPowers defaultPowers = (GroupPowers)(ulong)((OSDMap)res["defaults"])["default_powers"]; + OSDMap membersOSD = (OSDMap)res["members"]; + Dictionary groupMembers = new Dictionary(membersOSD.Count); + foreach (var memberID in membersOSD.Keys) + { + OSDMap member = (OSDMap)membersOSD[memberID]; + + GroupMember groupMember = new GroupMember(); + groupMember.ID = (UUID)memberID; + groupMember.Contribution = member["donated_square_meters"]; + groupMember.IsOwner = "Y" == member["owner"].AsString(); + groupMember.OnlineStatus = member["last_login"]; + groupMember.Powers = defaultPowers; + if (member.ContainsKey("powers")) + { + groupMember.Powers = (GroupPowers)(ulong)member["powers"]; + } + groupMember.Title = titles[(int)member["title"]]; + + groupMembers[groupMember.ID] = groupMember; + } + + OnGroupMembersReply(new GroupMembersReplyEventArgs(requestID, groupID, groupMembers)); + } + catch (Exception ex) + { + Logger.Log("Failed to decode result of GroupMemberData capability: ", Helpers.LogLevel.Error, Client, ex); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupRoleDataReplyHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + GroupRoleDataReplyPacket roles = (GroupRoleDataReplyPacket)packet; + Dictionary groupRoleCache = null; + + lock (GroupRolesRequests) + { + // If nothing is registered to receive this RequestID drop the data + if (GroupRolesRequests.Contains(roles.GroupData.RequestID)) + { + lock (TempGroupRoles.Dictionary) + { + if (!TempGroupRoles.TryGetValue(roles.GroupData.RequestID, out groupRoleCache)) + { + groupRoleCache = new Dictionary(); + TempGroupRoles[roles.GroupData.RequestID] = groupRoleCache; + } + + foreach (GroupRoleDataReplyPacket.RoleDataBlock block in roles.RoleData) + { + GroupRole groupRole = new GroupRole(); + + groupRole.GroupID = roles.GroupData.GroupID; + groupRole.ID = block.RoleID; + groupRole.Description = Utils.BytesToString(block.Description); + groupRole.Name = Utils.BytesToString(block.Name); + groupRole.Powers = (GroupPowers)block.Powers; + groupRole.Title = Utils.BytesToString(block.Title); + + groupRoleCache[block.RoleID] = groupRole; + } + + if (groupRoleCache.Count >= roles.GroupData.RoleCount) + { + GroupRolesRequests.Remove(roles.GroupData.RequestID); + TempGroupRoles.Remove(roles.GroupData.RequestID); + } + } + } + } + + if (m_GroupRoles != null && groupRoleCache != null && groupRoleCache.Count >= roles.GroupData.RoleCount) + { + OnGroupRoleDataReply(new GroupRolesDataReplyEventArgs(roles.GroupData.RequestID, roles.GroupData.GroupID, groupRoleCache)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupRoleMembersReplyHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + GroupRoleMembersReplyPacket members = (GroupRoleMembersReplyPacket)packet; + List> groupRoleMemberCache = null; + + try + { + lock (GroupRolesMembersRequests) + { + // If nothing is registered to receive this RequestID drop the data + if (GroupRolesMembersRequests.Contains(members.AgentData.RequestID)) + { + lock (TempGroupRolesMembers.Dictionary) + { + if (!TempGroupRolesMembers.TryGetValue(members.AgentData.RequestID, out groupRoleMemberCache)) + { + groupRoleMemberCache = new List>(); + TempGroupRolesMembers[members.AgentData.RequestID] = groupRoleMemberCache; + } + + foreach (GroupRoleMembersReplyPacket.MemberDataBlock block in members.MemberData) + { + KeyValuePair rolemember = + new KeyValuePair(block.RoleID, block.MemberID); + + groupRoleMemberCache.Add(rolemember); + } + + if (groupRoleMemberCache.Count >= members.AgentData.TotalPairs) + { + GroupRolesMembersRequests.Remove(members.AgentData.RequestID); + TempGroupRolesMembers.Remove(members.AgentData.RequestID); + } + } + } + } + } + catch (Exception ex) + { + Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); + } + + if (m_GroupRoleMembers != null && groupRoleMemberCache != null && groupRoleMemberCache.Count >= members.AgentData.TotalPairs) + { + OnGroupRoleMembers(new GroupRolesMembersReplyEventArgs(members.AgentData.RequestID, members.AgentData.GroupID, groupRoleMemberCache)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupActiveProposalItemHandler(object sender, PacketReceivedEventArgs e) + { + //GroupActiveProposalItemReplyPacket proposal = (GroupActiveProposalItemReplyPacket)packet; + + // TODO: Create a proposal struct to represent the fields in a proposal item + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupVoteHistoryItemHandler(object sender, PacketReceivedEventArgs e) + { + //GroupVoteHistoryItemReplyPacket history = (GroupVoteHistoryItemReplyPacket)packet; + + // TODO: This was broken in the official viewer when I was last trying to work on it + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void GroupAccountSummaryReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupAccountSummary != null) + { + Packet packet = e.Packet; + GroupAccountSummaryReplyPacket summary = (GroupAccountSummaryReplyPacket)packet; + GroupAccountSummary account = new GroupAccountSummary(); + + account.Balance = summary.MoneyData.Balance; + account.CurrentInterval = summary.MoneyData.CurrentInterval; + account.GroupTaxCurrent = summary.MoneyData.GroupTaxCurrent; + account.GroupTaxEstimate = summary.MoneyData.GroupTaxEstimate; + account.IntervalDays = summary.MoneyData.IntervalDays; + account.LandTaxCurrent = summary.MoneyData.LandTaxCurrent; + account.LandTaxEstimate = summary.MoneyData.LandTaxEstimate; + account.LastTaxDate = Utils.BytesToString(summary.MoneyData.LastTaxDate); + account.LightTaxCurrent = summary.MoneyData.LightTaxCurrent; + account.LightTaxEstimate = summary.MoneyData.LightTaxEstimate; + account.NonExemptMembers = summary.MoneyData.NonExemptMembers; + account.ObjectTaxCurrent = summary.MoneyData.ObjectTaxCurrent; + account.ObjectTaxEstimate = summary.MoneyData.ObjectTaxEstimate; + account.ParcelDirFeeCurrent = summary.MoneyData.ParcelDirFeeCurrent; + account.ParcelDirFeeEstimate = summary.MoneyData.ParcelDirFeeEstimate; + account.StartDate = Utils.BytesToString(summary.MoneyData.StartDate); + account.TaxDate = Utils.BytesToString(summary.MoneyData.TaxDate); + account.TotalCredits = summary.MoneyData.TotalCredits; + account.TotalDebits = summary.MoneyData.TotalDebits; + + OnGroupAccountSummaryReply(new GroupAccountSummaryReplyEventArgs(summary.AgentData.GroupID, account)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void CreateGroupReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupCreated != null) + { + Packet packet = e.Packet; + CreateGroupReplyPacket reply = (CreateGroupReplyPacket)packet; + + string message = Utils.BytesToString(reply.ReplyData.Message); + + OnGroupCreatedReply(new GroupCreatedReplyEventArgs(reply.ReplyData.GroupID, reply.ReplyData.Success, message)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void JoinGroupReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupJoined != null) + { + Packet packet = e.Packet; + JoinGroupReplyPacket reply = (JoinGroupReplyPacket)packet; + + OnGroupJoinedReply(new GroupOperationEventArgs(reply.GroupData.GroupID, reply.GroupData.Success)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void LeaveGroupReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_GroupLeft != null) + { + Packet packet = e.Packet; + LeaveGroupReplyPacket reply = (LeaveGroupReplyPacket)packet; + + OnGroupLeaveReply(new GroupOperationEventArgs(reply.GroupData.GroupID, reply.GroupData.Success)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + private void UUIDGroupNameReplyHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + UUIDGroupNameReplyPacket reply = (UUIDGroupNameReplyPacket)packet; + UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] blocks = reply.UUIDNameBlock; + + Dictionary groupNames = new Dictionary(); + + foreach (UUIDGroupNameReplyPacket.UUIDNameBlockBlock block in blocks) + { + groupNames.Add(block.ID, Utils.BytesToString(block.GroupName)); + if (!GroupName2KeyCache.ContainsKey(block.ID)) + GroupName2KeyCache.Add(block.ID, Utils.BytesToString(block.GroupName)); + } + + if (m_GroupNames != null) + { + OnGroupNamesReply(new GroupNamesEventArgs(groupNames)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void EjectGroupMemberReplyHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + EjectGroupMemberReplyPacket reply = (EjectGroupMemberReplyPacket)packet; + + // TODO: On Success remove the member from the cache(s) + + if (m_GroupMemberEjected != null) + { + OnGroupMemberEjected(new GroupOperationEventArgs(reply.GroupData.GroupID, reply.EjectData.Success)); + } + } + + #endregion Packet Handlers + } + + #region EventArgs + + /// Contains the current groups your agent is a member of + public class CurrentGroupsEventArgs : EventArgs + { + private readonly Dictionary m_Groups; + + /// Get the current groups your agent is a member of + public Dictionary Groups { get { return m_Groups; } } + + /// Construct a new instance of the CurrentGroupsEventArgs class + /// The current groups your agent is a member of + public CurrentGroupsEventArgs(Dictionary groups) + { + this.m_Groups = groups; + } + } + + /// A Dictionary of group names, where the Key is the groups ID and the value is the groups name + public class GroupNamesEventArgs : EventArgs + { + private readonly Dictionary m_GroupNames; + + /// Get the Group Names dictionary + public Dictionary GroupNames { get { return m_GroupNames; } } + + /// Construct a new instance of the GroupNamesEventArgs class + /// The Group names dictionary + public GroupNamesEventArgs(Dictionary groupNames) + { + this.m_GroupNames = groupNames; + } + } + + /// Represents the members of a group + public class GroupMembersReplyEventArgs : EventArgs + { + private readonly UUID m_RequestID; + private readonly UUID m_GroupID; + private readonly Dictionary m_Members; + + /// Get the ID as returned by the request to correlate + /// this result set and the request + public UUID RequestID { get { return m_RequestID; } } + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// Get the dictionary of members + public Dictionary Members { get { return m_Members; } } + + /// + /// Construct a new instance of the GroupMembersReplyEventArgs class + /// + /// The ID of the request + /// The ID of the group + /// The membership list of the group + public GroupMembersReplyEventArgs(UUID requestID, UUID groupID, Dictionary members) + { + this.m_RequestID = requestID; + this.m_GroupID = groupID; + this.m_Members = members; + } + } + + /// Represents the roles associated with a group + public class GroupRolesDataReplyEventArgs : EventArgs + { + private readonly UUID m_RequestID; + private readonly UUID m_GroupID; + private readonly Dictionary m_Roles; + + /// Get the ID as returned by the request to correlate + /// this result set and the request + public UUID RequestID { get { return m_RequestID; } } + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// Get the dictionary containing the roles + public Dictionary Roles { get { return m_Roles; } } + + /// Construct a new instance of the GroupRolesDataReplyEventArgs class + /// The ID as returned by the request to correlate + /// this result set and the request + /// The ID of the group + /// The dictionary containing the roles + public GroupRolesDataReplyEventArgs(UUID requestID, UUID groupID, Dictionary roles) + { + this.m_RequestID = requestID; + this.m_GroupID = groupID; + this.m_Roles = roles; + } + } + + /// Represents the Role to Member mappings for a group + public class GroupRolesMembersReplyEventArgs : EventArgs + { + private readonly UUID m_RequestID; + private readonly UUID m_GroupID; + private readonly List> m_RolesMembers; + + /// Get the ID as returned by the request to correlate + /// this result set and the request + public UUID RequestID { get { return m_RequestID; } } + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// Get the member to roles map + public List> RolesMembers { get { return m_RolesMembers; } } + + /// Construct a new instance of the GroupRolesMembersReplyEventArgs class + /// The ID as returned by the request to correlate + /// this result set and the request + /// The ID of the group + /// The member to roles map + public GroupRolesMembersReplyEventArgs(UUID requestID, UUID groupID, List> rolesMembers) + { + this.m_RequestID = requestID; + this.m_GroupID = groupID; + this.m_RolesMembers = rolesMembers; + } + } + + /// Represents the titles for a group + public class GroupTitlesReplyEventArgs : EventArgs + { + private readonly UUID m_RequestID; + private readonly UUID m_GroupID; + private readonly Dictionary m_Titles; + + /// Get the ID as returned by the request to correlate + /// this result set and the request + public UUID RequestID { get { return m_RequestID; } } + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// Get the titles + public Dictionary Titles { get { return m_Titles; } } + + /// Construct a new instance of the GroupTitlesReplyEventArgs class + /// The ID as returned by the request to correlate + /// this result set and the request + /// The ID of the group + /// The titles + public GroupTitlesReplyEventArgs(UUID requestID, UUID groupID, Dictionary titles) + { + this.m_RequestID = requestID; + this.m_GroupID = groupID; + this.m_Titles = titles; + } + } + + /// Represents the summary data for a group + public class GroupAccountSummaryReplyEventArgs : EventArgs + { + private readonly UUID m_GroupID; + private readonly GroupAccountSummary m_Summary; + + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// Get the summary data + public GroupAccountSummary Summary { get { return m_Summary; } } + + /// Construct a new instance of the GroupAccountSummaryReplyEventArgs class + /// The ID of the group + /// The summary data + public GroupAccountSummaryReplyEventArgs(UUID groupID, GroupAccountSummary summary) + { + this.m_GroupID = groupID; + this.m_Summary = summary; + } + } + + /// A response to a group create request + public class GroupCreatedReplyEventArgs : EventArgs + { + private readonly UUID m_GroupID; + private readonly bool m_Success; + private readonly string m_Message; + + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// true of the group was created successfully + public bool Success { get { return m_Success; } } + /// A string containing the message + public string Message { get { return m_Message; } } + + /// Construct a new instance of the GroupCreatedReplyEventArgs class + /// The ID of the group + /// the success or faulure of the request + /// A string containing additional information + public GroupCreatedReplyEventArgs(UUID groupID, bool success, string messsage) + { + this.m_GroupID = groupID; + this.m_Success = success; + this.m_Message = messsage; + } + } + + /// Represents a response to a request + public class GroupOperationEventArgs : EventArgs + { + private readonly UUID m_GroupID; + private readonly bool m_Success; + + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// true of the request was successful + public bool Success { get { return m_Success; } } + + /// Construct a new instance of the GroupOperationEventArgs class + /// The ID of the group + /// true of the request was successful + public GroupOperationEventArgs(UUID groupID, bool success) + { + this.m_GroupID = groupID; + this.m_Success = success; + } + } + + /// Represents your agent leaving a group + public class GroupDroppedEventArgs : EventArgs + { + private readonly UUID m_GroupID; + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + + /// Construct a new instance of the GroupDroppedEventArgs class + /// The ID of the group + public GroupDroppedEventArgs(UUID groupID) + { + m_GroupID = groupID; + } + } + + /// Represents a list of active group notices + public class GroupNoticesListReplyEventArgs : EventArgs + { + private readonly UUID m_GroupID; + private readonly List m_Notices; + + /// Get the ID of the group + public UUID GroupID { get { return m_GroupID; } } + /// Get the notices list + public List Notices { get { return m_Notices; } } + + /// Construct a new instance of the GroupNoticesListReplyEventArgs class + /// The ID of the group + /// The list containing active notices + public GroupNoticesListReplyEventArgs(UUID groupID, List notices) + { + m_GroupID = groupID; + m_Notices = notices; + } + } + + /// Represents the profile of a group + public class GroupProfileEventArgs : EventArgs + { + private readonly Group m_Group; + + /// Get the group profile + public Group Group { get { return m_Group; } } + + /// Construct a new instance of the GroupProfileEventArgs class + /// The group profile + public GroupProfileEventArgs(Group group) + { + this.m_Group = group; + } + } + + /// + /// Provides notification of a group invitation request sent by another Avatar + /// + /// The invitation is raised when another avatar makes an offer for our avatar + /// to join a group. + public class GroupInvitationEventArgs : EventArgs + { + private readonly UUID m_FromAgentID; + private readonly string m_FromAgentName; + private readonly string m_Message; + private readonly Simulator m_Simulator; + + /// The ID of the Avatar sending the group invitation + public UUID AgentID { get { return m_FromAgentID; } } + /// The name of the Avatar sending the group invitation + public string FromName { get { return m_FromAgentName; } } + /// A message containing the request information which includes + /// the name of the group, the groups charter and the fee to join details + public string Message { get { return m_Message; } } + /// The Simulator + public Simulator Simulator { get { return m_Simulator; } } + + /// Set to true to accept invitation, false to decline + public bool Accept { get; set; } + + public GroupInvitationEventArgs(Simulator simulator, UUID agentID, string agentName, string message) + { + this.m_Simulator = simulator; + this.m_FromAgentID = agentID; + this.m_FromAgentName = agentName; + this.m_Message = message; + } + } + + /// + /// Result of the request for list of agents banned from a group + /// + public class BannedAgentsEventArgs : EventArgs + { + readonly UUID mGroupID; + readonly bool mSuccess; + readonly Dictionary mBannedAgents; + + /// Indicates if list of banned agents for a group was successfully retrieved + public UUID GroupID { get { return mGroupID; } } + + /// Indicates if list of banned agents for a group was successfully retrieved + public bool Success { get { return mSuccess; } } + + /// Array containing a list of UUIDs of the agents banned from a group + public Dictionary BannedAgents { get { return mBannedAgents; } } + + public BannedAgentsEventArgs(UUID groupID, bool success, Dictionary bannedAgents) + { + this.mGroupID = groupID; + this.mSuccess = success; + this.mBannedAgents = bannedAgents; + } + } + + #endregion +} diff --git a/OpenMetaverse/Helpers.cs b/OpenMetaverse/Helpers.cs new file mode 100644 index 0000000..ba6d01e --- /dev/null +++ b/OpenMetaverse/Helpers.cs @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse.Packets; +using System.IO; +using System.Reflection; +using OpenMetaverse.StructuredData; +using ComponentAce.Compression.Libs.zlib; + +namespace OpenMetaverse +{ + /// + /// Static helper functions and global variables + /// + public static class Helpers + { + /// This header flag signals that ACKs are appended to the packet + public const byte MSG_APPENDED_ACKS = 0x10; + /// This header flag signals that this packet has been sent before + public const byte MSG_RESENT = 0x20; + /// This header flags signals that an ACK is expected for this packet + public const byte MSG_RELIABLE = 0x40; + /// This header flag signals that the message is compressed using zerocoding + public const byte MSG_ZEROCODED = 0x80; + + /// + /// Passed to Logger.Log() to identify the severity of a log entry + /// + public enum LogLevel + { + /// No logging information will be output + None, + /// Non-noisy useful information, may be helpful in + /// debugging a problem + Info, + /// A non-critical error occurred. A warning will not + /// prevent the rest of the library from operating as usual, + /// although it may be indicative of an underlying issue + Warning, + /// A critical error has occurred. Generally this will + /// be followed by the network layer shutting down, although the + /// stability of the library after an error is uncertain + Error, + /// Used for internal testing, this logging level can + /// generate very noisy (long and/or repetitive) messages. Don't + /// pass this to the Log() function, use DebugLog() instead. + /// + Debug + }; + + /// + /// + /// + /// + /// + public static short TEOffsetShort(float offset) + { + offset = Utils.Clamp(offset, -1.0f, 1.0f); + offset *= 32767.0f; + return (short)Math.Round(offset); + } + + /// + /// + /// + /// + /// + /// + public static float TEOffsetFloat(byte[] bytes, int pos) + { + float offset = (float)BitConverter.ToInt16(bytes, pos); + return offset / 32767.0f; + } + + /// + /// + /// + /// + /// + public static short TERotationShort(float rotation) + { + const float TWO_PI = 6.283185307179586476925286766559f; + return (short)Math.Round(((Math.IEEERemainder(rotation, TWO_PI) / TWO_PI) * 32768.0f) + 0.5f); + } + + /// + /// + /// + /// + /// + /// + public static float TERotationFloat(byte[] bytes, int pos) + { + const float TWO_PI = 6.283185307179586476925286766559f; + return ((float)(bytes[pos] | (bytes[pos + 1] << 8)) / 32768.0f) * TWO_PI; + } + + public static byte TEGlowByte(float glow) + { + return (byte)(glow * 255.0f); + } + + public static float TEGlowFloat(byte[] bytes, int pos) + { + return (float)bytes[pos] / 255.0f; + } + + /// + /// Given an X/Y location in absolute (grid-relative) terms, a region + /// handle is returned along with the local X/Y location in that region + /// + /// The absolute X location, a number such as + /// 255360.35 + /// The absolute Y location, a number such as + /// 255360.35 + /// The sim-local X position of the global X + /// position, a value from 0.0 to 256.0 + /// The sim-local Y position of the global Y + /// position, a value from 0.0 to 256.0 + /// A 64-bit region handle that can be used to teleport to + public static ulong GlobalPosToRegionHandle(float globalX, float globalY, out float localX, out float localY) + { + uint x = ((uint)globalX / 256) * 256; + uint y = ((uint)globalY / 256) * 256; + localX = globalX - (float)x; + localY = globalY - (float)y; + return Utils.UIntsToLong(x, y); + } + + /// + /// Converts a floating point number to a terse string format used for + /// transmitting numbers in wearable asset files + /// + /// Floating point number to convert to a string + /// A terse string representation of the input number + public static string FloatToTerseString(float val) + { + string s = string.Format(Utils.EnUsCulture, "{0:.00}", val); + + if (val == 0) + return ".00"; + + // Trim trailing zeroes + while (s[s.Length - 1] == '0') + s = s.Remove(s.Length - 1, 1); + + // Remove superfluous decimal places after the trim + if (s[s.Length - 1] == '.') + s = s.Remove(s.Length - 1, 1); + // Remove leading zeroes after a negative sign + else if (s[0] == '-' && s[1] == '0') + s = s.Remove(1, 1); + // Remove leading zeroes in positive numbers + else if (s[0] == '0') + s = s.Remove(0, 1); + + return s; + } + + /// + /// Convert a variable length field (byte array) to a string, with a + /// field name prepended to each line of the output + /// + /// If the byte array has unprintable characters in it, a + /// hex dump will be written instead + /// The StringBuilder object to write to + /// The byte array to convert to a string + /// A field name to prepend to each line of output + internal static void FieldToString(StringBuilder output, byte[] bytes, string fieldName) + { + // Check for a common case + if (bytes.Length == 0) return; + + bool printable = true; + + for (int i = 0; i < bytes.Length; ++i) + { + // Check if there are any unprintable characters in the array + if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09 + && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00) + { + printable = false; + break; + } + } + + if (printable) + { + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + if (bytes[bytes.Length - 1] == 0x00) + output.Append(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1)); + else + output.Append(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length)); + } + else + { + for (int i = 0; i < bytes.Length; i += 16) + { + if (i != 0) + output.Append('\n'); + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + for (int j = 0; j < 16; j++) + { + if ((i + j) < bytes.Length) + output.Append(String.Format("{0:X2} ", bytes[i + j])); + else + output.Append(" "); + } + } + } + } + + /// + /// Decode a zerocoded byte array, used to decompress packets marked + /// with the zerocoded flag + /// + /// Any time a zero is encountered, the next byte is a count + /// of how many zeroes to expand. One zero is encoded with 0x00 0x01, + /// two zeroes is 0x00 0x02, three zeroes is 0x00 0x03, etc. The + /// first four bytes are copied directly to the output buffer. + /// + /// The byte array to decode + /// The length of the byte array to decode. This + /// would be the length of the packet up to (but not including) any + /// appended ACKs + /// The output byte array to decode to + /// The length of the output buffer + public static int ZeroDecode(byte[] src, int srclen, byte[] dest) + { + if (srclen > src.Length) + throw new ArgumentException("srclen cannot be greater than src.Length"); + + uint zerolen = 0; + int bodylen = 0; + uint i = 0; + + try + { + Buffer.BlockCopy(src, 0, dest, 0, 6); + zerolen = 6; + bodylen = srclen; + + for (i = zerolen; i < bodylen; i++) + { + if (src[i] == 0x00) + { + for (byte j = 0; j < src[i + 1]; j++) + { + dest[zerolen++] = 0x00; + } + + i++; + } + else + { + dest[zerolen++] = src[i]; + } + } + + // Copy appended ACKs + for (; i < srclen; i++) + { + dest[zerolen++] = src[i]; + } + + return (int)zerolen; + } + catch (Exception ex) + { + Logger.Log(String.Format("Zerodecoding error: i={0}, srclen={1}, bodylen={2}, zerolen={3}\n{4}\n{5}", + i, srclen, bodylen, zerolen, Utils.BytesToHexString(src, srclen, null), ex), LogLevel.Error); + + throw new IndexOutOfRangeException(String.Format("Zerodecoding error: i={0}, srclen={1}, bodylen={2}, zerolen={3}\n{4}\n{5}", + i, srclen, bodylen, zerolen, Utils.BytesToHexString(src, srclen, null), ex.InnerException)); + } + } + + /// + /// Encode a byte array with zerocoding. Used to compress packets marked + /// with the zerocoded flag. Any zeroes in the array are compressed down + /// to a single zero byte followed by a count of how many zeroes to expand + /// out. A single zero becomes 0x00 0x01, two zeroes becomes 0x00 0x02, + /// three zeroes becomes 0x00 0x03, etc. The first four bytes are copied + /// directly to the output buffer. + /// + /// The byte array to encode + /// The length of the byte array to encode + /// The output byte array to encode to + /// The length of the output buffer + public static int ZeroEncode(byte[] src, int srclen, byte[] dest) + { + uint zerolen = 0; + byte zerocount = 0; + + Buffer.BlockCopy(src, 0, dest, 0, 6); + zerolen += 6; + + int bodylen; + if ((src[0] & MSG_APPENDED_ACKS) == 0) + { + bodylen = srclen; + } + else + { + bodylen = srclen - src[srclen - 1] * 4 - 1; + } + + uint i; + for (i = zerolen; i < bodylen; i++) + { + if (src[i] == 0x00) + { + zerocount++; + + if (zerocount == 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = 0xff; + zerocount++; + } + } + else + { + if (zerocount != 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = (byte)zerocount; + zerocount = 0; + } + + dest[zerolen++] = src[i]; + } + } + + if (zerocount != 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = (byte)zerocount; + } + + // copy appended ACKs + for (; i < srclen; i++) + { + dest[zerolen++] = src[i]; + } + + return (int)zerolen; + } + + /// + /// Calculates the CRC (cyclic redundancy check) needed to upload inventory. + /// + /// Creation date + /// Sale type + /// Inventory type + /// Type + /// Asset ID + /// Group ID + /// Sale price + /// Owner ID + /// Creator ID + /// Item ID + /// Folder ID + /// Everyone mask (permissions) + /// Flags + /// Next owner mask (permissions) + /// Group mask (permissions) + /// Owner mask (permissions) + /// The calculated CRC + public static uint InventoryCRC(int creationDate, byte saleType, sbyte invType, sbyte type, + UUID assetID, UUID groupID, int salePrice, UUID ownerID, UUID creatorID, + UUID itemID, UUID folderID, uint everyoneMask, uint flags, uint nextOwnerMask, + uint groupMask, uint ownerMask) + { + uint CRC = 0; + + // IDs + CRC += assetID.CRC(); // AssetID + CRC += folderID.CRC(); // FolderID + CRC += itemID.CRC(); // ItemID + + // Permission stuff + CRC += creatorID.CRC(); // CreatorID + CRC += ownerID.CRC(); // OwnerID + CRC += groupID.CRC(); // GroupID + + // CRC += another 4 words which always seem to be zero -- unclear if this is a UUID or what + CRC += ownerMask; + CRC += nextOwnerMask; + CRC += everyoneMask; + CRC += groupMask; + + // The rest of the CRC fields + CRC += flags; // Flags + CRC += (uint)invType; // InvType + CRC += (uint)type; // Type + CRC += (uint)creationDate; // CreationDate + CRC += (uint)salePrice; // SalePrice + CRC += (uint)((uint)saleType * 0x07073096); // SaleType + + return CRC; + } + + /// + /// Attempts to load a file embedded in the assembly + /// + /// The filename of the resource to load + /// A Stream for the requested file, or null if the resource + /// was not successfully loaded + public static System.IO.Stream GetResourceStream(string resourceName) + { + return GetResourceStream(resourceName, "openmetaverse_data"); + } + + /// + /// Attempts to load a file either embedded in the assembly or found in + /// a given search path + /// + /// The filename of the resource to load + /// An optional path that will be searched if + /// the asset is not found embedded in the assembly + /// A Stream for the requested file, or null if the resource + /// was not successfully loaded + public static System.IO.Stream GetResourceStream(string resourceName, string searchPath) + { + if (searchPath != null) + { + Assembly gea = Assembly.GetEntryAssembly(); + if (gea == null) gea = typeof(Helpers).Assembly; + string dirname = "."; + if (gea != null && gea.Location != null) + { + dirname = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(gea.Location), searchPath); + } + + string filename = System.IO.Path.Combine(dirname, resourceName); + try + { + return new System.IO.FileStream( + filename, + System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); + } + catch (Exception ex) + { + Logger.Log(string.Format("Failed opening resource from file {0}: {1}", filename, ex.Message), LogLevel.Error); + } + } + else + { + try + { + System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); + System.IO.Stream s = a.GetManifestResourceStream("OpenMetaverse.Resources." + resourceName); + if (s != null) return s; + } + catch (Exception ex) + { + Logger.Log(string.Format("Failed opening resource stream: {0}", ex.Message), LogLevel.Error); + } + } + + return null; + } + /// + /// Converts a list of primitives to an object that can be serialized + /// with the LLSD system + /// + /// Primitives to convert to a serializable object + /// An object that can be serialized with LLSD + public static StructuredData.OSD PrimListToOSD(List prims) + { + StructuredData.OSDMap map = new OpenMetaverse.StructuredData.OSDMap(prims.Count); + + for (int i = 0; i < prims.Count; i++) + map.Add(prims[i].LocalID.ToString(), prims[i].GetOSD()); + + return map; + } + + /// + /// Deserializes OSD in to a list of primitives + /// + /// Structure holding the serialized primitive list, + /// must be of the SDMap type + /// A list of deserialized primitives + public static List OSDToPrimList(StructuredData.OSD osd) + { + if (osd.Type != StructuredData.OSDType.Map) + throw new ArgumentException("LLSD must be in the Map structure"); + + StructuredData.OSDMap map = (StructuredData.OSDMap)osd; + List prims = new List(map.Count); + + foreach (KeyValuePair kvp in map) + { + Primitive prim = Primitive.FromOSD(kvp.Value); + prim.LocalID = UInt32.Parse(kvp.Key); + prims.Add(prim); + } + + return prims; + } + + /// + /// Converts a struct or class object containing fields only into a key value separated string + /// + /// The struct object + /// A string containing the struct fields as the keys, and the field value as the value separated + /// + /// + /// // Add the following code to any struct or class containing only fields to override the ToString() + /// // method to display the values of the passed object + /// + /// /// Print the struct data as a string + /// ///A string containing the field name, and field value + ///public override string ToString() + ///{ + /// return Helpers.StructToString(this); + ///} + /// + /// + public static string StructToString(object t) + { + StringBuilder result = new StringBuilder(); + Type structType = t.GetType(); + FieldInfo[] fields = structType.GetFields(); + + foreach (FieldInfo field in fields) + { + result.Append(field.Name + ": " + field.GetValue(t) + " "); + } + result.AppendLine(); + return result.ToString().TrimEnd(); + } + + public static void CopyStream(Stream input, Stream output) + { + byte[] buffer = new byte[4096]; + int read; + while ((read = input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer, 0, read); + } + } + + public static byte[] ZCompressOSD(OSD data) + { + byte[] ret = null; + + using (MemoryStream outMemoryStream = new MemoryStream()) + using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream, zlibConst.Z_BEST_COMPRESSION)) + using (Stream inMemoryStream = new MemoryStream(OSDParser.SerializeLLSDBinary(data, false))) + { + CopyStream(inMemoryStream, outZStream); + outZStream.finish(); + ret = outMemoryStream.ToArray(); + } + + return ret; + } + + public static OSD ZDecompressOSD(byte[] data) + { + OSD ret; + + using (MemoryStream input = new MemoryStream(data)) + using (MemoryStream output = new MemoryStream()) + using (ZOutputStream zout = new ZOutputStream(output)) + { + CopyStream(input, zout); + zout.finish(); + output.Seek(0, SeekOrigin.Begin); + ret = OSDParser.DeserializeLLSDBinary(output); + } + + return ret; + } + } +} diff --git a/OpenMetaverse/Imaging/BakeLayer.cs b/OpenMetaverse/Imaging/BakeLayer.cs new file mode 100644 index 0000000..f67f86c --- /dev/null +++ b/OpenMetaverse/Imaging/BakeLayer.cs @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Drawing; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.Imaging +{ + /// + /// A set of textures that are layered on texture of each other and "baked" + /// in to a single texture, for avatar appearances + /// + public class Baker + { + public static readonly UUID IMG_INVISIBLE = new UUID("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); + + #region Properties + /// Final baked texture + public AssetTexture BakedTexture { get { return bakedTexture; } } + /// Component layers + public List Textures { get { return textures; } } + /// Width of the final baked image and scratchpad + public int BakeWidth { get { return bakeWidth; } } + /// Height of the final baked image and scratchpad + public int BakeHeight { get { return bakeHeight; } } + /// Bake type + public BakeType BakeType { get { return bakeType; } } + /// Is this one of the 3 skin bakes + private bool IsSkin { get { return bakeType == BakeType.Head || bakeType == BakeType.LowerBody || bakeType == BakeType.UpperBody; } } + #endregion + + #region Private fields + /// Final baked texture + private AssetTexture bakedTexture; + /// Component layers + private List textures = new List(); + /// Width of the final baked image and scratchpad + private int bakeWidth; + /// Height of the final baked image and scratchpad + private int bakeHeight; + /// Bake type + private BakeType bakeType; + #endregion + + #region Constructor + /// + /// Default constructor + /// + /// Bake type + public Baker(BakeType bakeType) + { + this.bakeType = bakeType; + + if (bakeType == BakeType.Eyes) + { + bakeWidth = 128; + bakeHeight = 128; + } + else + { + bakeWidth = 512; + bakeHeight = 512; + } + } + #endregion + + #region Public methods + /// + /// Adds layer for baking + /// + /// TexturaData struct that contains texture and its params + public void AddTexture(AppearanceManager.TextureData tdata) + { + lock (textures) + { + textures.Add(tdata); + } + } + + public void Bake() + { + bakedTexture = new AssetTexture(new ManagedImage(bakeWidth, bakeHeight, + ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump)); + + // Base color for eye bake is white, color of layer0 for others + if (bakeType == BakeType.Eyes) + { + InitBakedLayerColor(Color4.White); + } + else if (textures.Count > 0) + { + InitBakedLayerColor(textures[0].Color); + } + + // Do we have skin texture? + bool SkinTexture = textures.Count > 0 && textures[0].Texture != null; + + if (bakeType == BakeType.Head) + { + DrawLayer(LoadResourceLayer("head_color.tga"), false); + AddAlpha(bakedTexture.Image, LoadResourceLayer("head_alpha.tga")); + MultiplyLayerFromAlpha(bakedTexture.Image, LoadResourceLayer("head_skingrain.tga")); + } + + if (!SkinTexture && bakeType == BakeType.UpperBody) + { + DrawLayer(LoadResourceLayer("upperbody_color.tga"), false); + } + + if (!SkinTexture && bakeType == BakeType.LowerBody) + { + DrawLayer(LoadResourceLayer("lowerbody_color.tga"), false); + } + + ManagedImage alphaWearableTexture = null; + + // Layer each texture on top of one other, applying alpha masks as we go + for (int i = 0; i < textures.Count; i++) + { + // Skip if we have no texture on this layer + if (textures[i].Texture == null) continue; + + // Is this Alpha wearable and does it have an alpha channel? + if (textures[i].TextureIndex >= AvatarTextureIndex.LowerAlpha && + textures[i].TextureIndex <= AvatarTextureIndex.HairAlpha) + { + if (textures[i].Texture.Image.Alpha != null) + { + alphaWearableTexture = textures[i].Texture.Image.Clone(); + } + else if (textures[i].TextureID == IMG_INVISIBLE) + { + alphaWearableTexture = new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Alpha); + } + continue; + } + + // Don't draw skin and tattoo on head bake first + // For head bake the skin and texture are drawn last, go figure + if (bakeType == BakeType.Head && (i == 0 || i == 1)) continue; + + ManagedImage texture = textures[i].Texture.Image.Clone(); + //File.WriteAllBytes(bakeType + "-texture-layer-" + i + ".tga", texture.ExportTGA()); + + // Resize texture to the size of baked layer + // FIXME: if texture is smaller than the layer, don't stretch it, tile it + if (texture.Width != bakeWidth || texture.Height != bakeHeight) + { + try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); } + catch (Exception) { continue; } + } + + // Special case for hair layer for the head bake + // If we don't have skin texture, we discard hair alpha + // and apply hair(i==2) pattern over the texture + if (!SkinTexture && bakeType == BakeType.Head && i == 2) + { + if (texture.Alpha != null) + { + for (int j = 0; j < texture.Alpha.Length; j++) texture.Alpha[j] = (byte)255; + } + MultiplyLayerFromAlpha(texture, LoadResourceLayer("head_hair.tga")); + } + + // Aply tint and alpha masks except for skin that has a texture + // on layer 0 which always overrides other skin settings + if (!(IsSkin && i == 0)) + { + ApplyTint(texture, textures[i].Color); + + // For hair bake, we skip all alpha masks + // and use one from the texture, for both + // alpha and morph layers + if (bakeType == BakeType.Hair) + { + if (texture.Alpha != null) + { + bakedTexture.Image.Bump = texture.Alpha; + } + else + { + for (int j = 0; j < bakedTexture.Image.Bump.Length; j++) bakedTexture.Image.Bump[j] = byte.MaxValue; + } + } + // Apply parametrized alpha masks + else if (textures[i].AlphaMasks != null && textures[i].AlphaMasks.Count > 0) + { + // Combined mask for the layer, fully transparent to begin with + ManagedImage combinedMask = new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Alpha); + + int addedMasks = 0; + + // First add mask in normal blend mode + foreach (KeyValuePair kvp in textures[i].AlphaMasks) + { + if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue; + + if (kvp.Key.MultiplyBlend == false && (kvp.Value > 0f || !kvp.Key.SkipIfZero)) + { + ApplyAlpha(combinedMask, kvp.Key, kvp.Value); + //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA()); + addedMasks++; + } + } + + // If there were no mask in normal blend mode make aplha fully opaque + if (addedMasks == 0) for (int l = 0; l < combinedMask.Alpha.Length; l++) combinedMask.Alpha[l] = 255; + + // Add masks in multiply blend mode + foreach (KeyValuePair kvp in textures[i].AlphaMasks) + { + if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue; + + if (kvp.Key.MultiplyBlend == true && (kvp.Value > 0f || !kvp.Key.SkipIfZero)) + { + ApplyAlpha(combinedMask, kvp.Key, kvp.Value); + //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA()); + addedMasks++; + } + } + + if (addedMasks > 0) + { + // Apply combined alpha mask to the cloned texture + AddAlpha(texture, combinedMask); + } + + // Is this layer used for morph mask? If it is, use its + // alpha as the morth for the whole bake + if (Textures[i].TextureIndex == AppearanceManager.MorphLayerForBakeType(bakeType)) + { + bakedTexture.Image.Bump = texture.Alpha; + } + + //File.WriteAllBytes(bakeType + "-masked-texture-" + i + ".tga", texture.ExportTGA()); + } + } + + bool useAlpha = i == 0 && (BakeType == BakeType.Skirt || BakeType == BakeType.Hair); + DrawLayer(texture, useAlpha); + //File.WriteAllBytes(bakeType + "-layer-" + i + ".tga", texture.ExportTGA()); + } + + // For head and tattoo, we add skin last + if (IsSkin && bakeType == BakeType.Head) + { + ManagedImage texture; + if (textures[0].Texture != null) + { + texture = textures[0].Texture.Image.Clone(); + if (texture.Width != bakeWidth || texture.Height != bakeHeight) + { + try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); } + catch (Exception) { } + } + DrawLayer(texture, false); + } + + // Add head tattoo here (if available, order-dependant) + if (textures.Count > 1 && textures[1].Texture != null) + { + texture = textures[1].Texture.Image.Clone(); + if (texture.Width != bakeWidth || texture.Height != bakeHeight) + { + try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); } + catch (Exception) { } + } + DrawLayer(texture, false); + } + } + + // Apply any alpha wearable textures to make parts of the avatar disappear + if (alphaWearableTexture != null) + { + AddAlpha(bakedTexture.Image, alphaWearableTexture); + } + + // We are done, encode asset for finalized bake + bakedTexture.Encode(); + //File.WriteAllBytes(bakeType + ".tga", bakedTexture.Image.ExportTGA()); + } + + private static object ResourceSync = new object(); + + public static ManagedImage LoadResourceLayer(string fileName) + { + try + { + Bitmap bitmap = null; + lock (ResourceSync) + { + using (Stream stream = Helpers.GetResourceStream(fileName, Settings.RESOURCE_DIR)) + { + bitmap = LoadTGAClass.LoadTGA(stream); + } + } + if (bitmap == null) + { + Logger.Log(String.Format("Failed loading resource file: {0}", fileName), Helpers.LogLevel.Error); + return null; + } + else + { + ManagedImage image = new ManagedImage(bitmap); + bitmap.Dispose(); + return image; + } + } + catch (Exception e) + { + Logger.Log(String.Format("Failed loading resource file: {0} ({1})", fileName, e.Message), + Helpers.LogLevel.Error, e); + return null; + } + } + + /// + /// Converts avatar texture index (face) to Bake type + /// + /// Face number (AvatarTextureIndex) + /// BakeType, layer to which this texture belongs to + public static BakeType BakeTypeFor(AvatarTextureIndex index) + { + switch (index) + { + case AvatarTextureIndex.HeadBodypaint: + return BakeType.Head; + + case AvatarTextureIndex.UpperBodypaint: + case AvatarTextureIndex.UpperGloves: + case AvatarTextureIndex.UpperUndershirt: + case AvatarTextureIndex.UpperShirt: + case AvatarTextureIndex.UpperJacket: + return BakeType.UpperBody; + + case AvatarTextureIndex.LowerBodypaint: + case AvatarTextureIndex.LowerUnderpants: + case AvatarTextureIndex.LowerSocks: + case AvatarTextureIndex.LowerShoes: + case AvatarTextureIndex.LowerPants: + case AvatarTextureIndex.LowerJacket: + return BakeType.LowerBody; + + case AvatarTextureIndex.EyesIris: + return BakeType.Eyes; + + case AvatarTextureIndex.Skirt: + return BakeType.Skirt; + + case AvatarTextureIndex.Hair: + return BakeType.Hair; + + default: + return BakeType.Unknown; + } + } + #endregion + + #region Private layer compositing methods + + private bool MaskBelongsToBake(string mask) + { + if ((bakeType == BakeType.LowerBody && mask.Contains("upper")) + || (bakeType == BakeType.LowerBody && mask.Contains("shirt")) + || (bakeType == BakeType.UpperBody && mask.Contains("lower"))) + { + return false; + } + else + { + return true; + } + } + + private bool DrawLayer(ManagedImage source, bool addSourceAlpha) + { + if (source == null) return false; + + bool sourceHasColor; + bool sourceHasAlpha; + bool sourceHasBump; + int i = 0; + + sourceHasColor = ((source.Channels & ManagedImage.ImageChannels.Color) != 0 && + source.Red != null && source.Green != null && source.Blue != null); + sourceHasAlpha = ((source.Channels & ManagedImage.ImageChannels.Alpha) != 0 && source.Alpha != null); + sourceHasBump = ((source.Channels & ManagedImage.ImageChannels.Bump) != 0 && source.Bump != null); + + addSourceAlpha = (addSourceAlpha && sourceHasAlpha); + + byte alpha = Byte.MaxValue; + byte alphaInv = (byte)(Byte.MaxValue - alpha); + + byte[] bakedRed = bakedTexture.Image.Red; + byte[] bakedGreen = bakedTexture.Image.Green; + byte[] bakedBlue = bakedTexture.Image.Blue; + byte[] bakedAlpha = bakedTexture.Image.Alpha; + byte[] bakedBump = bakedTexture.Image.Bump; + + byte[] sourceRed = source.Red; + byte[] sourceGreen = source.Green; + byte[] sourceBlue = source.Blue; + byte[] sourceAlpha = sourceHasAlpha ? source.Alpha : null; + byte[] sourceBump = sourceHasBump ? source.Bump : null; + + for (int y = 0; y < bakeHeight; y++) + { + for (int x = 0; x < bakeWidth; x++) + { + if (sourceHasAlpha) + { + alpha = sourceAlpha[i]; + alphaInv = (byte)(Byte.MaxValue - alpha); + } + + if (sourceHasColor) + { + bakedRed[i] = (byte)((bakedRed[i] * alphaInv + sourceRed[i] * alpha) >> 8); + bakedGreen[i] = (byte)((bakedGreen[i] * alphaInv + sourceGreen[i] * alpha) >> 8); + bakedBlue[i] = (byte)((bakedBlue[i] * alphaInv + sourceBlue[i] * alpha) >> 8); + } + + if (addSourceAlpha) + { + if (sourceAlpha[i] < bakedAlpha[i]) + { + bakedAlpha[i] = sourceAlpha[i]; + } + } + + if (sourceHasBump) + bakedBump[i] = sourceBump[i]; + + ++i; + } + } + + return true; + } + + /// + /// Make sure images exist, resize source if needed to match the destination + /// + /// Destination image + /// Source image + /// Sanitization was succefull + private bool SanitizeLayers(ManagedImage dest, ManagedImage src) + { + if (dest == null || src == null) return false; + + if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0) + { + dest.ConvertChannels(dest.Channels | ManagedImage.ImageChannels.Alpha); + } + + if (dest.Width != src.Width || dest.Height != src.Height) + { + try { src.ResizeNearestNeighbor(dest.Width, dest.Height); } + catch (Exception) { return false; } + } + + return true; + } + + + private void ApplyAlpha(ManagedImage dest, VisualAlphaParam param, float val) + { + ManagedImage src = LoadResourceLayer(param.TGAFile); + + if (dest == null || src == null || src.Alpha == null) return; + + if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0) + { + dest.ConvertChannels(ManagedImage.ImageChannels.Alpha | dest.Channels); + } + + if (dest.Width != src.Width || dest.Height != src.Height) + { + try { src.ResizeNearestNeighbor(dest.Width, dest.Height); } + catch (Exception) { return; } + } + + for (int i = 0; i < dest.Alpha.Length; i++) + { + byte alpha = src.Alpha[i] <= ((1 - val) * 255) ? (byte)0 : (byte)255; + if (alpha != 255) + { + } + if (param.MultiplyBlend) + { + dest.Alpha[i] = (byte)((dest.Alpha[i] * alpha) >> 8); + } + else + { + if (alpha > dest.Alpha[i]) + { + dest.Alpha[i] = alpha; + } + } + } + } + + private void AddAlpha(ManagedImage dest, ManagedImage src) + { + if (!SanitizeLayers(dest, src)) return; + + for (int i = 0; i < dest.Alpha.Length; i++) + { + if (src.Alpha[i] < dest.Alpha[i]) + { + dest.Alpha[i] = src.Alpha[i]; + } + } + } + + private void MultiplyLayerFromAlpha(ManagedImage dest, ManagedImage src) + { + if (!SanitizeLayers(dest, src)) return; + + for (int i = 0; i < dest.Red.Length; i++) + { + dest.Red[i] = (byte)((dest.Red[i] * src.Alpha[i]) >> 8); + dest.Green[i] = (byte)((dest.Green[i] * src.Alpha[i]) >> 8); + dest.Blue[i] = (byte)((dest.Blue[i] * src.Alpha[i]) >> 8); + } + } + + private void ApplyTint(ManagedImage dest, Color4 src) + { + if (dest == null) return; + + for (int i = 0; i < dest.Red.Length; i++) + { + dest.Red[i] = (byte)((dest.Red[i] * ((byte)(src.R * byte.MaxValue))) >> 8); + dest.Green[i] = (byte)((dest.Green[i] * ((byte)(src.G * byte.MaxValue))) >> 8); + dest.Blue[i] = (byte)((dest.Blue[i] * ((byte)(src.B * byte.MaxValue))) >> 8); + } + } + + /// + /// Fills a baked layer as a solid *appearing* color. The colors are + /// subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from + /// compressing it too far since it seems to cause upload failures if + /// the image is a pure solid color + /// + /// Color of the base of this layer + private void InitBakedLayerColor(Color4 color) + { + InitBakedLayerColor(color.R, color.G, color.B); + } + + /// + /// Fills a baked layer as a solid *appearing* color. The colors are + /// subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from + /// compressing it too far since it seems to cause upload failures if + /// the image is a pure solid color + /// + /// Red value + /// Green value + /// Blue value + private void InitBakedLayerColor(float r, float g, float b) + { + byte rByte = Utils.FloatToByte(r, 0f, 1f); + byte gByte = Utils.FloatToByte(g, 0f, 1f); + byte bByte = Utils.FloatToByte(b, 0f, 1f); + + byte rAlt, gAlt, bAlt; + + rAlt = rByte; + gAlt = gByte; + bAlt = bByte; + + if (rByte < Byte.MaxValue) + rAlt++; + else rAlt--; + + if (gByte < Byte.MaxValue) + gAlt++; + else gAlt--; + + if (bByte < Byte.MaxValue) + bAlt++; + else bAlt--; + + int i = 0; + + byte[] red = bakedTexture.Image.Red; + byte[] green = bakedTexture.Image.Green; + byte[] blue = bakedTexture.Image.Blue; + byte[] alpha = bakedTexture.Image.Alpha; + byte[] bump = bakedTexture.Image.Bump; + + for (int y = 0; y < bakeHeight; y++) + { + for (int x = 0; x < bakeWidth; x++) + { + if (((x ^ y) & 0x10) == 0) + { + red[i] = rAlt; + green[i] = gByte; + blue[i] = bByte; + alpha[i] = Byte.MaxValue; + bump[i] = 0; + } + else + { + red[i] = rByte; + green[i] = gAlt; + blue[i] = bAlt; + alpha[i] = Byte.MaxValue; + bump[i] = 0; + } + + ++i; + } + } + + } + #endregion + } +} \ No newline at end of file diff --git a/OpenMetaverse/Imaging/ManagedImage.cs b/OpenMetaverse/Imaging/ManagedImage.cs new file mode 100644 index 0000000..0b206ed --- /dev/null +++ b/OpenMetaverse/Imaging/ManagedImage.cs @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse.Imaging +{ + public class ManagedImage + { + [Flags] + public enum ImageChannels + { + Gray = 1, + Color = 2, + Alpha = 4, + Bump = 8 + }; + + public enum ImageResizeAlgorithm + { + NearestNeighbor + } + + /// + /// Image width + /// + public int Width; + + /// + /// Image height + /// + public int Height; + + /// + /// Image channel flags + /// + public ImageChannels Channels; + + /// + /// Red channel data + /// + public byte[] Red; + + /// + /// Green channel data + /// + public byte[] Green; + + /// + /// Blue channel data + /// + public byte[] Blue; + + /// + /// Alpha channel data + /// + public byte[] Alpha; + + /// + /// Bump channel data + /// + public byte[] Bump; + + /// + /// Create a new blank image + /// + /// width + /// height + /// channel flags + public ManagedImage(int width, int height, ImageChannels channels) + { + Width = width; + Height = height; + Channels = channels; + + int n = width * height; + + if ((channels & ImageChannels.Gray) != 0) + { + Red = new byte[n]; + } + else if ((channels & ImageChannels.Color) != 0) + { + Red = new byte[n]; + Green = new byte[n]; + Blue = new byte[n]; + } + + if ((channels & ImageChannels.Alpha) != 0) + Alpha = new byte[n]; + + if ((channels & ImageChannels.Bump) != 0) + Bump = new byte[n]; + } + +#if !NO_UNSAFE + /// + /// + /// + /// + public ManagedImage(System.Drawing.Bitmap bitmap) + { + Width = bitmap.Width; + Height = bitmap.Height; + + int pixelCount = Width * Height; + + if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb) + { + Channels = ImageChannels.Alpha | ImageChannels.Color; + Red = new byte[pixelCount]; + Green = new byte[pixelCount]; + Blue = new byte[pixelCount]; + Alpha = new byte[pixelCount]; + + System.Drawing.Imaging.BitmapData bd = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height), + System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + unsafe + { + byte* pixel = (byte*)bd.Scan0; + + for (int i = 0; i < pixelCount; i++) + { + // GDI+ gives us BGRA and we need to turn that in to RGBA + Blue[i] = *(pixel++); + Green[i] = *(pixel++); + Red[i] = *(pixel++); + Alpha[i] = *(pixel++); + } + } + + bitmap.UnlockBits(bd); + } + else if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format16bppGrayScale) + { + Channels = ImageChannels.Gray; + Red = new byte[pixelCount]; + + throw new NotImplementedException("16bpp grayscale image support is incomplete"); + } + else if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb) + { + Channels = ImageChannels.Color; + Red = new byte[pixelCount]; + Green = new byte[pixelCount]; + Blue = new byte[pixelCount]; + + System.Drawing.Imaging.BitmapData bd = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height), + System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); + + unsafe + { + byte* pixel = (byte*)bd.Scan0; + + for (int i = 0; i < pixelCount; i++) + { + // GDI+ gives us BGR and we need to turn that in to RGB + Blue[i] = *(pixel++); + Green[i] = *(pixel++); + Red[i] = *(pixel++); + } + } + + bitmap.UnlockBits(bd); + } + else if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppRgb) + { + Channels = ImageChannels.Color; + Red = new byte[pixelCount]; + Green = new byte[pixelCount]; + Blue = new byte[pixelCount]; + + System.Drawing.Imaging.BitmapData bd = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height), + System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb); + + unsafe + { + byte* pixel = (byte*)bd.Scan0; + + for (int i = 0; i < pixelCount; i++) + { + // GDI+ gives us BGR and we need to turn that in to RGB + Blue[i] = *(pixel++); + Green[i] = *(pixel++); + Red[i] = *(pixel++); + pixel++; // Skip over the empty byte where the Alpha info would normally be + } + } + + bitmap.UnlockBits(bd); + } + else + { + throw new NotSupportedException("Unrecognized pixel format: " + bitmap.PixelFormat.ToString()); + } + } +#endif + + /// + /// Convert the channels in the image. Channels are created or destroyed as required. + /// + /// new channel flags + public void ConvertChannels(ImageChannels channels) + { + if (Channels == channels) + return; + + int n = Width * Height; + ImageChannels add = Channels ^ channels & channels; + ImageChannels del = Channels ^ channels & Channels; + + if ((add & ImageChannels.Color) != 0) + { + Red = new byte[n]; + Green = new byte[n]; + Blue = new byte[n]; + } + else if ((del & ImageChannels.Color) != 0) + { + Red = null; + Green = null; + Blue = null; + } + + if ((add & ImageChannels.Alpha) != 0) + { + Alpha = new byte[n]; + FillArray(Alpha, 255); + } + else if ((del & ImageChannels.Alpha) != 0) + Alpha = null; + + if ((add & ImageChannels.Bump) != 0) + Bump = new byte[n]; + else if ((del & ImageChannels.Bump) != 0) + Bump = null; + + Channels = channels; + } + + /// + /// Resize or stretch the image using nearest neighbor (ugly) resampling + /// + /// new width + /// new height + public void ResizeNearestNeighbor(int width, int height) + { + if (width == Width && height == Height) + return; + + byte[] + red = null, + green = null, + blue = null, + alpha = null, + bump = null; + int n = width * height; + int di = 0, si; + + if (Red != null) red = new byte[n]; + if (Green != null) green = new byte[n]; + if (Blue != null) blue = new byte[n]; + if (Alpha != null) alpha = new byte[n]; + if (Bump != null) bump = new byte[n]; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + si = (y * Height / height) * Width + (x * Width / width); + if (Red != null) red[di] = Red[si]; + if (Green != null) green[di] = Green[si]; + if (Blue != null) blue[di] = Blue[si]; + if (Alpha != null) alpha[di] = Alpha[si]; + if (Bump != null) bump[di] = Bump[si]; + di++; + } + } + + Width = width; + Height = height; + Red = red; + Green = green; + Blue = blue; + Alpha = alpha; + Bump = bump; + } + + /// + /// Create a byte array containing 32-bit RGBA data with a bottom-left + /// origin, suitable for feeding directly into OpenGL + /// + /// A byte array containing raw texture data + public byte[] ExportRaw() + { + byte[] raw = new byte[Width * Height * 4]; + + if ((Channels & ImageChannels.Alpha) != 0) + { + if ((Channels & ImageChannels.Color) != 0) + { + // RGBA + for (int h = 0; h < Height; h++) + { + for (int w = 0; w < Width; w++) + { + int pos = (Height - 1 - h) * Width + w; + int srcPos = h * Width + w; + + raw[pos * 4 + 0] = Red[srcPos]; + raw[pos * 4 + 1] = Green[srcPos]; + raw[pos * 4 + 2] = Blue[srcPos]; + raw[pos * 4 + 3] = Alpha[srcPos]; + } + } + } + else + { + // Alpha only + for (int h = 0; h < Height; h++) + { + for (int w = 0; w < Width; w++) + { + int pos = (Height - 1 - h) * Width + w; + int srcPos = h * Width + w; + + raw[pos * 4 + 0] = Alpha[srcPos]; + raw[pos * 4 + 1] = Alpha[srcPos]; + raw[pos * 4 + 2] = Alpha[srcPos]; + raw[pos * 4 + 3] = Byte.MaxValue; + } + } + } + } + else + { + // RGB + for (int h = 0; h < Height; h++) + { + for (int w = 0; w < Width; w++) + { + int pos = (Height - 1 - h) * Width + w; + int srcPos = h * Width + w; + + raw[pos * 4 + 0] = Red[srcPos]; + raw[pos * 4 + 1] = Green[srcPos]; + raw[pos * 4 + 2] = Blue[srcPos]; + raw[pos * 4 + 3] = Byte.MaxValue; + } + } + } + + return raw; + } + + /// + /// Create a byte array containing 32-bit RGBA data with a bottom-left + /// origin, suitable for feeding directly into OpenGL + /// + /// A byte array containing raw texture data + public System.Drawing.Bitmap ExportBitmap() + { + byte[] raw = new byte[Width * Height * 4]; + + if ((Channels & ImageChannels.Alpha) != 0) + { + if ((Channels & ImageChannels.Color) != 0) + { + // RGBA + for (int pos = 0; pos < Height * Width; pos++) + { + raw[pos * 4 + 0] = Blue[pos]; + raw[pos * 4 + 1] = Green[pos]; + raw[pos * 4 + 2] = Red[pos]; + raw[pos * 4 + 3] = Alpha[pos]; + } + } + else + { + // Alpha only + for (int pos = 0; pos < Height * Width; pos++) + { + raw[pos * 4 + 0] = Alpha[pos]; + raw[pos * 4 + 1] = Alpha[pos]; + raw[pos * 4 + 2] = Alpha[pos]; + raw[pos * 4 + 3] = Byte.MaxValue; + } + } + } + else + { + // RGB + for (int pos = 0; pos < Height * Width; pos++) + { + raw[pos * 4 + 0] = Blue[pos]; + raw[pos * 4 + 1] = Green[pos]; + raw[pos * 4 + 2] = Red[pos]; + raw[pos * 4 + 3] = Byte.MaxValue; + } + } + + System.Drawing.Bitmap b = new System.Drawing.Bitmap( + Width, + Height, + System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + System.Drawing.Imaging.BitmapData bd = b.LockBits(new System.Drawing.Rectangle(0, 0, b.Width, b.Height), + System.Drawing.Imaging.ImageLockMode.WriteOnly, + System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + System.Runtime.InteropServices.Marshal.Copy(raw, 0, bd.Scan0, Width * Height * 4); + + b.UnlockBits(bd); + + return b; + } + + public byte[] ExportTGA() + { + byte[] tga = new byte[Width * Height * ((Channels & ImageChannels.Alpha) == 0 ? 3 : 4) + 32]; + int di = 0; + tga[di++] = 0; // idlength + tga[di++] = 0; // colormaptype = 0: no colormap + tga[di++] = 2; // image type = 2: uncompressed RGB + tga[di++] = 0; // color map spec is five zeroes for no color map + tga[di++] = 0; // color map spec is five zeroes for no color map + tga[di++] = 0; // color map spec is five zeroes for no color map + tga[di++] = 0; // color map spec is five zeroes for no color map + tga[di++] = 0; // color map spec is five zeroes for no color map + tga[di++] = 0; // x origin = two bytes + tga[di++] = 0; // x origin = two bytes + tga[di++] = 0; // y origin = two bytes + tga[di++] = 0; // y origin = two bytes + tga[di++] = (byte)(Width & 0xFF); // width - low byte + tga[di++] = (byte)(Width >> 8); // width - hi byte + tga[di++] = (byte)(Height & 0xFF); // height - low byte + tga[di++] = (byte)(Height >> 8); // height - hi byte + tga[di++] = (byte)((Channels & ImageChannels.Alpha) == 0 ? 24 : 32); // 24/32 bits per pixel + tga[di++] = (byte)((Channels & ImageChannels.Alpha) == 0 ? 32 : 40); // image descriptor byte + + int n = Width * Height; + + if ((Channels & ImageChannels.Alpha) != 0) + { + if ((Channels & ImageChannels.Color) != 0) + { + // RGBA + for (int i = 0; i < n; i++) + { + tga[di++] = Blue[i]; + tga[di++] = Green[i]; + tga[di++] = Red[i]; + tga[di++] = Alpha[i]; + } + } + else + { + // Alpha only + for (int i = 0; i < n; i++) + { + tga[di++] = Alpha[i]; + tga[di++] = Alpha[i]; + tga[di++] = Alpha[i]; + tga[di++] = Byte.MaxValue; + } + } + } + else + { + // RGB + for (int i = 0; i < n; i++) + { + tga[di++] = Blue[i]; + tga[di++] = Green[i]; + tga[di++] = Red[i]; + } + } + + return tga; + } + + private static void FillArray(byte[] array, byte value) + { + if (array != null) + { + for (int i = 0; i < array.Length; i++) + array[i] = value; + } + } + + public void Clear() + { + FillArray(Red, 0); + FillArray(Green, 0); + FillArray(Blue, 0); + FillArray(Alpha, 0); + FillArray(Bump, 0); + } + + public ManagedImage Clone() + { + ManagedImage image = new ManagedImage(Width, Height, Channels); + if (Red != null) image.Red = (byte[])Red.Clone(); + if (Green != null) image.Green = (byte[])Green.Clone(); + if (Blue != null) image.Blue = (byte[])Blue.Clone(); + if (Alpha != null) image.Alpha = (byte[])Alpha.Clone(); + if (Bump != null) image.Bump = (byte[])Bump.Clone(); + return image; + } + } +} diff --git a/OpenMetaverse/Imaging/OpenJPEG.cs b/OpenMetaverse/Imaging/OpenJPEG.cs new file mode 100644 index 0000000..862c5eb --- /dev/null +++ b/OpenMetaverse/Imaging/OpenJPEG.cs @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; + +namespace OpenMetaverse.Imaging +{ +#if !NO_UNSAFE + /// + /// A Wrapper around openjpeg to encode and decode images to and from byte arrays + /// + public class OpenJPEG + { + /// TGA Header size + public const int TGA_HEADER_SIZE = 32; + + #region JPEG2000 Structs + + /// + /// Defines the beginning and ending file positions of a layer in an + /// LRCP-progression JPEG2000 file + /// + [System.Diagnostics.DebuggerDisplay("Start = {Start} End = {End} Size = {End - Start}")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct J2KLayerInfo + { + public int Start; + public int End; + } + + /// + /// This structure is used to marshal both encoded and decoded images. + /// MUST MATCH THE STRUCT IN dotnet.h! + /// + [StructLayout(LayoutKind.Sequential, Pack = 4)] + private struct MarshalledImage + { + public IntPtr encoded; // encoded image data + public int length; // encoded image length + public int dummy; // padding for 64-bit alignment + + public IntPtr decoded; // decoded image, contiguous components + + public int width; // width of decoded image + public int height; // height of decoded image + public int layers; // layer count + public int resolutions; // resolution count + public int components; // component count + public int packet_count; // packet count + public IntPtr packets; // pointer to the packets array + } + + /// + /// Information about a single packet in a JPEG2000 stream + /// + [StructLayout(LayoutKind.Sequential, Pack = 4)] + private struct MarshalledPacket + { + /// Packet start position + public int start_pos; + /// Packet header end position + public int end_ph_pos; + /// Packet end position + public int end_pos; + + public override string ToString() + { + return String.Format("start_pos: {0} end_ph_pos: {1} end_pos: {2}", + start_pos, end_ph_pos, end_pos); + } + } + + #endregion JPEG2000 Structs + + #region Unmanaged Function Declarations + + + // allocate encoded buffer based on length field + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetAllocEncoded(ref MarshalledImage image); + + // allocate decoded buffer based on width and height fields + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetAllocDecoded(ref MarshalledImage image); + + // free buffers + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetFree(ref MarshalledImage image); + + // encode raw to jpeg2000 + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetEncode(ref MarshalledImage image, bool lossless); + + // decode jpeg2000 to raw + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetDecode(ref MarshalledImage image); + + // decode jpeg2000 to raw, get jpeg2000 file info + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetDecodeWithInfo(ref MarshalledImage image); + + // invoke 64 bit openjpeg calls + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetAllocEncoded64(ref MarshalledImage image); + + // allocate decoded buffer based on width and height fields + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetAllocDecoded64(ref MarshalledImage image); + + // free buffers + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetFree64(ref MarshalledImage image); + + // encode raw to jpeg2000 + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetEncode64(ref MarshalledImage image, bool lossless); + + // decode jpeg2000 to raw + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetDecode64(ref MarshalledImage image); + + // decode jpeg2000 to raw, get jpeg2000 file info + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern bool DotNetDecodeWithInfo64(ref MarshalledImage image); + #endregion Unmanaged Function Declarations + + /// OpenJPEG is not threadsafe, so this object is used to lock + /// during calls into unmanaged code + private static object OpenJPEGLock = new object(); + + /// + /// Encode a object into a byte array + /// + /// The object to encode + /// true to enable lossless conversion, only useful for small images ie: sculptmaps + /// A byte array containing the encoded Image object + public static byte[] Encode(ManagedImage image, bool lossless) + { + if ((image.Channels & ManagedImage.ImageChannels.Color) == 0 || + ((image.Channels & ManagedImage.ImageChannels.Bump) != 0 && (image.Channels & ManagedImage.ImageChannels.Alpha) == 0)) + throw new ArgumentException("JPEG2000 encoding is not supported for this channel combination"); + + byte[] encoded = null; + MarshalledImage marshalled = new MarshalledImage(); + + // allocate and copy to input buffer + marshalled.width = image.Width; + marshalled.height = image.Height; + marshalled.components = 3; + if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) marshalled.components++; + if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) marshalled.components++; + + lock (OpenJPEGLock) + { + + bool allocSuccess = (IntPtr.Size == 8) ? DotNetAllocDecoded64(ref marshalled) : DotNetAllocDecoded(ref marshalled); + + if (!allocSuccess) + throw new Exception("DotNetAllocDecoded failed"); + + int n = image.Width * image.Height; + + if ((image.Channels & ManagedImage.ImageChannels.Color) != 0) + { + Marshal.Copy(image.Red, 0, marshalled.decoded, n); + Marshal.Copy(image.Green, 0, (IntPtr)(marshalled.decoded.ToInt64() + n), n); + Marshal.Copy(image.Blue, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 2), n); + } + + if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) Marshal.Copy(image.Alpha, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 3), n); + if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) Marshal.Copy(image.Bump, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 4), n); + + // codec will allocate output buffer + bool encodeSuccess = (IntPtr.Size == 8) ? DotNetEncode64(ref marshalled, lossless) : DotNetEncode(ref marshalled, lossless); + if (!encodeSuccess) + throw new Exception("DotNetEncode failed"); + + // copy output buffer + encoded = new byte[marshalled.length]; + Marshal.Copy(marshalled.encoded, encoded, 0, marshalled.length); + + // free buffers + if (IntPtr.Size == 8) + DotNetFree64(ref marshalled); + else + DotNetFree(ref marshalled); + } + + return encoded; + } + + /// + /// Encode a object into a byte array + /// + /// The object to encode + /// a byte array of the encoded image + public static byte[] Encode(ManagedImage image) + { + return Encode(image, false); + } + + /// + /// Decode JPEG2000 data to an and + /// + /// + /// JPEG2000 encoded data + /// ManagedImage object to decode to + /// Image object to decode to + /// True if the decode succeeds, otherwise false + public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage, out Image image) + { + managedImage = null; + image = null; + + if (DecodeToImage(encoded, out managedImage)) + { + try + { + image = managedImage.ExportBitmap(); + return true; + } + catch (Exception ex) + { + Logger.Log("Failed to export and load TGA data from decoded image", Helpers.LogLevel.Error, ex); + return false; + } + } + else + { + return false; + } + } + + /// + /// + /// + /// + /// + /// + public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage) + { + MarshalledImage marshalled = new MarshalledImage(); + + // Allocate and copy to input buffer + marshalled.length = encoded.Length; + + lock (OpenJPEGLock) + { + if (IntPtr.Size == 8) + DotNetAllocEncoded64(ref marshalled); + else + DotNetAllocEncoded(ref marshalled); + + Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length); + + // Codec will allocate output buffer + if (IntPtr.Size == 8) + DotNetDecode64(ref marshalled); + else + DotNetDecode(ref marshalled); + + int n = marshalled.width * marshalled.height; + + switch (marshalled.components) + { + case 1: // Grayscale + managedImage = new ManagedImage(marshalled.width, marshalled.height, + ManagedImage.ImageChannels.Color); + Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); + Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n); + Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n); + break; + + case 2: // Grayscale + alpha + managedImage = new ManagedImage(marshalled.width, marshalled.height, + ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); + Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); + Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n); + Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Alpha, 0, n); + break; + + case 3: // RGB + managedImage = new ManagedImage(marshalled.width, marshalled.height, + ManagedImage.ImageChannels.Color); + Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); + break; + + case 4: // RGBA + managedImage = new ManagedImage(marshalled.width, marshalled.height, + ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); + Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Alpha, 0, n); + break; + + case 5: // RGBAB + managedImage = new ManagedImage(marshalled.width, marshalled.height, + ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump); + Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Alpha, 0, n); + Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 4)), managedImage.Bump, 0, n); + break; + + default: + Logger.Log("Decoded image with unhandled number of components: " + marshalled.components, + Helpers.LogLevel.Error); + + if (IntPtr.Size == 8) + DotNetFree64(ref marshalled); + else + DotNetFree(ref marshalled); + + managedImage = null; + return false; + } + + if (IntPtr.Size == 8) + DotNetFree64(ref marshalled); + else + DotNetFree(ref marshalled); + } + + return true; + } + + /// + /// + /// + /// + /// + /// + /// + public static bool DecodeLayerBoundaries(byte[] encoded, out J2KLayerInfo[] layerInfo, out int components) + { + bool success = false; + layerInfo = null; + components = 0; + MarshalledImage marshalled = new MarshalledImage(); + + // Allocate and copy to input buffer + marshalled.length = encoded.Length; + + lock (OpenJPEGLock) + { + if (IntPtr.Size == 8) + DotNetAllocEncoded64(ref marshalled); + else + DotNetAllocEncoded(ref marshalled); + + Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length); + + // Run the decode + bool decodeSuccess = (IntPtr.Size == 8) ? DotNetDecodeWithInfo64(ref marshalled) : DotNetDecodeWithInfo(ref marshalled); + if (decodeSuccess) + { + components = marshalled.components; + + // Sanity check + if (marshalled.layers * marshalled.resolutions * marshalled.components == marshalled.packet_count) + { + // Manually marshal the array of opj_packet_info structs + MarshalledPacket[] packets = new MarshalledPacket[marshalled.packet_count]; + int offset = 0; + + for (int i = 0; i < marshalled.packet_count; i++) + { + MarshalledPacket packet; + packet.start_pos = Marshal.ReadInt32(marshalled.packets, offset); + offset += 4; + packet.end_ph_pos = Marshal.ReadInt32(marshalled.packets, offset); + offset += 4; + packet.end_pos = Marshal.ReadInt32(marshalled.packets, offset); + offset += 4; + //double distortion = (double)Marshal.ReadInt64(marshalled.packets, offset); + offset += 8; + + packets[i] = packet; + } + + layerInfo = new J2KLayerInfo[marshalled.layers]; + + for (int i = 0; i < marshalled.layers; i++) + { + int packetsPerLayer = marshalled.packet_count / marshalled.layers; + MarshalledPacket startPacket = packets[packetsPerLayer * i]; + MarshalledPacket endPacket = packets[(packetsPerLayer * (i + 1)) - 1]; + layerInfo[i].Start = startPacket.start_pos; + layerInfo[i].End = endPacket.end_pos; + } + + // More sanity checking + if (layerInfo.Length == 0 || layerInfo[layerInfo.Length - 1].End <= encoded.Length - 1) + { + success = true; + + for (int i = 0; i < layerInfo.Length; i++) + { + if (layerInfo[i].Start >= layerInfo[i].End || + (i > 0 && layerInfo[i].Start <= layerInfo[i - 1].End)) + { + System.Text.StringBuilder output = new System.Text.StringBuilder( + "Inconsistent packet data in JPEG2000 stream:\n"); + for (int j = 0; j < layerInfo.Length; j++) + output.AppendFormat("Layer {0}: Start: {1} End: {2}\n", j, layerInfo[j].Start, layerInfo[j].End); + Logger.DebugLog(output.ToString()); + + success = false; + break; + } + } + + if (!success) + { + for (int i = 0; i < layerInfo.Length; i++) + { + if (i < layerInfo.Length - 1) + layerInfo[i].End = layerInfo[i + 1].Start - 1; + else + layerInfo[i].End = marshalled.length; + } + + Logger.DebugLog("Corrected JPEG2000 packet data"); + success = true; + + for (int i = 0; i < layerInfo.Length; i++) + { + if (layerInfo[i].Start >= layerInfo[i].End || + (i > 0 && layerInfo[i].Start <= layerInfo[i - 1].End)) + { + System.Text.StringBuilder output = new System.Text.StringBuilder( + "Still inconsistent packet data in JPEG2000 stream, giving up:\n"); + for (int j = 0; j < layerInfo.Length; j++) + output.AppendFormat("Layer {0}: Start: {1} End: {2}\n", j, layerInfo[j].Start, layerInfo[j].End); + Logger.DebugLog(output.ToString()); + + success = false; + break; + } + } + } + } + else + { + Logger.Log(String.Format( + "Last packet end in JPEG2000 stream extends beyond the end of the file. filesize={0} layerend={1}", + encoded.Length, layerInfo[layerInfo.Length - 1].End), Helpers.LogLevel.Warning); + } + } + else + { + Logger.Log(String.Format( + "Packet count mismatch in JPEG2000 stream. layers={0} resolutions={1} components={2} packets={3}", + marshalled.layers, marshalled.resolutions, marshalled.components, marshalled.packet_count), + Helpers.LogLevel.Warning); + } + } + + if (IntPtr.Size == 8) + DotNetFree64(ref marshalled); + else + DotNetFree(ref marshalled); + } + + return success; + } + + /// + /// Encode a object into a byte array + /// + /// The source object to encode + /// true to enable lossless decoding + /// A byte array containing the source Bitmap object + public unsafe static byte[] EncodeFromImage(Bitmap bitmap, bool lossless) + { + BitmapData bd; + ManagedImage decoded; + + int bitmapWidth = bitmap.Width; + int bitmapHeight = bitmap.Height; + int pixelCount = bitmapWidth * bitmapHeight; + int i; + + if ((bitmap.PixelFormat & PixelFormat.Alpha) != 0 || (bitmap.PixelFormat & PixelFormat.PAlpha) != 0) + { + // Four layers, RGBA + decoded = new ManagedImage(bitmapWidth, bitmapHeight, + ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); + bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), + ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + byte* pixel = (byte*)bd.Scan0; + + for (i = 0; i < pixelCount; i++) + { + // GDI+ gives us BGRA and we need to turn that in to RGBA + decoded.Blue[i] = *(pixel++); + decoded.Green[i] = *(pixel++); + decoded.Red[i] = *(pixel++); + decoded.Alpha[i] = *(pixel++); + } + } + else if (bitmap.PixelFormat == PixelFormat.Format16bppGrayScale) + { + // One layer + decoded = new ManagedImage(bitmapWidth, bitmapHeight, + ManagedImage.ImageChannels.Color); + bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), + ImageLockMode.ReadOnly, PixelFormat.Format16bppGrayScale); + byte* pixel = (byte*)bd.Scan0; + + for (i = 0; i < pixelCount; i++) + { + // Normalize 16-bit data down to 8-bit + ushort origVal = (byte)(*(pixel) + (*(pixel + 1) << 8)); + byte val = (byte)(((double)origVal / (double)UInt32.MaxValue) * (double)Byte.MaxValue); + + decoded.Red[i] = val; + decoded.Green[i] = val; + decoded.Blue[i] = val; + pixel += 2; + } + } + else + { + // Three layers, RGB + decoded = new ManagedImage(bitmapWidth, bitmapHeight, + ManagedImage.ImageChannels.Color); + bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), + ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); + byte* pixel = (byte*)bd.Scan0; + + for (i = 0; i < pixelCount; i++) + { + decoded.Blue[i] = *(pixel++); + decoded.Green[i] = *(pixel++); + decoded.Red[i] = *(pixel++); + } + } + + bitmap.UnlockBits(bd); + byte[] encoded = Encode(decoded, lossless); + return encoded; + } + } +#endif +} diff --git a/OpenMetaverse/Imaging/TGALoader.cs b/OpenMetaverse/Imaging/TGALoader.cs new file mode 100644 index 0000000..b4c1ea6 --- /dev/null +++ b/OpenMetaverse/Imaging/TGALoader.cs @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse.Imaging +{ +#if !NO_UNSAFE + + /// + /// Capability to load TGAs to Bitmap + /// + public class LoadTGAClass + { + struct tgaColorMap + { + public ushort FirstEntryIndex; + public ushort Length; + public byte EntrySize; + + public void Read(System.IO.BinaryReader br) + { + FirstEntryIndex = br.ReadUInt16(); + Length = br.ReadUInt16(); + EntrySize = br.ReadByte(); + } + } + + struct tgaImageSpec + { + public ushort XOrigin; + public ushort YOrigin; + public ushort Width; + public ushort Height; + public byte PixelDepth; + public byte Descriptor; + + public void Read(System.IO.BinaryReader br) + { + XOrigin = br.ReadUInt16(); + YOrigin = br.ReadUInt16(); + Width = br.ReadUInt16(); + Height = br.ReadUInt16(); + PixelDepth = br.ReadByte(); + Descriptor = br.ReadByte(); + } + + public byte AlphaBits + { + get + { + return (byte)(Descriptor & 0xF); + } + set + { + Descriptor = (byte)((Descriptor & ~0xF) | (value & 0xF)); + } + } + + public bool BottomUp + { + get + { + return (Descriptor & 0x20) == 0x20; + } + set + { + Descriptor = (byte)((Descriptor & ~0x20) | (value ? 0x20 : 0)); + } + } + } + + struct tgaHeader + { + public byte IdLength; + public byte ColorMapType; + public byte ImageType; + + public tgaColorMap ColorMap; + public tgaImageSpec ImageSpec; + + public void Read(System.IO.BinaryReader br) + { + this.IdLength = br.ReadByte(); + this.ColorMapType = br.ReadByte(); + this.ImageType = br.ReadByte(); + this.ColorMap = new tgaColorMap(); + this.ImageSpec = new tgaImageSpec(); + this.ColorMap.Read(br); + this.ImageSpec.Read(br); + } + + public bool RleEncoded + { + get + { + return ImageType >= 9; + } + } + } + + struct tgaCD + { + public uint RMask, GMask, BMask, AMask; + public byte RShift, GShift, BShift, AShift; + public uint FinalOr; + public bool NeedNoConvert; + } + + static uint UnpackColor( + uint sourceColor, ref tgaCD cd) + { + if (cd.RMask == 0xFF && cd.GMask == 0xFF && cd.BMask == 0xFF) + { + // Special case to deal with 8-bit TGA files that we treat as alpha masks + return sourceColor << 24; + } + else + { + uint rpermute = (sourceColor << cd.RShift) | (sourceColor >> (32 - cd.RShift)); + uint gpermute = (sourceColor << cd.GShift) | (sourceColor >> (32 - cd.GShift)); + uint bpermute = (sourceColor << cd.BShift) | (sourceColor >> (32 - cd.BShift)); + uint apermute = (sourceColor << cd.AShift) | (sourceColor >> (32 - cd.AShift)); + uint result = + (rpermute & cd.RMask) | (gpermute & cd.GMask) + | (bpermute & cd.BMask) | (apermute & cd.AMask) | cd.FinalOr; + + return result; + } + } + + static unsafe void decodeLine( + System.Drawing.Imaging.BitmapData b, + int line, + int byp, + byte[] data, + ref tgaCD cd) + { + if (cd.NeedNoConvert) + { + // fast copy + uint* linep = (uint*)((byte*)b.Scan0.ToPointer() + line * b.Stride); + fixed (byte* ptr = data) + { + uint* sptr = (uint*)ptr; + for (int i = 0; i < b.Width; ++i) + { + linep[i] = sptr[i]; + } + } + } + else + { + byte* linep = (byte*)b.Scan0.ToPointer() + line * b.Stride; + + uint* up = (uint*)linep; + + int rdi = 0; + + fixed (byte* ptr = data) + { + for (int i = 0; i < b.Width; ++i) + { + uint x = 0; + for (int j = 0; j < byp; ++j) + { + x |= ((uint)ptr[rdi]) << (j << 3); + ++rdi; + } + up[i] = UnpackColor(x, ref cd); + } + } + } + } + + static void decodeRle( + System.Drawing.Imaging.BitmapData b, + int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) + { + try + { + int w = b.Width; + // make buffer larger, so in case of emergency I can decode + // over line ends. + byte[] linebuffer = new byte[(w + 128) * byp]; + int maxindex = w * byp; + int index = 0; + + for (int j = 0; j < b.Height; ++j) + { + while (index < maxindex) + { + byte blocktype = br.ReadByte(); + + int bytestoread; + int bytestocopy; + + if (blocktype >= 0x80) + { + bytestoread = byp; + bytestocopy = byp * (blocktype - 0x80); + } + else + { + bytestoread = byp * (blocktype + 1); + bytestocopy = 0; + } + + //if (index + bytestoread > maxindex) + // throw new System.ArgumentException ("Corrupt TGA"); + + br.Read(linebuffer, index, bytestoread); + index += bytestoread; + + for (int i = 0; i != bytestocopy; ++i) + { + linebuffer[index + i] = linebuffer[index + i - bytestoread]; + } + index += bytestocopy; + } + if (!bottomUp) + decodeLine(b, b.Height - j - 1, byp, linebuffer, ref cd); + else + decodeLine(b, j, byp, linebuffer, ref cd); + + if (index > maxindex) + { + Array.Copy(linebuffer, maxindex, linebuffer, 0, index - maxindex); + index -= maxindex; + } + else + index = 0; + + } + } + catch (System.IO.EndOfStreamException) + { + } + } + + static void decodePlain( + System.Drawing.Imaging.BitmapData b, + int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) + { + int w = b.Width; + byte[] linebuffer = new byte[w * byp]; + + for (int j = 0; j < b.Height; ++j) + { + br.Read(linebuffer, 0, w * byp); + + if (!bottomUp) + decodeLine(b, b.Height - j - 1, byp, linebuffer, ref cd); + else + decodeLine(b, j, byp, linebuffer, ref cd); + } + } + + static void decodeStandard8( + System.Drawing.Imaging.BitmapData b, + tgaHeader hdr, + System.IO.BinaryReader br) + { + tgaCD cd = new tgaCD(); + cd.RMask = 0x000000ff; + cd.GMask = 0x000000ff; + cd.BMask = 0x000000ff; + cd.AMask = 0x000000ff; + cd.RShift = 0; + cd.GShift = 0; + cd.BShift = 0; + cd.AShift = 0; + cd.FinalOr = 0x00000000; + if (hdr.RleEncoded) + decodeRle(b, 1, cd, br, hdr.ImageSpec.BottomUp); + else + decodePlain(b, 1, cd, br, hdr.ImageSpec.BottomUp); + } + + static void decodeSpecial16( + System.Drawing.Imaging.BitmapData b, tgaHeader hdr, System.IO.BinaryReader br) + { + // i must convert the input stream to a sequence of uint values + // which I then unpack. + tgaCD cd = new tgaCD(); + cd.RMask = 0x00f00000; + cd.GMask = 0x0000f000; + cd.BMask = 0x000000f0; + cd.AMask = 0xf0000000; + cd.RShift = 12; + cd.GShift = 8; + cd.BShift = 4; + cd.AShift = 16; + cd.FinalOr = 0; + + if (hdr.RleEncoded) + decodeRle(b, 2, cd, br, hdr.ImageSpec.BottomUp); + else + decodePlain(b, 2, cd, br, hdr.ImageSpec.BottomUp); + } + + static void decodeStandard16( + System.Drawing.Imaging.BitmapData b, + tgaHeader hdr, + System.IO.BinaryReader br) + { + // i must convert the input stream to a sequence of uint values + // which I then unpack. + tgaCD cd = new tgaCD(); + cd.RMask = 0x00f80000; // from 0xF800 + cd.GMask = 0x0000fc00; // from 0x07E0 + cd.BMask = 0x000000f8; // from 0x001F + cd.AMask = 0x00000000; + cd.RShift = 8; + cd.GShift = 5; + cd.BShift = 3; + cd.AShift = 0; + cd.FinalOr = 0xff000000; + + if (hdr.RleEncoded) + decodeRle(b, 2, cd, br, hdr.ImageSpec.BottomUp); + else + decodePlain(b, 2, cd, br, hdr.ImageSpec.BottomUp); + } + + + static void decodeSpecial24(System.Drawing.Imaging.BitmapData b, + tgaHeader hdr, System.IO.BinaryReader br) + { + // i must convert the input stream to a sequence of uint values + // which I then unpack. + tgaCD cd = new tgaCD(); + cd.RMask = 0x00f80000; + cd.GMask = 0x0000fc00; + cd.BMask = 0x000000f8; + cd.AMask = 0xff000000; + cd.RShift = 8; + cd.GShift = 5; + cd.BShift = 3; + cd.AShift = 8; + cd.FinalOr = 0; + + if (hdr.RleEncoded) + decodeRle(b, 3, cd, br, hdr.ImageSpec.BottomUp); + else + decodePlain(b, 3, cd, br, hdr.ImageSpec.BottomUp); + } + + static void decodeStandard24(System.Drawing.Imaging.BitmapData b, + tgaHeader hdr, System.IO.BinaryReader br) + { + // i must convert the input stream to a sequence of uint values + // which I then unpack. + tgaCD cd = new tgaCD(); + cd.RMask = 0x00ff0000; + cd.GMask = 0x0000ff00; + cd.BMask = 0x000000ff; + cd.AMask = 0x00000000; + cd.RShift = 0; + cd.GShift = 0; + cd.BShift = 0; + cd.AShift = 0; + cd.FinalOr = 0xff000000; + + if (hdr.RleEncoded) + decodeRle(b, 3, cd, br, hdr.ImageSpec.BottomUp); + else + decodePlain(b, 3, cd, br, hdr.ImageSpec.BottomUp); + } + + static void decodeStandard32(System.Drawing.Imaging.BitmapData b, + tgaHeader hdr, System.IO.BinaryReader br) + { + // i must convert the input stream to a sequence of uint values + // which I then unpack. + tgaCD cd = new tgaCD(); + cd.RMask = 0x00ff0000; + cd.GMask = 0x0000ff00; + cd.BMask = 0x000000ff; + cd.AMask = 0xff000000; + cd.RShift = 0; + cd.GShift = 0; + cd.BShift = 0; + cd.AShift = 0; + cd.FinalOr = 0x00000000; + cd.NeedNoConvert = true; + + if (hdr.RleEncoded) + decodeRle(b, 4, cd, br, hdr.ImageSpec.BottomUp); + else + decodePlain(b, 4, cd, br, hdr.ImageSpec.BottomUp); + } + + + public static System.Drawing.Size GetTGASize(string filename) + { + System.IO.FileStream f = System.IO.File.OpenRead(filename); + + System.IO.BinaryReader br = new System.IO.BinaryReader(f); + + tgaHeader header = new tgaHeader(); + header.Read(br); + br.Close(); + + return new System.Drawing.Size(header.ImageSpec.Width, header.ImageSpec.Height); + + } + + public static System.Drawing.Bitmap LoadTGA(System.IO.Stream source) + { + byte[] buffer = new byte[source.Length]; + source.Read(buffer, 0, buffer.Length); + + System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); + + using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) + { + tgaHeader header = new tgaHeader(); + header.Read(br); + + if (header.ImageSpec.PixelDepth != 8 && + header.ImageSpec.PixelDepth != 16 && + header.ImageSpec.PixelDepth != 24 && + header.ImageSpec.PixelDepth != 32) + throw new ArgumentException("Not a supported tga file."); + + if (header.ImageSpec.AlphaBits > 8) + throw new ArgumentException("Not a supported tga file."); + + if (header.ImageSpec.Width > 4096 || + header.ImageSpec.Height > 4096) + throw new ArgumentException("Image too large."); + + System.Drawing.Bitmap b; + System.Drawing.Imaging.BitmapData bd; + + // Create a bitmap for the image. + // Only include an alpha layer when the image requires one. + if (header.ImageSpec.AlphaBits > 0 || + header.ImageSpec.PixelDepth == 8 || // Assume 8 bit images are alpha only + header.ImageSpec.PixelDepth == 32) // Assume 32 bit images are ARGB + { // Image needs an alpha layer + b = new System.Drawing.Bitmap( + header.ImageSpec.Width, + header.ImageSpec.Height, + System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + bd = b.LockBits(new System.Drawing.Rectangle(0, 0, b.Width, b.Height), + System.Drawing.Imaging.ImageLockMode.WriteOnly, + System.Drawing.Imaging.PixelFormat.Format32bppPArgb); + } + else + { // Image does not need an alpha layer, so do not include one. + b = new System.Drawing.Bitmap( + header.ImageSpec.Width, + header.ImageSpec.Height, + System.Drawing.Imaging.PixelFormat.Format32bppRgb); + + bd = b.LockBits(new System.Drawing.Rectangle(0, 0, b.Width, b.Height), + System.Drawing.Imaging.ImageLockMode.WriteOnly, + System.Drawing.Imaging.PixelFormat.Format32bppRgb); + } + + switch (header.ImageSpec.PixelDepth) + { + case 8: + decodeStandard8(bd, header, br); + break; + case 16: + if (header.ImageSpec.AlphaBits > 0) + decodeSpecial16(bd, header, br); + else + decodeStandard16(bd, header, br); + break; + case 24: + if (header.ImageSpec.AlphaBits > 0) + decodeSpecial24(bd, header, br); + else + decodeStandard24(bd, header, br); + break; + case 32: + decodeStandard32(bd, header, br); + break; + default: + b.UnlockBits(bd); + b.Dispose(); + return null; + } + + b.UnlockBits(bd); + return b; + } + } + + public static unsafe ManagedImage LoadTGAImage(System.IO.Stream source) + { + return LoadTGAImage(source, false); + } + + public static unsafe ManagedImage LoadTGAImage(System.IO.Stream source, bool mask) + { + byte[] buffer = new byte[source.Length]; + source.Read(buffer, 0, buffer.Length); + + System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); + + using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) + { + tgaHeader header = new tgaHeader(); + header.Read(br); + + if (header.ImageSpec.PixelDepth != 8 && + header.ImageSpec.PixelDepth != 16 && + header.ImageSpec.PixelDepth != 24 && + header.ImageSpec.PixelDepth != 32) + throw new ArgumentException("Not a supported tga file."); + + if (header.ImageSpec.AlphaBits > 8) + throw new ArgumentException("Not a supported tga file."); + + if (header.ImageSpec.Width > 4096 || + header.ImageSpec.Height > 4096) + throw new ArgumentException("Image too large."); + + byte[] decoded = new byte[header.ImageSpec.Width * header.ImageSpec.Height * 4]; + System.Drawing.Imaging.BitmapData bd = new System.Drawing.Imaging.BitmapData(); + + fixed (byte* pdecoded = &decoded[0]) + { + bd.Width = header.ImageSpec.Width; + bd.Height = header.ImageSpec.Height; + bd.PixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppPArgb; + bd.Stride = header.ImageSpec.Width * 4; + bd.Scan0 = (IntPtr)pdecoded; + + switch (header.ImageSpec.PixelDepth) + { + case 8: + decodeStandard8(bd, header, br); + break; + case 16: + if (header.ImageSpec.AlphaBits > 0) + decodeSpecial16(bd, header, br); + else + decodeStandard16(bd, header, br); + break; + case 24: + if (header.ImageSpec.AlphaBits > 0) + decodeSpecial24(bd, header, br); + else + decodeStandard24(bd, header, br); + break; + case 32: + decodeStandard32(bd, header, br); + break; + default: + return null; + } + } + + int n = header.ImageSpec.Width * header.ImageSpec.Height; + ManagedImage image; + + if (mask && header.ImageSpec.AlphaBits == 0 && header.ImageSpec.PixelDepth == 8) + { + image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, + ManagedImage.ImageChannels.Alpha); + int p = 3; + + for (int i = 0; i < n; i++) + { + image.Alpha[i] = decoded[p]; + p += 4; + } + } + else + { + image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, + ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); + int p = 0; + + for (int i = 0; i < n; i++) + { + image.Blue[i] = decoded[p++]; + image.Green[i] = decoded[p++]; + image.Red[i] = decoded[p++]; + image.Alpha[i] = decoded[p++]; + } + } + + br.Close(); + return image; + } + } + + public static System.Drawing.Bitmap LoadTGA(string filename) + { + try + { + using (System.IO.FileStream f = System.IO.File.OpenRead(filename)) + { + return LoadTGA(f); + } + } + catch (System.IO.DirectoryNotFoundException) + { + return null; // file not found + } + catch (System.IO.FileNotFoundException) + { + return null; // file not found + } + } + } + +#endif +} diff --git a/OpenMetaverse/ImportExport/Collada.cs b/OpenMetaverse/ImportExport/Collada.cs new file mode 100644 index 0000000..3d5c0e0 --- /dev/null +++ b/OpenMetaverse/ImportExport/Collada.cs @@ -0,0 +1,38315 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// THIS FILE WAS CHANGED IN COMMIT 3a59220 TO RESOLVE A MONO BUG. PLEASE RE-INSERT THOSE CHANGES IF THIS FILE IS +// REGENERATED. + +// +// This source code was auto-generated by xsd, Version=4.0.30319.17929. +// +namespace OpenMetaverse.ImportExport.Collada14 +{ + using System.Xml.Serialization; + using System.Text.RegularExpressions; + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class COLLADA + { + + private asset assetField; + + private object[] itemsField; + + private COLLADAScene sceneField; + + private extra[] extraField; + + private VersionType versionField; + + private string baseField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("library_animation_clips", typeof(library_animation_clips))] + [System.Xml.Serialization.XmlElementAttribute("library_animations", typeof(library_animations))] + [System.Xml.Serialization.XmlElementAttribute("library_cameras", typeof(library_cameras))] + [System.Xml.Serialization.XmlElementAttribute("library_controllers", typeof(library_controllers))] + [System.Xml.Serialization.XmlElementAttribute("library_effects", typeof(library_effects))] + [System.Xml.Serialization.XmlElementAttribute("library_force_fields", typeof(library_force_fields))] + [System.Xml.Serialization.XmlElementAttribute("library_geometries", typeof(library_geometries))] + [System.Xml.Serialization.XmlElementAttribute("library_images", typeof(library_images))] + [System.Xml.Serialization.XmlElementAttribute("library_lights", typeof(library_lights))] + [System.Xml.Serialization.XmlElementAttribute("library_materials", typeof(library_materials))] + [System.Xml.Serialization.XmlElementAttribute("library_nodes", typeof(library_nodes))] + [System.Xml.Serialization.XmlElementAttribute("library_physics_materials", typeof(library_physics_materials))] + [System.Xml.Serialization.XmlElementAttribute("library_physics_models", typeof(library_physics_models))] + [System.Xml.Serialization.XmlElementAttribute("library_physics_scenes", typeof(library_physics_scenes))] + [System.Xml.Serialization.XmlElementAttribute("library_visual_scenes", typeof(library_visual_scenes))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + public COLLADAScene scene + { + get + { + return this.sceneField; + } + set + { + this.sceneField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public VersionType version + { + get + { + return this.versionField; + } + set + { + this.versionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form = System.Xml.Schema.XmlSchemaForm.Qualified, Namespace = "http://www.w3.org/XML/1998/namespace")] + public string @base + { + get + { + return this.baseField; + } + set + { + this.baseField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class asset + { + + private assetContributor[] contributorField; + + private System.DateTime createdField; + + private string keywordsField; + + private System.DateTime modifiedField; + + private string revisionField; + + private string subjectField; + + private string titleField; + + private assetUnit unitField; + + private UpAxisType up_axisField; + + public asset() + { + this.up_axisField = UpAxisType.Y_UP; + } + + /// + [System.Xml.Serialization.XmlElementAttribute("contributor")] + public assetContributor[] contributor + { + get + { + return this.contributorField; + } + set + { + this.contributorField = value; + } + } + + /// + public System.DateTime created + { + get + { + return this.createdField; + } + set + { + this.createdField = value; + } + } + + /// + public string keywords + { + get + { + return this.keywordsField; + } + set + { + this.keywordsField = value; + } + } + + /// + public System.DateTime modified + { + get + { + return this.modifiedField; + } + set + { + this.modifiedField = value; + } + } + + /// + public string revision + { + get + { + return this.revisionField; + } + set + { + this.revisionField = value; + } + } + + /// + public string subject + { + get + { + return this.subjectField; + } + set + { + this.subjectField = value; + } + } + + /// + public string title + { + get + { + return this.titleField; + } + set + { + this.titleField = value; + } + } + + /// + public assetUnit unit + { + get + { + return this.unitField; + } + set + { + this.unitField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(UpAxisType.Y_UP)] + public UpAxisType up_axis + { + get + { + return this.up_axisField; + } + set + { + this.up_axisField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class assetContributor + { + + private string authorField; + + private string authoring_toolField; + + private string commentsField; + + private string copyrightField; + + private string source_dataField; + + /// + public string author + { + get + { + return this.authorField; + } + set + { + this.authorField = value; + } + } + + /// + public string authoring_tool + { + get + { + return this.authoring_toolField; + } + set + { + this.authoring_toolField = value; + } + } + + /// + public string comments + { + get + { + return this.commentsField; + } + set + { + this.commentsField = value; + } + } + + /// + public string copyright + { + get + { + return this.copyrightField; + } + set + { + this.copyrightField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "anyURI")] + public string source_data + { + get + { + return this.source_dataField; + } + set + { + this.source_dataField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_clearstencil_common + { + + private string indexField; + + private sbyte valueField; + + public fx_clearstencil_common() + { + this.indexField = "0"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public sbyte Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_cleardepth_common + { + + private string indexField; + + private double valueField; + + public fx_cleardepth_common() + { + this.indexField = "0"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public double Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_clearcolor_common + { + + private string indexField; + + private double[] textField; + + public fx_clearcolor_common() + { + this.indexField = "0"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_stenciltarget_common + { + + private string indexField; + + private fx_surface_face_enum faceField; + + private string mipField; + + private string sliceField; + + private string valueField; + + public fx_stenciltarget_common() + { + this.indexField = "0"; + this.faceField = fx_surface_face_enum.POSITIVE_X; + this.mipField = "0"; + this.sliceField = "0"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(fx_surface_face_enum.POSITIVE_X)] + public fx_surface_face_enum face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string mip + { + get + { + return this.mipField; + } + set + { + this.mipField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string slice + { + get + { + return this.sliceField; + } + set + { + this.sliceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NCName")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_surface_face_enum + { + + /// + POSITIVE_X, + + /// + NEGATIVE_X, + + /// + POSITIVE_Y, + + /// + NEGATIVE_Y, + + /// + POSITIVE_Z, + + /// + NEGATIVE_Z, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_depthtarget_common + { + + private string indexField; + + private fx_surface_face_enum faceField; + + private string mipField; + + private string sliceField; + + private string valueField; + + public fx_depthtarget_common() + { + this.indexField = "0"; + this.faceField = fx_surface_face_enum.POSITIVE_X; + this.mipField = "0"; + this.sliceField = "0"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(fx_surface_face_enum.POSITIVE_X)] + public fx_surface_face_enum face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string mip + { + get + { + return this.mipField; + } + set + { + this.mipField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string slice + { + get + { + return this.sliceField; + } + set + { + this.sliceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NCName")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_colortarget_common + { + + private string indexField; + + private fx_surface_face_enum faceField; + + private string mipField; + + private string sliceField; + + private string valueField; + + public fx_colortarget_common() + { + this.indexField = "0"; + this.faceField = fx_surface_face_enum.POSITIVE_X; + this.mipField = "0"; + this.sliceField = "0"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(fx_surface_face_enum.POSITIVE_X)] + public fx_surface_face_enum face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string mip + { + get + { + return this.mipField; + } + set + { + this.mipField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + [System.ComponentModel.DefaultValueAttribute("0")] + public string slice + { + get + { + return this.sliceField; + } + set + { + this.sliceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NCName")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_from_common + { + + private uint mipField; + + private uint sliceField; + + private fx_surface_face_enum faceField; + + private string valueField; + + public fx_surface_init_from_common() + { + this.mipField = ((uint)(0)); + this.sliceField = ((uint)(0)); + this.faceField = fx_surface_face_enum.POSITIVE_X; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(uint), "0")] + public uint mip + { + get + { + return this.mipField; + } + set + { + this.mipField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(uint), "0")] + public uint slice + { + get + { + return this.sliceField; + } + set + { + this.sliceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(fx_surface_face_enum.POSITIVE_X)] + public fx_surface_face_enum face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "IDREF")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_newparam + { + + private fx_annotate_common[] annotateField; + + private string semanticField; + + private fx_modifier_enum_common modifierField; + + private bool modifierFieldSpecified; + + private bool boolField; + + private string bool2Field; + + private string bool3Field; + + private string bool4Field; + + private long intField; + + private string int2Field; + + private string int3Field; + + private string int4Field; + + private double floatField; + + private string float2Field; + + private string float3Field; + + private string float4Field; + + private double float1x1Field; + + private string float1x2Field; + + private string float1x3Field; + + private string float1x4Field; + + private string float2x1Field; + + private string float2x2Field; + + private string float2x3Field; + + private string float2x4Field; + + private string float3x1Field; + + private string float3x2Field; + + private string float3x3Field; + + private string float3x4Field; + + private string float4x1Field; + + private string float4x2Field; + + private string float4x3Field; + + private string float4x4Field; + + private fx_surface_common surfaceField; + + private gles_texture_pipeline texture_pipelineField; + + private gles_sampler_state sampler_stateField; + + private gles_texture_unit texture_unitField; + + private string enumField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + public fx_modifier_enum_common modifier + { + get + { + return this.modifierField; + } + set + { + this.modifierField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool modifierSpecified + { + get + { + return this.modifierFieldSpecified; + } + set + { + this.modifierFieldSpecified = value; + } + } + + /// + public bool @bool + { + get + { + return this.boolField; + } + set + { + this.boolField = value; + } + } + + /// + public string bool2 + { + get + { + return this.bool2Field; + } + set + { + this.bool2Field = value; + } + } + + /// + public string bool3 + { + get + { + return this.bool3Field; + } + set + { + this.bool3Field = value; + } + } + + /// + public string bool4 + { + get + { + return this.bool4Field; + } + set + { + this.bool4Field = value; + } + } + + /// + public long @int + { + get + { + return this.intField; + } + set + { + this.intField = value; + } + } + + /// + public string int2 + { + get + { + return this.int2Field; + } + set + { + this.int2Field = value; + } + } + + /// + public string int3 + { + get + { + return this.int3Field; + } + set + { + this.int3Field = value; + } + } + + /// + public string int4 + { + get + { + return this.int4Field; + } + set + { + this.int4Field = value; + } + } + + /// + public double @float + { + get + { + return this.floatField; + } + set + { + this.floatField = value; + } + } + + /// + public string float2 + { + get + { + return this.float2Field; + } + set + { + this.float2Field = value; + } + } + + /// + public string float3 + { + get + { + return this.float3Field; + } + set + { + this.float3Field = value; + } + } + + /// + public string float4 + { + get + { + return this.float4Field; + } + set + { + this.float4Field = value; + } + } + + /// + public double float1x1 + { + get + { + return this.float1x1Field; + } + set + { + this.float1x1Field = value; + } + } + + /// + public string float1x2 + { + get + { + return this.float1x2Field; + } + set + { + this.float1x2Field = value; + } + } + + /// + public string float1x3 + { + get + { + return this.float1x3Field; + } + set + { + this.float1x3Field = value; + } + } + + /// + public string float1x4 + { + get + { + return this.float1x4Field; + } + set + { + this.float1x4Field = value; + } + } + + /// + public string float2x1 + { + get + { + return this.float2x1Field; + } + set + { + this.float2x1Field = value; + } + } + + /// + public string float2x2 + { + get + { + return this.float2x2Field; + } + set + { + this.float2x2Field = value; + } + } + + /// + public string float2x3 + { + get + { + return this.float2x3Field; + } + set + { + this.float2x3Field = value; + } + } + + /// + public string float2x4 + { + get + { + return this.float2x4Field; + } + set + { + this.float2x4Field = value; + } + } + + /// + public string float3x1 + { + get + { + return this.float3x1Field; + } + set + { + this.float3x1Field = value; + } + } + + /// + public string float3x2 + { + get + { + return this.float3x2Field; + } + set + { + this.float3x2Field = value; + } + } + + /// + public string float3x3 + { + get + { + return this.float3x3Field; + } + set + { + this.float3x3Field = value; + } + } + + /// + public string float3x4 + { + get + { + return this.float3x4Field; + } + set + { + this.float3x4Field = value; + } + } + + /// + public string float4x1 + { + get + { + return this.float4x1Field; + } + set + { + this.float4x1Field = value; + } + } + + /// + public string float4x2 + { + get + { + return this.float4x2Field; + } + set + { + this.float4x2Field = value; + } + } + + /// + public string float4x3 + { + get + { + return this.float4x3Field; + } + set + { + this.float4x3Field = value; + } + } + + /// + public string float4x4 + { + get + { + return this.float4x4Field; + } + set + { + this.float4x4Field = value; + } + } + + /// + public fx_surface_common surface + { + get + { + return this.surfaceField; + } + set + { + this.surfaceField = value; + } + } + + /// + public gles_texture_pipeline texture_pipeline + { + get + { + return this.texture_pipelineField; + } + set + { + this.texture_pipelineField = value; + } + } + + /// + public gles_sampler_state sampler_state + { + get + { + return this.sampler_stateField; + } + set + { + this.sampler_stateField = value; + } + } + + /// + public gles_texture_unit texture_unit + { + get + { + return this.texture_unitField; + } + set + { + this.texture_unitField = value; + } + } + + /// + public string @enum + { + get + { + return this.enumField; + } + set + { + this.enumField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_annotate_common + { + + private bool boolField; + + private string bool2Field; + + private string bool3Field; + + private string bool4Field; + + private long intField; + + private string int2Field; + + private string int3Field; + + private string int4Field; + + private double floatField; + + private string float2Field; + + private string float3Field; + + private string float4Field; + + private string float2x2Field; + + private string float3x3Field; + + private string float4x4Field; + + private string stringField; + + private string nameField; + + /// + public bool @bool + { + get + { + return this.boolField; + } + set + { + this.boolField = value; + } + } + + /// + public string bool2 + { + get + { + return this.bool2Field; + } + set + { + this.bool2Field = value; + } + } + + /// + public string bool3 + { + get + { + return this.bool3Field; + } + set + { + this.bool3Field = value; + } + } + + /// + public string bool4 + { + get + { + return this.bool4Field; + } + set + { + this.bool4Field = value; + } + } + + /// + public long @int + { + get + { + return this.intField; + } + set + { + this.intField = value; + } + } + + /// + public string int2 + { + get + { + return this.int2Field; + } + set + { + this.int2Field = value; + } + } + + /// + public string int3 + { + get + { + return this.int3Field; + } + set + { + this.int3Field = value; + } + } + + /// + public string int4 + { + get + { + return this.int4Field; + } + set + { + this.int4Field = value; + } + } + + /// + public double @float + { + get + { + return this.floatField; + } + set + { + this.floatField = value; + } + } + + /// + public string float2 + { + get + { + return this.float2Field; + } + set + { + this.float2Field = value; + } + } + + /// + public string float3 + { + get + { + return this.float3Field; + } + set + { + this.float3Field = value; + } + } + + /// + public string float4 + { + get + { + return this.float4Field; + } + set + { + this.float4Field = value; + } + } + + /// + public string float2x2 + { + get + { + return this.float2x2Field; + } + set + { + this.float2x2Field = value; + } + } + + /// + public string float3x3 + { + get + { + return this.float3x3Field; + } + set + { + this.float3x3Field = value; + } + } + + /// + public string float4x4 + { + get + { + return this.float4x4Field; + } + set + { + this.float4x4Field = value; + } + } + + /// + public string @string + { + get + { + return this.stringField; + } + set + { + this.stringField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_modifier_enum_common + { + + /// + CONST, + + /// + UNIFORM, + + /// + VARYING, + + /// + STATIC, + + /// + VOLATILE, + + /// + EXTERN, + + /// + SHARED, + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(cg_surface_type))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(glsl_surface_type))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_common + { + + private object init_as_nullField; + + private object init_as_targetField; + + private fx_surface_init_cube_common init_cubeField; + + private fx_surface_init_volume_common init_volumeField; + + private fx_surface_init_planar_common init_planarField; + + private fx_surface_init_from_common[] init_fromField; + + private string formatField; + + private fx_surface_format_hint_common format_hintField; + + private object itemField; + + private uint mip_levelsField; + + private bool mipmap_generateField; + + private bool mipmap_generateFieldSpecified; + + private extra[] extraField; + + private fx_surface_type_enum typeField; + + public fx_surface_common() + { + this.mip_levelsField = ((uint)(0)); + } + + /// + public object init_as_null + { + get + { + return this.init_as_nullField; + } + set + { + this.init_as_nullField = value; + } + } + + /// + public object init_as_target + { + get + { + return this.init_as_targetField; + } + set + { + this.init_as_targetField = value; + } + } + + /// + public fx_surface_init_cube_common init_cube + { + get + { + return this.init_cubeField; + } + set + { + this.init_cubeField = value; + } + } + + /// + public fx_surface_init_volume_common init_volume + { + get + { + return this.init_volumeField; + } + set + { + this.init_volumeField = value; + } + } + + /// + public fx_surface_init_planar_common init_planar + { + get + { + return this.init_planarField; + } + set + { + this.init_planarField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("init_from")] + public fx_surface_init_from_common[] init_from + { + get + { + return this.init_fromField; + } + set + { + this.init_fromField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "token")] + public string format + { + get + { + return this.formatField; + } + set + { + this.formatField = value; + } + } + + /// + public fx_surface_format_hint_common format_hint + { + get + { + return this.format_hintField; + } + set + { + this.format_hintField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("size", typeof(long))] + [System.Xml.Serialization.XmlElementAttribute("viewport_ratio", typeof(double))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(uint), "0")] + public uint mip_levels + { + get + { + return this.mip_levelsField; + } + set + { + this.mip_levelsField = value; + } + } + + /// + public bool mipmap_generate + { + get + { + return this.mipmap_generateField; + } + set + { + this.mipmap_generateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool mipmap_generateSpecified + { + get + { + return this.mipmap_generateFieldSpecified; + } + set + { + this.mipmap_generateFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public fx_surface_type_enum type + { + get + { + return this.typeField; + } + set + { + this.typeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_cube_common + { + + private object[] itemsField; + + /// + [System.Xml.Serialization.XmlElementAttribute("all", typeof(fx_surface_init_cube_commonAll))] + [System.Xml.Serialization.XmlElementAttribute("face", typeof(fx_surface_init_cube_commonFace))] + [System.Xml.Serialization.XmlElementAttribute("primary", typeof(fx_surface_init_cube_commonPrimary))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_cube_commonAll + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "IDREF")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_cube_commonFace + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "IDREF")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_cube_commonPrimary + { + + private fx_surface_face_enum[] orderField; + + private string refField; + + /// + [System.Xml.Serialization.XmlElementAttribute("order")] + public fx_surface_face_enum[] order + { + get + { + return this.orderField; + } + set + { + this.orderField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "IDREF")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_volume_common + { + + private object itemField; + + /// + [System.Xml.Serialization.XmlElementAttribute("all", typeof(fx_surface_init_volume_commonAll))] + [System.Xml.Serialization.XmlElementAttribute("primary", typeof(fx_surface_init_volume_commonPrimary))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_volume_commonAll + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "IDREF")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_volume_commonPrimary + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "IDREF")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_planar_common + { + + private fx_surface_init_planar_commonAll itemField; + + /// + [System.Xml.Serialization.XmlElementAttribute("all")] + public fx_surface_init_planar_commonAll Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_init_planar_commonAll + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "IDREF")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_surface_format_hint_common + { + + private fx_surface_format_hint_channels_enum channelsField; + + private fx_surface_format_hint_range_enum rangeField; + + private fx_surface_format_hint_precision_enum precisionField; + + private bool precisionFieldSpecified; + + private fx_surface_format_hint_option_enum[] optionField; + + private extra[] extraField; + + /// + public fx_surface_format_hint_channels_enum channels + { + get + { + return this.channelsField; + } + set + { + this.channelsField = value; + } + } + + /// + public fx_surface_format_hint_range_enum range + { + get + { + return this.rangeField; + } + set + { + this.rangeField = value; + } + } + + /// + public fx_surface_format_hint_precision_enum precision + { + get + { + return this.precisionField; + } + set + { + this.precisionField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool precisionSpecified + { + get + { + return this.precisionFieldSpecified; + } + set + { + this.precisionFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("option")] + public fx_surface_format_hint_option_enum[] option + { + get + { + return this.optionField; + } + set + { + this.optionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_surface_format_hint_channels_enum + { + + /// + RGB, + + /// + RGBA, + + /// + L, + + /// + LA, + + /// + D, + + /// + XYZ, + + /// + XYZW, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_surface_format_hint_range_enum + { + + /// + SNORM, + + /// + UNORM, + + /// + SINT, + + /// + UINT, + + /// + FLOAT, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_surface_format_hint_precision_enum + { + + /// + LOW, + + /// + MID, + + /// + HIGH, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_surface_format_hint_option_enum + { + + /// + SRGB_GAMMA, + + /// + NORMALIZED3, + + /// + NORMALIZED4, + + /// + COMPRESSABLE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class extra + { + + private asset assetField; + + private technique[] techniqueField; + + private string idField; + + private string nameField; + + private string typeField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + public string type + { + get + { + return this.typeField; + } + set + { + this.typeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class technique + { + + private System.Xml.XmlElement[] anyField; + + private string profileField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any + { + get + { + return this.anyField; + } + set + { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + public string profile + { + get + { + return this.profileField; + } + set + { + this.profileField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_surface_type_enum + { + + /// + UNTYPED, + + /// + [System.Xml.Serialization.XmlEnumAttribute("1D")] + Item1D, + + /// + [System.Xml.Serialization.XmlEnumAttribute("2D")] + Item2D, + + /// + [System.Xml.Serialization.XmlEnumAttribute("3D")] + Item3D, + + /// + RECT, + + /// + CUBE, + + /// + DEPTH, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_surface_type : fx_surface_common + { + + private cg_surface_typeGenerator generatorField; + + /// + public cg_surface_typeGenerator generator + { + get + { + return this.generatorField; + } + set + { + this.generatorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_surface_typeGenerator + { + + private fx_annotate_common[] annotateField; + + private object[] itemsField; + + private cg_surface_typeGeneratorName nameField; + + private cg_setparam_simple[] setparamField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("code", typeof(fx_code_profile))] + [System.Xml.Serialization.XmlElementAttribute("include", typeof(fx_include_common))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + public cg_surface_typeGeneratorName name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("setparam")] + public cg_setparam_simple[] setparam + { + get + { + return this.setparamField; + } + set + { + this.setparamField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_code_profile + { + + private string sidField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_include_common + { + + private string sidField; + + private string urlField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string url + { + get + { + return this.urlField; + } + set + { + this.urlField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_surface_typeGeneratorName + { + + private string sourceField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NCName")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_setparam_simple + { + + private fx_annotate_common[] annotateField; + + private bool boolField; + + private bool bool1Field; + + private string bool2Field; + + private string bool3Field; + + private string bool4Field; + + private string bool1x1Field; + + private string bool1x2Field; + + private string bool1x3Field; + + private string bool1x4Field; + + private string bool2x1Field; + + private string bool2x2Field; + + private string bool2x3Field; + + private string bool2x4Field; + + private string bool3x1Field; + + private string bool3x2Field; + + private string bool3x3Field; + + private string bool3x4Field; + + private string bool4x1Field; + + private string bool4x2Field; + + private string bool4x3Field; + + private string bool4x4Field; + + private float floatField; + + private float float1Field; + + private string float2Field; + + private string float3Field; + + private string float4Field; + + private string float1x1Field; + + private string float1x2Field; + + private string float1x3Field; + + private string float1x4Field; + + private string float2x1Field; + + private string float2x2Field; + + private string float2x3Field; + + private string float2x4Field; + + private string float3x1Field; + + private string float3x2Field; + + private string float3x3Field; + + private string float3x4Field; + + private string float4x1Field; + + private string float4x2Field; + + private string float4x3Field; + + private string float4x4Field; + + private int intField; + + private int int1Field; + + private string int2Field; + + private string int3Field; + + private string int4Field; + + private string int1x1Field; + + private string int1x2Field; + + private string int1x3Field; + + private string int1x4Field; + + private string int2x1Field; + + private string int2x2Field; + + private string int2x3Field; + + private string int2x4Field; + + private string int3x1Field; + + private string int3x2Field; + + private string int3x3Field; + + private string int3x4Field; + + private string int4x1Field; + + private string int4x2Field; + + private string int4x3Field; + + private string int4x4Field; + + private float halfField; + + private float half1Field; + + private string half2Field; + + private string half3Field; + + private string half4Field; + + private string half1x1Field; + + private string half1x2Field; + + private string half1x3Field; + + private string half1x4Field; + + private string half2x1Field; + + private string half2x2Field; + + private string half2x3Field; + + private string half2x4Field; + + private string half3x1Field; + + private string half3x2Field; + + private string half3x3Field; + + private string half3x4Field; + + private string half4x1Field; + + private string half4x2Field; + + private string half4x3Field; + + private string half4x4Field; + + private float fixedField; + + private float fixed1Field; + + private string fixed2Field; + + private string fixed3Field; + + private string fixed4Field; + + private string fixed1x1Field; + + private string fixed1x2Field; + + private string fixed1x3Field; + + private string fixed1x4Field; + + private string fixed2x1Field; + + private string fixed2x2Field; + + private string fixed2x3Field; + + private string fixed2x4Field; + + private string fixed3x1Field; + + private string fixed3x2Field; + + private string fixed3x3Field; + + private string fixed3x4Field; + + private string fixed4x1Field; + + private string fixed4x2Field; + + private string fixed4x3Field; + + private string fixed4x4Field; + + private cg_surface_type surfaceField; + + private cg_sampler1D sampler1DField; + + private cg_sampler2D sampler2DField; + + private cg_sampler3D sampler3DField; + + private cg_samplerRECT samplerRECTField; + + private cg_samplerCUBE samplerCUBEField; + + private cg_samplerDEPTH samplerDEPTHField; + + private string stringField; + + private string enumField; + + private string refField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + public bool @bool + { + get + { + return this.boolField; + } + set + { + this.boolField = value; + } + } + + /// + public bool bool1 + { + get + { + return this.bool1Field; + } + set + { + this.bool1Field = value; + } + } + + /// + public string bool2 + { + get + { + return this.bool2Field; + } + set + { + this.bool2Field = value; + } + } + + /// + public string bool3 + { + get + { + return this.bool3Field; + } + set + { + this.bool3Field = value; + } + } + + /// + public string bool4 + { + get + { + return this.bool4Field; + } + set + { + this.bool4Field = value; + } + } + + /// + public string bool1x1 + { + get + { + return this.bool1x1Field; + } + set + { + this.bool1x1Field = value; + } + } + + /// + public string bool1x2 + { + get + { + return this.bool1x2Field; + } + set + { + this.bool1x2Field = value; + } + } + + /// + public string bool1x3 + { + get + { + return this.bool1x3Field; + } + set + { + this.bool1x3Field = value; + } + } + + /// + public string bool1x4 + { + get + { + return this.bool1x4Field; + } + set + { + this.bool1x4Field = value; + } + } + + /// + public string bool2x1 + { + get + { + return this.bool2x1Field; + } + set + { + this.bool2x1Field = value; + } + } + + /// + public string bool2x2 + { + get + { + return this.bool2x2Field; + } + set + { + this.bool2x2Field = value; + } + } + + /// + public string bool2x3 + { + get + { + return this.bool2x3Field; + } + set + { + this.bool2x3Field = value; + } + } + + /// + public string bool2x4 + { + get + { + return this.bool2x4Field; + } + set + { + this.bool2x4Field = value; + } + } + + /// + public string bool3x1 + { + get + { + return this.bool3x1Field; + } + set + { + this.bool3x1Field = value; + } + } + + /// + public string bool3x2 + { + get + { + return this.bool3x2Field; + } + set + { + this.bool3x2Field = value; + } + } + + /// + public string bool3x3 + { + get + { + return this.bool3x3Field; + } + set + { + this.bool3x3Field = value; + } + } + + /// + public string bool3x4 + { + get + { + return this.bool3x4Field; + } + set + { + this.bool3x4Field = value; + } + } + + /// + public string bool4x1 + { + get + { + return this.bool4x1Field; + } + set + { + this.bool4x1Field = value; + } + } + + /// + public string bool4x2 + { + get + { + return this.bool4x2Field; + } + set + { + this.bool4x2Field = value; + } + } + + /// + public string bool4x3 + { + get + { + return this.bool4x3Field; + } + set + { + this.bool4x3Field = value; + } + } + + /// + public string bool4x4 + { + get + { + return this.bool4x4Field; + } + set + { + this.bool4x4Field = value; + } + } + + /// + public float @float + { + get + { + return this.floatField; + } + set + { + this.floatField = value; + } + } + + /// + public float float1 + { + get + { + return this.float1Field; + } + set + { + this.float1Field = value; + } + } + + /// + public string float2 + { + get + { + return this.float2Field; + } + set + { + this.float2Field = value; + } + } + + /// + public string float3 + { + get + { + return this.float3Field; + } + set + { + this.float3Field = value; + } + } + + /// + public string float4 + { + get + { + return this.float4Field; + } + set + { + this.float4Field = value; + } + } + + /// + public string float1x1 + { + get + { + return this.float1x1Field; + } + set + { + this.float1x1Field = value; + } + } + + /// + public string float1x2 + { + get + { + return this.float1x2Field; + } + set + { + this.float1x2Field = value; + } + } + + /// + public string float1x3 + { + get + { + return this.float1x3Field; + } + set + { + this.float1x3Field = value; + } + } + + /// + public string float1x4 + { + get + { + return this.float1x4Field; + } + set + { + this.float1x4Field = value; + } + } + + /// + public string float2x1 + { + get + { + return this.float2x1Field; + } + set + { + this.float2x1Field = value; + } + } + + /// + public string float2x2 + { + get + { + return this.float2x2Field; + } + set + { + this.float2x2Field = value; + } + } + + /// + public string float2x3 + { + get + { + return this.float2x3Field; + } + set + { + this.float2x3Field = value; + } + } + + /// + public string float2x4 + { + get + { + return this.float2x4Field; + } + set + { + this.float2x4Field = value; + } + } + + /// + public string float3x1 + { + get + { + return this.float3x1Field; + } + set + { + this.float3x1Field = value; + } + } + + /// + public string float3x2 + { + get + { + return this.float3x2Field; + } + set + { + this.float3x2Field = value; + } + } + + /// + public string float3x3 + { + get + { + return this.float3x3Field; + } + set + { + this.float3x3Field = value; + } + } + + /// + public string float3x4 + { + get + { + return this.float3x4Field; + } + set + { + this.float3x4Field = value; + } + } + + /// + public string float4x1 + { + get + { + return this.float4x1Field; + } + set + { + this.float4x1Field = value; + } + } + + /// + public string float4x2 + { + get + { + return this.float4x2Field; + } + set + { + this.float4x2Field = value; + } + } + + /// + public string float4x3 + { + get + { + return this.float4x3Field; + } + set + { + this.float4x3Field = value; + } + } + + /// + public string float4x4 + { + get + { + return this.float4x4Field; + } + set + { + this.float4x4Field = value; + } + } + + /// + public int @int + { + get + { + return this.intField; + } + set + { + this.intField = value; + } + } + + /// + public int int1 + { + get + { + return this.int1Field; + } + set + { + this.int1Field = value; + } + } + + /// + public string int2 + { + get + { + return this.int2Field; + } + set + { + this.int2Field = value; + } + } + + /// + public string int3 + { + get + { + return this.int3Field; + } + set + { + this.int3Field = value; + } + } + + /// + public string int4 + { + get + { + return this.int4Field; + } + set + { + this.int4Field = value; + } + } + + /// + public string int1x1 + { + get + { + return this.int1x1Field; + } + set + { + this.int1x1Field = value; + } + } + + /// + public string int1x2 + { + get + { + return this.int1x2Field; + } + set + { + this.int1x2Field = value; + } + } + + /// + public string int1x3 + { + get + { + return this.int1x3Field; + } + set + { + this.int1x3Field = value; + } + } + + /// + public string int1x4 + { + get + { + return this.int1x4Field; + } + set + { + this.int1x4Field = value; + } + } + + /// + public string int2x1 + { + get + { + return this.int2x1Field; + } + set + { + this.int2x1Field = value; + } + } + + /// + public string int2x2 + { + get + { + return this.int2x2Field; + } + set + { + this.int2x2Field = value; + } + } + + /// + public string int2x3 + { + get + { + return this.int2x3Field; + } + set + { + this.int2x3Field = value; + } + } + + /// + public string int2x4 + { + get + { + return this.int2x4Field; + } + set + { + this.int2x4Field = value; + } + } + + /// + public string int3x1 + { + get + { + return this.int3x1Field; + } + set + { + this.int3x1Field = value; + } + } + + /// + public string int3x2 + { + get + { + return this.int3x2Field; + } + set + { + this.int3x2Field = value; + } + } + + /// + public string int3x3 + { + get + { + return this.int3x3Field; + } + set + { + this.int3x3Field = value; + } + } + + /// + public string int3x4 + { + get + { + return this.int3x4Field; + } + set + { + this.int3x4Field = value; + } + } + + /// + public string int4x1 + { + get + { + return this.int4x1Field; + } + set + { + this.int4x1Field = value; + } + } + + /// + public string int4x2 + { + get + { + return this.int4x2Field; + } + set + { + this.int4x2Field = value; + } + } + + /// + public string int4x3 + { + get + { + return this.int4x3Field; + } + set + { + this.int4x3Field = value; + } + } + + /// + public string int4x4 + { + get + { + return this.int4x4Field; + } + set + { + this.int4x4Field = value; + } + } + + /// + public float half + { + get + { + return this.halfField; + } + set + { + this.halfField = value; + } + } + + /// + public float half1 + { + get + { + return this.half1Field; + } + set + { + this.half1Field = value; + } + } + + /// + public string half2 + { + get + { + return this.half2Field; + } + set + { + this.half2Field = value; + } + } + + /// + public string half3 + { + get + { + return this.half3Field; + } + set + { + this.half3Field = value; + } + } + + /// + public string half4 + { + get + { + return this.half4Field; + } + set + { + this.half4Field = value; + } + } + + /// + public string half1x1 + { + get + { + return this.half1x1Field; + } + set + { + this.half1x1Field = value; + } + } + + /// + public string half1x2 + { + get + { + return this.half1x2Field; + } + set + { + this.half1x2Field = value; + } + } + + /// + public string half1x3 + { + get + { + return this.half1x3Field; + } + set + { + this.half1x3Field = value; + } + } + + /// + public string half1x4 + { + get + { + return this.half1x4Field; + } + set + { + this.half1x4Field = value; + } + } + + /// + public string half2x1 + { + get + { + return this.half2x1Field; + } + set + { + this.half2x1Field = value; + } + } + + /// + public string half2x2 + { + get + { + return this.half2x2Field; + } + set + { + this.half2x2Field = value; + } + } + + /// + public string half2x3 + { + get + { + return this.half2x3Field; + } + set + { + this.half2x3Field = value; + } + } + + /// + public string half2x4 + { + get + { + return this.half2x4Field; + } + set + { + this.half2x4Field = value; + } + } + + /// + public string half3x1 + { + get + { + return this.half3x1Field; + } + set + { + this.half3x1Field = value; + } + } + + /// + public string half3x2 + { + get + { + return this.half3x2Field; + } + set + { + this.half3x2Field = value; + } + } + + /// + public string half3x3 + { + get + { + return this.half3x3Field; + } + set + { + this.half3x3Field = value; + } + } + + /// + public string half3x4 + { + get + { + return this.half3x4Field; + } + set + { + this.half3x4Field = value; + } + } + + /// + public string half4x1 + { + get + { + return this.half4x1Field; + } + set + { + this.half4x1Field = value; + } + } + + /// + public string half4x2 + { + get + { + return this.half4x2Field; + } + set + { + this.half4x2Field = value; + } + } + + /// + public string half4x3 + { + get + { + return this.half4x3Field; + } + set + { + this.half4x3Field = value; + } + } + + /// + public string half4x4 + { + get + { + return this.half4x4Field; + } + set + { + this.half4x4Field = value; + } + } + + /// + public float @fixed + { + get + { + return this.fixedField; + } + set + { + this.fixedField = value; + } + } + + /// + public float fixed1 + { + get + { + return this.fixed1Field; + } + set + { + this.fixed1Field = value; + } + } + + /// + public string fixed2 + { + get + { + return this.fixed2Field; + } + set + { + this.fixed2Field = value; + } + } + + /// + public string fixed3 + { + get + { + return this.fixed3Field; + } + set + { + this.fixed3Field = value; + } + } + + /// + public string fixed4 + { + get + { + return this.fixed4Field; + } + set + { + this.fixed4Field = value; + } + } + + /// + public string fixed1x1 + { + get + { + return this.fixed1x1Field; + } + set + { + this.fixed1x1Field = value; + } + } + + /// + public string fixed1x2 + { + get + { + return this.fixed1x2Field; + } + set + { + this.fixed1x2Field = value; + } + } + + /// + public string fixed1x3 + { + get + { + return this.fixed1x3Field; + } + set + { + this.fixed1x3Field = value; + } + } + + /// + public string fixed1x4 + { + get + { + return this.fixed1x4Field; + } + set + { + this.fixed1x4Field = value; + } + } + + /// + public string fixed2x1 + { + get + { + return this.fixed2x1Field; + } + set + { + this.fixed2x1Field = value; + } + } + + /// + public string fixed2x2 + { + get + { + return this.fixed2x2Field; + } + set + { + this.fixed2x2Field = value; + } + } + + /// + public string fixed2x3 + { + get + { + return this.fixed2x3Field; + } + set + { + this.fixed2x3Field = value; + } + } + + /// + public string fixed2x4 + { + get + { + return this.fixed2x4Field; + } + set + { + this.fixed2x4Field = value; + } + } + + /// + public string fixed3x1 + { + get + { + return this.fixed3x1Field; + } + set + { + this.fixed3x1Field = value; + } + } + + /// + public string fixed3x2 + { + get + { + return this.fixed3x2Field; + } + set + { + this.fixed3x2Field = value; + } + } + + /// + public string fixed3x3 + { + get + { + return this.fixed3x3Field; + } + set + { + this.fixed3x3Field = value; + } + } + + /// + public string fixed3x4 + { + get + { + return this.fixed3x4Field; + } + set + { + this.fixed3x4Field = value; + } + } + + /// + public string fixed4x1 + { + get + { + return this.fixed4x1Field; + } + set + { + this.fixed4x1Field = value; + } + } + + /// + public string fixed4x2 + { + get + { + return this.fixed4x2Field; + } + set + { + this.fixed4x2Field = value; + } + } + + /// + public string fixed4x3 + { + get + { + return this.fixed4x3Field; + } + set + { + this.fixed4x3Field = value; + } + } + + /// + public string fixed4x4 + { + get + { + return this.fixed4x4Field; + } + set + { + this.fixed4x4Field = value; + } + } + + /// + public cg_surface_type surface + { + get + { + return this.surfaceField; + } + set + { + this.surfaceField = value; + } + } + + /// + public cg_sampler1D sampler1D + { + get + { + return this.sampler1DField; + } + set + { + this.sampler1DField = value; + } + } + + /// + public cg_sampler2D sampler2D + { + get + { + return this.sampler2DField; + } + set + { + this.sampler2DField = value; + } + } + + /// + public cg_sampler3D sampler3D + { + get + { + return this.sampler3DField; + } + set + { + this.sampler3DField = value; + } + } + + /// + public cg_samplerRECT samplerRECT + { + get + { + return this.samplerRECTField; + } + set + { + this.samplerRECTField = value; + } + } + + /// + public cg_samplerCUBE samplerCUBE + { + get + { + return this.samplerCUBEField; + } + set + { + this.samplerCUBEField = value; + } + } + + /// + public cg_samplerDEPTH samplerDEPTH + { + get + { + return this.samplerDEPTHField; + } + set + { + this.samplerDEPTHField = value; + } + } + + /// + public string @string + { + get + { + return this.stringField; + } + set + { + this.stringField = value; + } + } + + /// + public string @enum + { + get + { + return this.enumField; + } + set + { + this.enumField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_sampler1D : fx_sampler1D_common + { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(cg_sampler1D))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(gl_sampler1D))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_sampler1D_common + { + + private string sourceField; + + private fx_sampler_wrap_common wrap_sField; + + private fx_sampler_filter_common minfilterField; + + private fx_sampler_filter_common magfilterField; + + private fx_sampler_filter_common mipfilterField; + + private string border_colorField; + + private byte mipmap_maxlevelField; + + private float mipmap_biasField; + + private extra[] extraField; + + public fx_sampler1D_common() + { + this.wrap_sField = fx_sampler_wrap_common.WRAP; + this.minfilterField = fx_sampler_filter_common.NONE; + this.magfilterField = fx_sampler_filter_common.NONE; + this.mipfilterField = fx_sampler_filter_common.NONE; + this.mipmap_maxlevelField = ((byte)(0)); + this.mipmap_biasField = ((float)(0F)); + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_s + { + get + { + return this.wrap_sField; + } + set + { + this.wrap_sField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common minfilter + { + get + { + return this.minfilterField; + } + set + { + this.minfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common magfilter + { + get + { + return this.magfilterField; + } + set + { + this.magfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common mipfilter + { + get + { + return this.mipfilterField; + } + set + { + this.mipfilterField = value; + } + } + + /// + public string border_color + { + get + { + return this.border_colorField; + } + set + { + this.border_colorField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "0")] + public byte mipmap_maxlevel + { + get + { + return this.mipmap_maxlevelField; + } + set + { + this.mipmap_maxlevelField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float mipmap_bias + { + get + { + return this.mipmap_biasField; + } + set + { + this.mipmap_biasField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_sampler_wrap_common + { + + /// + NONE, + + /// + WRAP, + + /// + MIRROR, + + /// + CLAMP, + + /// + BORDER, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_sampler_filter_common + { + + /// + NONE, + + /// + NEAREST, + + /// + LINEAR, + + /// + NEAREST_MIPMAP_NEAREST, + + /// + LINEAR_MIPMAP_NEAREST, + + /// + NEAREST_MIPMAP_LINEAR, + + /// + LINEAR_MIPMAP_LINEAR, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gl_sampler1D : fx_sampler1D_common + { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_sampler2D : fx_sampler2D_common + { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(cg_sampler2D))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(gl_sampler2D))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_sampler2D_common + { + + private string sourceField; + + private fx_sampler_wrap_common wrap_sField; + + private fx_sampler_wrap_common wrap_tField; + + private fx_sampler_filter_common minfilterField; + + private fx_sampler_filter_common magfilterField; + + private fx_sampler_filter_common mipfilterField; + + private string border_colorField; + + private byte mipmap_maxlevelField; + + private float mipmap_biasField; + + private extra[] extraField; + + public fx_sampler2D_common() + { + this.wrap_sField = fx_sampler_wrap_common.WRAP; + this.wrap_tField = fx_sampler_wrap_common.WRAP; + this.minfilterField = fx_sampler_filter_common.NONE; + this.magfilterField = fx_sampler_filter_common.NONE; + this.mipfilterField = fx_sampler_filter_common.NONE; + this.mipmap_maxlevelField = ((byte)(255)); + this.mipmap_biasField = ((float)(0F)); + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_s + { + get + { + return this.wrap_sField; + } + set + { + this.wrap_sField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_t + { + get + { + return this.wrap_tField; + } + set + { + this.wrap_tField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common minfilter + { + get + { + return this.minfilterField; + } + set + { + this.minfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common magfilter + { + get + { + return this.magfilterField; + } + set + { + this.magfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common mipfilter + { + get + { + return this.mipfilterField; + } + set + { + this.mipfilterField = value; + } + } + + /// + public string border_color + { + get + { + return this.border_colorField; + } + set + { + this.border_colorField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte mipmap_maxlevel + { + get + { + return this.mipmap_maxlevelField; + } + set + { + this.mipmap_maxlevelField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float mipmap_bias + { + get + { + return this.mipmap_biasField; + } + set + { + this.mipmap_biasField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gl_sampler2D : fx_sampler2D_common + { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_sampler3D : fx_sampler3D_common + { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(cg_sampler3D))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(gl_sampler3D))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_sampler3D_common + { + + private string sourceField; + + private fx_sampler_wrap_common wrap_sField; + + private fx_sampler_wrap_common wrap_tField; + + private fx_sampler_wrap_common wrap_pField; + + private fx_sampler_filter_common minfilterField; + + private fx_sampler_filter_common magfilterField; + + private fx_sampler_filter_common mipfilterField; + + private string border_colorField; + + private byte mipmap_maxlevelField; + + private float mipmap_biasField; + + private extra[] extraField; + + public fx_sampler3D_common() + { + this.wrap_sField = fx_sampler_wrap_common.WRAP; + this.wrap_tField = fx_sampler_wrap_common.WRAP; + this.wrap_pField = fx_sampler_wrap_common.WRAP; + this.minfilterField = fx_sampler_filter_common.NONE; + this.magfilterField = fx_sampler_filter_common.NONE; + this.mipfilterField = fx_sampler_filter_common.NONE; + this.mipmap_maxlevelField = ((byte)(255)); + this.mipmap_biasField = ((float)(0F)); + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_s + { + get + { + return this.wrap_sField; + } + set + { + this.wrap_sField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_t + { + get + { + return this.wrap_tField; + } + set + { + this.wrap_tField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_p + { + get + { + return this.wrap_pField; + } + set + { + this.wrap_pField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common minfilter + { + get + { + return this.minfilterField; + } + set + { + this.minfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common magfilter + { + get + { + return this.magfilterField; + } + set + { + this.magfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common mipfilter + { + get + { + return this.mipfilterField; + } + set + { + this.mipfilterField = value; + } + } + + /// + public string border_color + { + get + { + return this.border_colorField; + } + set + { + this.border_colorField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte mipmap_maxlevel + { + get + { + return this.mipmap_maxlevelField; + } + set + { + this.mipmap_maxlevelField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float mipmap_bias + { + get + { + return this.mipmap_biasField; + } + set + { + this.mipmap_biasField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gl_sampler3D : fx_sampler3D_common + { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_samplerRECT : fx_samplerRECT_common + { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(cg_samplerRECT))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(gl_samplerRECT))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_samplerRECT_common + { + + private string sourceField; + + private fx_sampler_wrap_common wrap_sField; + + private fx_sampler_wrap_common wrap_tField; + + private fx_sampler_filter_common minfilterField; + + private fx_sampler_filter_common magfilterField; + + private fx_sampler_filter_common mipfilterField; + + private string border_colorField; + + private byte mipmap_maxlevelField; + + private float mipmap_biasField; + + private extra[] extraField; + + public fx_samplerRECT_common() + { + this.wrap_sField = fx_sampler_wrap_common.WRAP; + this.wrap_tField = fx_sampler_wrap_common.WRAP; + this.minfilterField = fx_sampler_filter_common.NONE; + this.magfilterField = fx_sampler_filter_common.NONE; + this.mipfilterField = fx_sampler_filter_common.NONE; + this.mipmap_maxlevelField = ((byte)(255)); + this.mipmap_biasField = ((float)(0F)); + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_s + { + get + { + return this.wrap_sField; + } + set + { + this.wrap_sField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_t + { + get + { + return this.wrap_tField; + } + set + { + this.wrap_tField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common minfilter + { + get + { + return this.minfilterField; + } + set + { + this.minfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common magfilter + { + get + { + return this.magfilterField; + } + set + { + this.magfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common mipfilter + { + get + { + return this.mipfilterField; + } + set + { + this.mipfilterField = value; + } + } + + /// + public string border_color + { + get + { + return this.border_colorField; + } + set + { + this.border_colorField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte mipmap_maxlevel + { + get + { + return this.mipmap_maxlevelField; + } + set + { + this.mipmap_maxlevelField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float mipmap_bias + { + get + { + return this.mipmap_biasField; + } + set + { + this.mipmap_biasField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gl_samplerRECT : fx_samplerRECT_common + { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_samplerCUBE : fx_samplerCUBE_common + { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(cg_samplerCUBE))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(gl_samplerCUBE))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_samplerCUBE_common + { + + private string sourceField; + + private fx_sampler_wrap_common wrap_sField; + + private fx_sampler_wrap_common wrap_tField; + + private fx_sampler_wrap_common wrap_pField; + + private fx_sampler_filter_common minfilterField; + + private fx_sampler_filter_common magfilterField; + + private fx_sampler_filter_common mipfilterField; + + private string border_colorField; + + private byte mipmap_maxlevelField; + + private float mipmap_biasField; + + private extra[] extraField; + + public fx_samplerCUBE_common() + { + this.wrap_sField = fx_sampler_wrap_common.WRAP; + this.wrap_tField = fx_sampler_wrap_common.WRAP; + this.wrap_pField = fx_sampler_wrap_common.WRAP; + this.minfilterField = fx_sampler_filter_common.NONE; + this.magfilterField = fx_sampler_filter_common.NONE; + this.mipfilterField = fx_sampler_filter_common.NONE; + this.mipmap_maxlevelField = ((byte)(255)); + this.mipmap_biasField = ((float)(0F)); + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_s + { + get + { + return this.wrap_sField; + } + set + { + this.wrap_sField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_t + { + get + { + return this.wrap_tField; + } + set + { + this.wrap_tField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_p + { + get + { + return this.wrap_pField; + } + set + { + this.wrap_pField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common minfilter + { + get + { + return this.minfilterField; + } + set + { + this.minfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common magfilter + { + get + { + return this.magfilterField; + } + set + { + this.magfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common mipfilter + { + get + { + return this.mipfilterField; + } + set + { + this.mipfilterField = value; + } + } + + /// + public string border_color + { + get + { + return this.border_colorField; + } + set + { + this.border_colorField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte mipmap_maxlevel + { + get + { + return this.mipmap_maxlevelField; + } + set + { + this.mipmap_maxlevelField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float mipmap_bias + { + get + { + return this.mipmap_biasField; + } + set + { + this.mipmap_biasField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gl_samplerCUBE : fx_samplerCUBE_common + { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_samplerDEPTH : fx_samplerDEPTH_common + { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(cg_samplerDEPTH))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(gl_samplerDEPTH))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_samplerDEPTH_common + { + + private string sourceField; + + private fx_sampler_wrap_common wrap_sField; + + private fx_sampler_wrap_common wrap_tField; + + private fx_sampler_filter_common minfilterField; + + private fx_sampler_filter_common magfilterField; + + private extra[] extraField; + + public fx_samplerDEPTH_common() + { + this.wrap_sField = fx_sampler_wrap_common.WRAP; + this.wrap_tField = fx_sampler_wrap_common.WRAP; + this.minfilterField = fx_sampler_filter_common.NONE; + this.magfilterField = fx_sampler_filter_common.NONE; + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_s + { + get + { + return this.wrap_sField; + } + set + { + this.wrap_sField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_wrap_common.WRAP)] + public fx_sampler_wrap_common wrap_t + { + get + { + return this.wrap_tField; + } + set + { + this.wrap_tField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common minfilter + { + get + { + return this.minfilterField; + } + set + { + this.minfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common magfilter + { + get + { + return this.magfilterField; + } + set + { + this.magfilterField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gl_samplerDEPTH : fx_samplerDEPTH_common + { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_surface_type : fx_surface_common + { + + private glsl_surface_typeGenerator generatorField; + + /// + public glsl_surface_typeGenerator generator + { + get + { + return this.generatorField; + } + set + { + this.generatorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_surface_typeGenerator + { + + private fx_annotate_common[] annotateField; + + private object[] itemsField; + + private glsl_surface_typeGeneratorName nameField; + + private glsl_setparam_simple[] setparamField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("code", typeof(fx_code_profile))] + [System.Xml.Serialization.XmlElementAttribute("include", typeof(fx_include_common))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + public glsl_surface_typeGeneratorName name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("setparam")] + public glsl_setparam_simple[] setparam + { + get + { + return this.setparamField; + } + set + { + this.setparamField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_surface_typeGeneratorName + { + + private string sourceField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NCName")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_setparam_simple + { + + private fx_annotate_common[] annotateField; + + private bool boolField; + + private string bool2Field; + + private string bool3Field; + + private string bool4Field; + + private float floatField; + + private string float2Field; + + private string float3Field; + + private string float4Field; + + private string float2x2Field; + + private string float3x3Field; + + private string float4x4Field; + + private int intField; + + private string int2Field; + + private string int3Field; + + private string int4Field; + + private glsl_surface_type surfaceField; + + private gl_sampler1D sampler1DField; + + private gl_sampler2D sampler2DField; + + private gl_sampler3D sampler3DField; + + private gl_samplerCUBE samplerCUBEField; + + private gl_samplerRECT samplerRECTField; + + private gl_samplerDEPTH samplerDEPTHField; + + private string enumField; + + private string refField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + public bool @bool + { + get + { + return this.boolField; + } + set + { + this.boolField = value; + } + } + + /// + public string bool2 + { + get + { + return this.bool2Field; + } + set + { + this.bool2Field = value; + } + } + + /// + public string bool3 + { + get + { + return this.bool3Field; + } + set + { + this.bool3Field = value; + } + } + + /// + public string bool4 + { + get + { + return this.bool4Field; + } + set + { + this.bool4Field = value; + } + } + + /// + public float @float + { + get + { + return this.floatField; + } + set + { + this.floatField = value; + } + } + + /// + public string float2 + { + get + { + return this.float2Field; + } + set + { + this.float2Field = value; + } + } + + /// + public string float3 + { + get + { + return this.float3Field; + } + set + { + this.float3Field = value; + } + } + + /// + public string float4 + { + get + { + return this.float4Field; + } + set + { + this.float4Field = value; + } + } + + /// + public string float2x2 + { + get + { + return this.float2x2Field; + } + set + { + this.float2x2Field = value; + } + } + + /// + public string float3x3 + { + get + { + return this.float3x3Field; + } + set + { + this.float3x3Field = value; + } + } + + /// + public string float4x4 + { + get + { + return this.float4x4Field; + } + set + { + this.float4x4Field = value; + } + } + + /// + public int @int + { + get + { + return this.intField; + } + set + { + this.intField = value; + } + } + + /// + public string int2 + { + get + { + return this.int2Field; + } + set + { + this.int2Field = value; + } + } + + /// + public string int3 + { + get + { + return this.int3Field; + } + set + { + this.int3Field = value; + } + } + + /// + public string int4 + { + get + { + return this.int4Field; + } + set + { + this.int4Field = value; + } + } + + /// + public glsl_surface_type surface + { + get + { + return this.surfaceField; + } + set + { + this.surfaceField = value; + } + } + + /// + public gl_sampler1D sampler1D + { + get + { + return this.sampler1DField; + } + set + { + this.sampler1DField = value; + } + } + + /// + public gl_sampler2D sampler2D + { + get + { + return this.sampler2DField; + } + set + { + this.sampler2DField = value; + } + } + + /// + public gl_sampler3D sampler3D + { + get + { + return this.sampler3DField; + } + set + { + this.sampler3DField = value; + } + } + + /// + public gl_samplerCUBE samplerCUBE + { + get + { + return this.samplerCUBEField; + } + set + { + this.samplerCUBEField = value; + } + } + + /// + public gl_samplerRECT samplerRECT + { + get + { + return this.samplerRECTField; + } + set + { + this.samplerRECTField = value; + } + } + + /// + public gl_samplerDEPTH samplerDEPTH + { + get + { + return this.samplerDEPTHField; + } + set + { + this.samplerDEPTHField = value; + } + } + + /// + public string @enum + { + get + { + return this.enumField; + } + set + { + this.enumField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texture_pipeline + { + + private object[] itemsField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("extra", typeof(extra))] + [System.Xml.Serialization.XmlElementAttribute("texcombiner", typeof(gles_texcombiner_command_type))] + [System.Xml.Serialization.XmlElementAttribute("texenv", typeof(gles_texenv_command_type))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texcombiner_command_type + { + + private gles_texture_constant_type constantField; + + private gles_texcombiner_commandRGB_type rGBField; + + private gles_texcombiner_commandAlpha_type alphaField; + + /// + public gles_texture_constant_type constant + { + get + { + return this.constantField; + } + set + { + this.constantField = value; + } + } + + /// + public gles_texcombiner_commandRGB_type RGB + { + get + { + return this.rGBField; + } + set + { + this.rGBField = value; + } + } + + /// + public gles_texcombiner_commandAlpha_type alpha + { + get + { + return this.alphaField; + } + set + { + this.alphaField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texture_constant_type + { + + private double[] valueField; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texcombiner_commandRGB_type + { + + private gles_texcombiner_argumentRGB_type[] argumentField; + + private gles_texcombiner_operatorRGB_enums operatorField; + + private bool operatorFieldSpecified; + + private float scaleField; + + private bool scaleFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute("argument")] + public gles_texcombiner_argumentRGB_type[] argument + { + get + { + return this.argumentField; + } + set + { + this.argumentField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public gles_texcombiner_operatorRGB_enums @operator + { + get + { + return this.operatorField; + } + set + { + this.operatorField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool operatorSpecified + { + get + { + return this.operatorFieldSpecified; + } + set + { + this.operatorFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public float scale + { + get + { + return this.scaleField; + } + set + { + this.scaleField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool scaleSpecified + { + get + { + return this.scaleFieldSpecified; + } + set + { + this.scaleFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texcombiner_argumentRGB_type + { + + private gles_texcombiner_source_enums sourceField; + + private bool sourceFieldSpecified; + + private gles_texcombiner_operandRGB_enums operandField; + + private string unitField; + + public gles_texcombiner_argumentRGB_type() + { + this.operandField = gles_texcombiner_operandRGB_enums.SRC_COLOR; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public gles_texcombiner_source_enums source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool sourceSpecified + { + get + { + return this.sourceFieldSpecified; + } + set + { + this.sourceFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gles_texcombiner_operandRGB_enums.SRC_COLOR)] + public gles_texcombiner_operandRGB_enums operand + { + get + { + return this.operandField; + } + set + { + this.operandField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string unit + { + get + { + return this.unitField; + } + set + { + this.unitField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_texcombiner_source_enums + { + + /// + TEXTURE, + + /// + CONSTANT, + + /// + PRIMARY, + + /// + PREVIOUS, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_texcombiner_operandRGB_enums + { + + /// + SRC_COLOR, + + /// + ONE_MINUS_SRC_COLOR, + + /// + SRC_ALPHA, + + /// + ONE_MINUS_SRC_ALPHA, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_texcombiner_operatorRGB_enums + { + + /// + REPLACE, + + /// + MODULATE, + + /// + ADD, + + /// + ADD_SIGNED, + + /// + INTERPOLATE, + + /// + SUBTRACT, + + /// + DOT3_RGB, + + /// + DOT3_RGBA, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texcombiner_commandAlpha_type + { + + private gles_texcombiner_argumentAlpha_type[] argumentField; + + private gles_texcombiner_operatorAlpha_enums operatorField; + + private bool operatorFieldSpecified; + + private float scaleField; + + private bool scaleFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute("argument")] + public gles_texcombiner_argumentAlpha_type[] argument + { + get + { + return this.argumentField; + } + set + { + this.argumentField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public gles_texcombiner_operatorAlpha_enums @operator + { + get + { + return this.operatorField; + } + set + { + this.operatorField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool operatorSpecified + { + get + { + return this.operatorFieldSpecified; + } + set + { + this.operatorFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public float scale + { + get + { + return this.scaleField; + } + set + { + this.scaleField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool scaleSpecified + { + get + { + return this.scaleFieldSpecified; + } + set + { + this.scaleFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texcombiner_argumentAlpha_type + { + + private gles_texcombiner_source_enums sourceField; + + private bool sourceFieldSpecified; + + private gles_texcombiner_operandAlpha_enums operandField; + + private string unitField; + + public gles_texcombiner_argumentAlpha_type() + { + this.operandField = gles_texcombiner_operandAlpha_enums.SRC_ALPHA; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public gles_texcombiner_source_enums source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool sourceSpecified + { + get + { + return this.sourceFieldSpecified; + } + set + { + this.sourceFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gles_texcombiner_operandAlpha_enums.SRC_ALPHA)] + public gles_texcombiner_operandAlpha_enums operand + { + get + { + return this.operandField; + } + set + { + this.operandField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string unit + { + get + { + return this.unitField; + } + set + { + this.unitField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_texcombiner_operandAlpha_enums + { + + /// + SRC_ALPHA, + + /// + ONE_MINUS_SRC_ALPHA, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_texcombiner_operatorAlpha_enums + { + + /// + REPLACE, + + /// + MODULATE, + + /// + ADD, + + /// + ADD_SIGNED, + + /// + INTERPOLATE, + + /// + SUBTRACT, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texenv_command_type + { + + private gles_texture_constant_type constantField; + + private gles_texenv_mode_enums operatorField; + + private bool operatorFieldSpecified; + + private string unitField; + + /// + public gles_texture_constant_type constant + { + get + { + return this.constantField; + } + set + { + this.constantField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public gles_texenv_mode_enums @operator + { + get + { + return this.operatorField; + } + set + { + this.operatorField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool operatorSpecified + { + get + { + return this.operatorFieldSpecified; + } + set + { + this.operatorFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string unit + { + get + { + return this.unitField; + } + set + { + this.unitField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_texenv_mode_enums + { + + /// + REPLACE, + + /// + MODULATE, + + /// + DECAL, + + /// + BLEND, + + /// + ADD, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_sampler_state + { + + private gles_sampler_wrap wrap_sField; + + private gles_sampler_wrap wrap_tField; + + private fx_sampler_filter_common minfilterField; + + private fx_sampler_filter_common magfilterField; + + private fx_sampler_filter_common mipfilterField; + + private byte mipmap_maxlevelField; + + private float mipmap_biasField; + + private extra[] extraField; + + private string sidField; + + public gles_sampler_state() + { + this.wrap_sField = gles_sampler_wrap.REPEAT; + this.wrap_tField = gles_sampler_wrap.REPEAT; + this.minfilterField = fx_sampler_filter_common.NONE; + this.magfilterField = fx_sampler_filter_common.NONE; + this.mipfilterField = fx_sampler_filter_common.NONE; + this.mipmap_maxlevelField = ((byte)(255)); + this.mipmap_biasField = ((float)(0F)); + } + + /// + [System.ComponentModel.DefaultValueAttribute(gles_sampler_wrap.REPEAT)] + public gles_sampler_wrap wrap_s + { + get + { + return this.wrap_sField; + } + set + { + this.wrap_sField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(gles_sampler_wrap.REPEAT)] + public gles_sampler_wrap wrap_t + { + get + { + return this.wrap_tField; + } + set + { + this.wrap_tField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common minfilter + { + get + { + return this.minfilterField; + } + set + { + this.minfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common magfilter + { + get + { + return this.magfilterField; + } + set + { + this.magfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(fx_sampler_filter_common.NONE)] + public fx_sampler_filter_common mipfilter + { + get + { + return this.mipfilterField; + } + set + { + this.mipfilterField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte mipmap_maxlevel + { + get + { + return this.mipmap_maxlevelField; + } + set + { + this.mipmap_maxlevelField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float mipmap_bias + { + get + { + return this.mipmap_biasField; + } + set + { + this.mipmap_biasField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_sampler_wrap + { + + /// + REPEAT, + + /// + CLAMP, + + /// + CLAMP_TO_EDGE, + + /// + MIRRORED_REPEAT, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texture_unit + { + + private string surfaceField; + + private string sampler_stateField; + + private gles_texture_unitTexcoord texcoordField; + + private extra[] extraField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string surface + { + get + { + return this.surfaceField; + } + set + { + this.surfaceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string sampler_state + { + get + { + return this.sampler_stateField; + } + set + { + this.sampler_stateField = value; + } + } + + /// + public gles_texture_unitTexcoord texcoord + { + get + { + return this.texcoordField; + } + set + { + this.texcoordField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class gles_texture_unitTexcoord + { + + private string semanticField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_newparam + { + + private fx_annotate_common[] annotateField; + + private string semanticField; + + private fx_modifier_enum_common modifierField; + + private bool modifierFieldSpecified; + + private object itemField; + + private ItemChoiceType4 itemElementNameField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + public fx_modifier_enum_common modifier + { + get + { + return this.modifierField; + } + set + { + this.modifierField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool modifierSpecified + { + get + { + return this.modifierFieldSpecified; + } + set + { + this.modifierFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(cg_newarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("fixed", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(cg_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(cg_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(cg_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(cg_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(cg_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(cg_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("string", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(cg_surface_type))] + [System.Xml.Serialization.XmlElementAttribute("usertype", typeof(cg_setuser_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemChoiceType4 ItemElementName + { + get + { + return this.itemElementNameField; + } + set + { + this.itemElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_newarray_type + { + + private object[] itemsField; + + private ItemsChoiceType6[] itemsElementNameField; + + private string lengthField; + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(cg_newarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("connect_param", typeof(cg_connect_param))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("fixed", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(cg_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(cg_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(cg_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(cg_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(cg_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(cg_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("string", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(cg_surface_type))] + [System.Xml.Serialization.XmlElementAttribute("usertype", typeof(cg_setuser_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType6[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "positiveInteger")] + public string length + { + get + { + return this.lengthField; + } + set + { + this.lengthField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_connect_param + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_setuser_type + { + + private object[] itemsField; + + private ItemsChoiceType5[] itemsElementNameField; + + private string nameField; + + private string sourceField; + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(cg_setarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("connect_param", typeof(cg_connect_param))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("fixed", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(cg_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(cg_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(cg_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(cg_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(cg_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(cg_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("setparam", typeof(cg_setparam))] + [System.Xml.Serialization.XmlElementAttribute("string", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(cg_surface_type))] + [System.Xml.Serialization.XmlElementAttribute("usertype", typeof(cg_setuser_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType5[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_setarray_type + { + + private object[] itemsField; + + private ItemsChoiceType4[] itemsElementNameField; + + private string lengthField; + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(cg_setarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("fixed", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(cg_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(cg_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(cg_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(cg_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(cg_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(cg_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("string", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(cg_surface_type))] + [System.Xml.Serialization.XmlElementAttribute("usertype", typeof(cg_setuser_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType4[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "positiveInteger")] + public string length + { + get + { + return this.lengthField; + } + set + { + this.lengthField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType4 + { + + /// + array, + + /// + @bool, + + /// + bool1, + + /// + bool1x1, + + /// + bool1x2, + + /// + bool1x3, + + /// + bool1x4, + + /// + bool2, + + /// + bool2x1, + + /// + bool2x2, + + /// + bool2x3, + + /// + bool2x4, + + /// + bool3, + + /// + bool3x1, + + /// + bool3x2, + + /// + bool3x3, + + /// + bool3x4, + + /// + bool4, + + /// + bool4x1, + + /// + bool4x2, + + /// + bool4x3, + + /// + bool4x4, + + /// + @enum, + + /// + @fixed, + + /// + fixed1, + + /// + fixed1x1, + + /// + fixed1x2, + + /// + fixed1x3, + + /// + fixed1x4, + + /// + fixed2, + + /// + fixed2x1, + + /// + fixed2x2, + + /// + fixed2x3, + + /// + fixed2x4, + + /// + fixed3, + + /// + fixed3x1, + + /// + fixed3x2, + + /// + fixed3x3, + + /// + fixed3x4, + + /// + fixed4, + + /// + fixed4x1, + + /// + fixed4x2, + + /// + fixed4x3, + + /// + fixed4x4, + + /// + @float, + + /// + float1, + + /// + float1x1, + + /// + float1x2, + + /// + float1x3, + + /// + float1x4, + + /// + float2, + + /// + float2x1, + + /// + float2x2, + + /// + float2x3, + + /// + float2x4, + + /// + float3, + + /// + float3x1, + + /// + float3x2, + + /// + float3x3, + + /// + float3x4, + + /// + float4, + + /// + float4x1, + + /// + float4x2, + + /// + float4x3, + + /// + float4x4, + + /// + half, + + /// + half1, + + /// + half1x1, + + /// + half1x2, + + /// + half1x3, + + /// + half1x4, + + /// + half2, + + /// + half2x1, + + /// + half2x2, + + /// + half2x3, + + /// + half2x4, + + /// + half3, + + /// + half3x1, + + /// + half3x2, + + /// + half3x3, + + /// + half3x4, + + /// + half4, + + /// + half4x1, + + /// + half4x2, + + /// + half4x3, + + /// + half4x4, + + /// + @int, + + /// + int1, + + /// + int1x1, + + /// + int1x2, + + /// + int1x3, + + /// + int1x4, + + /// + int2, + + /// + int2x1, + + /// + int2x2, + + /// + int2x3, + + /// + int2x4, + + /// + int3, + + /// + int3x1, + + /// + int3x2, + + /// + int3x3, + + /// + int3x4, + + /// + int4, + + /// + int4x1, + + /// + int4x2, + + /// + int4x3, + + /// + int4x4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + @string, + + /// + surface, + + /// + usertype, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cg_setparam + { + + private object itemField; + + private ItemChoiceType3 itemElementNameField; + + private string refField; + + private string programField; + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(cg_setarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("connect_param", typeof(cg_connect_param))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("fixed", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(cg_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(cg_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(cg_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(cg_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(cg_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(cg_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("string", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(cg_surface_type))] + [System.Xml.Serialization.XmlElementAttribute("usertype", typeof(cg_setuser_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemChoiceType3 ItemElementName + { + get + { + return this.itemElementNameField; + } + set + { + this.itemElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string program + { + get + { + return this.programField; + } + set + { + this.programField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemChoiceType3 + { + + /// + array, + + /// + @bool, + + /// + bool1, + + /// + bool1x1, + + /// + bool1x2, + + /// + bool1x3, + + /// + bool1x4, + + /// + bool2, + + /// + bool2x1, + + /// + bool2x2, + + /// + bool2x3, + + /// + bool2x4, + + /// + bool3, + + /// + bool3x1, + + /// + bool3x2, + + /// + bool3x3, + + /// + bool3x4, + + /// + bool4, + + /// + bool4x1, + + /// + bool4x2, + + /// + bool4x3, + + /// + bool4x4, + + /// + connect_param, + + /// + @enum, + + /// + @fixed, + + /// + fixed1, + + /// + fixed1x1, + + /// + fixed1x2, + + /// + fixed1x3, + + /// + fixed1x4, + + /// + fixed2, + + /// + fixed2x1, + + /// + fixed2x2, + + /// + fixed2x3, + + /// + fixed2x4, + + /// + fixed3, + + /// + fixed3x1, + + /// + fixed3x2, + + /// + fixed3x3, + + /// + fixed3x4, + + /// + fixed4, + + /// + fixed4x1, + + /// + fixed4x2, + + /// + fixed4x3, + + /// + fixed4x4, + + /// + @float, + + /// + float1, + + /// + float1x1, + + /// + float1x2, + + /// + float1x3, + + /// + float1x4, + + /// + float2, + + /// + float2x1, + + /// + float2x2, + + /// + float2x3, + + /// + float2x4, + + /// + float3, + + /// + float3x1, + + /// + float3x2, + + /// + float3x3, + + /// + float3x4, + + /// + float4, + + /// + float4x1, + + /// + float4x2, + + /// + float4x3, + + /// + float4x4, + + /// + half, + + /// + half1, + + /// + half1x1, + + /// + half1x2, + + /// + half1x3, + + /// + half1x4, + + /// + half2, + + /// + half2x1, + + /// + half2x2, + + /// + half2x3, + + /// + half2x4, + + /// + half3, + + /// + half3x1, + + /// + half3x2, + + /// + half3x3, + + /// + half3x4, + + /// + half4, + + /// + half4x1, + + /// + half4x2, + + /// + half4x3, + + /// + half4x4, + + /// + @int, + + /// + int1, + + /// + int1x1, + + /// + int1x2, + + /// + int1x3, + + /// + int1x4, + + /// + int2, + + /// + int2x1, + + /// + int2x2, + + /// + int2x3, + + /// + int2x4, + + /// + int3, + + /// + int3x1, + + /// + int3x2, + + /// + int3x3, + + /// + int3x4, + + /// + int4, + + /// + int4x1, + + /// + int4x2, + + /// + int4x3, + + /// + int4x4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + @string, + + /// + surface, + + /// + usertype, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType5 + { + + /// + array, + + /// + @bool, + + /// + bool1, + + /// + bool1x1, + + /// + bool1x2, + + /// + bool1x3, + + /// + bool1x4, + + /// + bool2, + + /// + bool2x1, + + /// + bool2x2, + + /// + bool2x3, + + /// + bool2x4, + + /// + bool3, + + /// + bool3x1, + + /// + bool3x2, + + /// + bool3x3, + + /// + bool3x4, + + /// + bool4, + + /// + bool4x1, + + /// + bool4x2, + + /// + bool4x3, + + /// + bool4x4, + + /// + connect_param, + + /// + @enum, + + /// + @fixed, + + /// + fixed1, + + /// + fixed1x1, + + /// + fixed1x2, + + /// + fixed1x3, + + /// + fixed1x4, + + /// + fixed2, + + /// + fixed2x1, + + /// + fixed2x2, + + /// + fixed2x3, + + /// + fixed2x4, + + /// + fixed3, + + /// + fixed3x1, + + /// + fixed3x2, + + /// + fixed3x3, + + /// + fixed3x4, + + /// + fixed4, + + /// + fixed4x1, + + /// + fixed4x2, + + /// + fixed4x3, + + /// + fixed4x4, + + /// + @float, + + /// + float1, + + /// + float1x1, + + /// + float1x2, + + /// + float1x3, + + /// + float1x4, + + /// + float2, + + /// + float2x1, + + /// + float2x2, + + /// + float2x3, + + /// + float2x4, + + /// + float3, + + /// + float3x1, + + /// + float3x2, + + /// + float3x3, + + /// + float3x4, + + /// + float4, + + /// + float4x1, + + /// + float4x2, + + /// + float4x3, + + /// + float4x4, + + /// + half, + + /// + half1, + + /// + half1x1, + + /// + half1x2, + + /// + half1x3, + + /// + half1x4, + + /// + half2, + + /// + half2x1, + + /// + half2x2, + + /// + half2x3, + + /// + half2x4, + + /// + half3, + + /// + half3x1, + + /// + half3x2, + + /// + half3x3, + + /// + half3x4, + + /// + half4, + + /// + half4x1, + + /// + half4x2, + + /// + half4x3, + + /// + half4x4, + + /// + @int, + + /// + int1, + + /// + int1x1, + + /// + int1x2, + + /// + int1x3, + + /// + int1x4, + + /// + int2, + + /// + int2x1, + + /// + int2x2, + + /// + int2x3, + + /// + int2x4, + + /// + int3, + + /// + int3x1, + + /// + int3x2, + + /// + int3x3, + + /// + int3x4, + + /// + int4, + + /// + int4x1, + + /// + int4x2, + + /// + int4x3, + + /// + int4x4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + setparam, + + /// + @string, + + /// + surface, + + /// + usertype, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType6 + { + + /// + array, + + /// + @bool, + + /// + bool1, + + /// + bool1x1, + + /// + bool1x2, + + /// + bool1x3, + + /// + bool1x4, + + /// + bool2, + + /// + bool2x1, + + /// + bool2x2, + + /// + bool2x3, + + /// + bool2x4, + + /// + bool3, + + /// + bool3x1, + + /// + bool3x2, + + /// + bool3x3, + + /// + bool3x4, + + /// + bool4, + + /// + bool4x1, + + /// + bool4x2, + + /// + bool4x3, + + /// + bool4x4, + + /// + connect_param, + + /// + @enum, + + /// + @fixed, + + /// + fixed1, + + /// + fixed1x1, + + /// + fixed1x2, + + /// + fixed1x3, + + /// + fixed1x4, + + /// + fixed2, + + /// + fixed2x1, + + /// + fixed2x2, + + /// + fixed2x3, + + /// + fixed2x4, + + /// + fixed3, + + /// + fixed3x1, + + /// + fixed3x2, + + /// + fixed3x3, + + /// + fixed3x4, + + /// + fixed4, + + /// + fixed4x1, + + /// + fixed4x2, + + /// + fixed4x3, + + /// + fixed4x4, + + /// + @float, + + /// + float1, + + /// + float1x1, + + /// + float1x2, + + /// + float1x3, + + /// + float1x4, + + /// + float2, + + /// + float2x1, + + /// + float2x2, + + /// + float2x3, + + /// + float2x4, + + /// + float3, + + /// + float3x1, + + /// + float3x2, + + /// + float3x3, + + /// + float3x4, + + /// + float4, + + /// + float4x1, + + /// + float4x2, + + /// + float4x3, + + /// + float4x4, + + /// + half, + + /// + half1, + + /// + half1x1, + + /// + half1x2, + + /// + half1x3, + + /// + half1x4, + + /// + half2, + + /// + half2x1, + + /// + half2x2, + + /// + half2x3, + + /// + half2x4, + + /// + half3, + + /// + half3x1, + + /// + half3x2, + + /// + half3x3, + + /// + half3x4, + + /// + half4, + + /// + half4x1, + + /// + half4x2, + + /// + half4x3, + + /// + half4x4, + + /// + @int, + + /// + int1, + + /// + int1x1, + + /// + int1x2, + + /// + int1x3, + + /// + int1x4, + + /// + int2, + + /// + int2x1, + + /// + int2x2, + + /// + int2x3, + + /// + int2x4, + + /// + int3, + + /// + int3x1, + + /// + int3x2, + + /// + int3x3, + + /// + int3x4, + + /// + int4, + + /// + int4x1, + + /// + int4x2, + + /// + int4x3, + + /// + int4x4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + @string, + + /// + surface, + + /// + usertype, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemChoiceType4 + { + + /// + array, + + /// + @bool, + + /// + bool1, + + /// + bool1x1, + + /// + bool1x2, + + /// + bool1x3, + + /// + bool1x4, + + /// + bool2, + + /// + bool2x1, + + /// + bool2x2, + + /// + bool2x3, + + /// + bool2x4, + + /// + bool3, + + /// + bool3x1, + + /// + bool3x2, + + /// + bool3x3, + + /// + bool3x4, + + /// + bool4, + + /// + bool4x1, + + /// + bool4x2, + + /// + bool4x3, + + /// + bool4x4, + + /// + @enum, + + /// + @fixed, + + /// + fixed1, + + /// + fixed1x1, + + /// + fixed1x2, + + /// + fixed1x3, + + /// + fixed1x4, + + /// + fixed2, + + /// + fixed2x1, + + /// + fixed2x2, + + /// + fixed2x3, + + /// + fixed2x4, + + /// + fixed3, + + /// + fixed3x1, + + /// + fixed3x2, + + /// + fixed3x3, + + /// + fixed3x4, + + /// + fixed4, + + /// + fixed4x1, + + /// + fixed4x2, + + /// + fixed4x3, + + /// + fixed4x4, + + /// + @float, + + /// + float1, + + /// + float1x1, + + /// + float1x2, + + /// + float1x3, + + /// + float1x4, + + /// + float2, + + /// + float2x1, + + /// + float2x2, + + /// + float2x3, + + /// + float2x4, + + /// + float3, + + /// + float3x1, + + /// + float3x2, + + /// + float3x3, + + /// + float3x4, + + /// + float4, + + /// + float4x1, + + /// + float4x2, + + /// + float4x3, + + /// + float4x4, + + /// + half, + + /// + half1, + + /// + half1x1, + + /// + half1x2, + + /// + half1x3, + + /// + half1x4, + + /// + half2, + + /// + half2x1, + + /// + half2x2, + + /// + half2x3, + + /// + half2x4, + + /// + half3, + + /// + half3x1, + + /// + half3x2, + + /// + half3x3, + + /// + half3x4, + + /// + half4, + + /// + half4x1, + + /// + half4x2, + + /// + half4x3, + + /// + half4x4, + + /// + @int, + + /// + int1, + + /// + int1x1, + + /// + int1x2, + + /// + int1x3, + + /// + int1x4, + + /// + int2, + + /// + int2x1, + + /// + int2x2, + + /// + int2x3, + + /// + int2x4, + + /// + int3, + + /// + int3x1, + + /// + int3x2, + + /// + int3x3, + + /// + int3x4, + + /// + int4, + + /// + int4x1, + + /// + int4x2, + + /// + int4x3, + + /// + int4x4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + @string, + + /// + surface, + + /// + usertype, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_newparam_type + { + + private string semanticField; + + private object itemField; + + private ItemChoiceType2 itemElementNameField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("float", typeof(double))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(double))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(double))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(double))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(fx_sampler2D_common))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(fx_surface_common))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemChoiceType2 ItemElementName + { + get + { + return this.itemElementNameField; + } + set + { + this.itemElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemChoiceType2 + { + + /// + @float, + + /// + float2, + + /// + float3, + + /// + float4, + + /// + sampler2D, + + /// + surface, + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(common_transparent_type))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_color_or_texture_type + { + + private object itemField; + + /// + [System.Xml.Serialization.XmlElementAttribute("color", typeof(common_color_or_texture_typeColor))] + [System.Xml.Serialization.XmlElementAttribute("param", typeof(common_color_or_texture_typeParam))] + [System.Xml.Serialization.XmlElementAttribute("texture", typeof(common_color_or_texture_typeTexture))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_color_or_texture_typeColor + { + + private string sidField; + + private double[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_color_or_texture_typeParam + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_color_or_texture_typeTexture + { + + private extra extraField; + + private string textureField; + + private string texcoordField; + + /// + public extra extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string texture + { + get + { + return this.textureField; + } + set + { + this.textureField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string texcoord + { + get + { + return this.texcoordField; + } + set + { + this.texcoordField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_transparent_type : common_color_or_texture_type + { + + private fx_opaque_enum opaqueField; + + public common_transparent_type() + { + this.opaqueField = fx_opaque_enum.A_ONE; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(fx_opaque_enum.A_ONE)] + public fx_opaque_enum opaque + { + get + { + return this.opaqueField; + } + set + { + this.opaqueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum fx_opaque_enum + { + + /// + A_ONE, + + /// + RGB_ZERO, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_float_or_param_type + { + + private object itemField; + + /// + [System.Xml.Serialization.XmlElementAttribute("float", typeof(common_float_or_param_typeFloat))] + [System.Xml.Serialization.XmlElementAttribute("param", typeof(common_float_or_param_typeParam))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_float_or_param_typeFloat + { + + private string sidField; + + private double valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public double Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class common_float_or_param_typeParam + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_setparam + { + + private fx_annotate_common[] annotateField; + + private object itemField; + + private ItemChoiceType1 itemElementNameField; + + private string refField; + + private string programField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(glsl_setarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(gl_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(gl_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(gl_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(gl_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(gl_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(gl_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(glsl_surface_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemChoiceType1 ItemElementName + { + get + { + return this.itemElementNameField; + } + set + { + this.itemElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string program + { + get + { + return this.programField; + } + set + { + this.programField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_setarray_type + { + + private object[] itemsField; + + private ItemsChoiceType3[] itemsElementNameField; + + private string lengthField; + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(glsl_setarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(gl_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(gl_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(gl_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(gl_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(gl_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(gl_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(glsl_surface_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType3[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "positiveInteger")] + public string length + { + get + { + return this.lengthField; + } + set + { + this.lengthField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType3 + { + + /// + array, + + /// + @bool, + + /// + bool2, + + /// + bool3, + + /// + bool4, + + /// + @enum, + + /// + @float, + + /// + float2, + + /// + float2x2, + + /// + float3, + + /// + float3x3, + + /// + float4, + + /// + float4x4, + + /// + @int, + + /// + int2, + + /// + int3, + + /// + int4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + surface, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemChoiceType1 + { + + /// + array, + + /// + @bool, + + /// + bool2, + + /// + bool3, + + /// + bool4, + + /// + @enum, + + /// + @float, + + /// + float2, + + /// + float2x2, + + /// + float3, + + /// + float3x3, + + /// + float4, + + /// + float4x4, + + /// + @int, + + /// + int2, + + /// + int3, + + /// + int4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + surface, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_newparam + { + + private fx_annotate_common[] annotateField; + + private string semanticField; + + private fx_modifier_enum_common modifierField; + + private bool modifierFieldSpecified; + + private object itemField; + + private ItemChoiceType itemElementNameField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + public fx_modifier_enum_common modifier + { + get + { + return this.modifierField; + } + set + { + this.modifierField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool modifierSpecified + { + get + { + return this.modifierFieldSpecified; + } + set + { + this.modifierFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(glsl_newarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(gl_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(gl_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(gl_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(gl_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(gl_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(gl_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(glsl_surface_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemChoiceType ItemElementName + { + get + { + return this.itemElementNameField; + } + set + { + this.itemElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class glsl_newarray_type + { + + private object[] itemsField; + + private ItemsChoiceType2[] itemsElementNameField; + + private string lengthField; + + /// + [System.Xml.Serialization.XmlElementAttribute("array", typeof(glsl_newarray_type))] + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(gl_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(gl_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(gl_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(gl_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(gl_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(gl_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(glsl_surface_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType2[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "positiveInteger")] + public string length + { + get + { + return this.lengthField; + } + set + { + this.lengthField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType2 + { + + /// + array, + + /// + @bool, + + /// + bool2, + + /// + bool3, + + /// + bool4, + + /// + @enum, + + /// + @float, + + /// + float2, + + /// + float2x2, + + /// + float3, + + /// + float3x3, + + /// + float4, + + /// + float4x4, + + /// + @int, + + /// + int2, + + /// + int3, + + /// + int4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + surface, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemChoiceType + { + + /// + array, + + /// + @bool, + + /// + bool2, + + /// + bool3, + + /// + bool4, + + /// + @enum, + + /// + @float, + + /// + float2, + + /// + float2x2, + + /// + float3, + + /// + float3x3, + + /// + float4, + + /// + float4x4, + + /// + @int, + + /// + int2, + + /// + int3, + + /// + int4, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + surface, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class InputGlobal + { + + private string semanticField; + + private string sourceField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class fx_newparam_common + { + + private fx_annotate_common[] annotateField; + + private string semanticField; + + private fx_modifier_enum_common modifierField; + + private bool modifierFieldSpecified; + + private bool boolField; + + private string bool2Field; + + private string bool3Field; + + private string bool4Field; + + private long intField; + + private string int2Field; + + private string int3Field; + + private string int4Field; + + private double floatField; + + private string float2Field; + + private string float3Field; + + private string float4Field; + + private double float1x1Field; + + private string float1x2Field; + + private string float1x3Field; + + private string float1x4Field; + + private string float2x1Field; + + private string float2x2Field; + + private string float2x3Field; + + private string float2x4Field; + + private string float3x1Field; + + private string float3x2Field; + + private string float3x3Field; + + private string float3x4Field; + + private string float4x1Field; + + private string float4x2Field; + + private string float4x3Field; + + private string float4x4Field; + + private fx_surface_common surfaceField; + + private fx_sampler1D_common sampler1DField; + + private fx_sampler2D_common sampler2DField; + + private fx_sampler3D_common sampler3DField; + + private fx_samplerCUBE_common samplerCUBEField; + + private fx_samplerRECT_common samplerRECTField; + + private fx_samplerDEPTH_common samplerDEPTHField; + + private string enumField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + public fx_modifier_enum_common modifier + { + get + { + return this.modifierField; + } + set + { + this.modifierField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool modifierSpecified + { + get + { + return this.modifierFieldSpecified; + } + set + { + this.modifierFieldSpecified = value; + } + } + + /// + public bool @bool + { + get + { + return this.boolField; + } + set + { + this.boolField = value; + } + } + + /// + public string bool2 + { + get + { + return this.bool2Field; + } + set + { + this.bool2Field = value; + } + } + + /// + public string bool3 + { + get + { + return this.bool3Field; + } + set + { + this.bool3Field = value; + } + } + + /// + public string bool4 + { + get + { + return this.bool4Field; + } + set + { + this.bool4Field = value; + } + } + + /// + public long @int + { + get + { + return this.intField; + } + set + { + this.intField = value; + } + } + + /// + public string int2 + { + get + { + return this.int2Field; + } + set + { + this.int2Field = value; + } + } + + /// + public string int3 + { + get + { + return this.int3Field; + } + set + { + this.int3Field = value; + } + } + + /// + public string int4 + { + get + { + return this.int4Field; + } + set + { + this.int4Field = value; + } + } + + /// + public double @float + { + get + { + return this.floatField; + } + set + { + this.floatField = value; + } + } + + /// + public string float2 + { + get + { + return this.float2Field; + } + set + { + this.float2Field = value; + } + } + + /// + public string float3 + { + get + { + return this.float3Field; + } + set + { + this.float3Field = value; + } + } + + /// + public string float4 + { + get + { + return this.float4Field; + } + set + { + this.float4Field = value; + } + } + + /// + public double float1x1 + { + get + { + return this.float1x1Field; + } + set + { + this.float1x1Field = value; + } + } + + /// + public string float1x2 + { + get + { + return this.float1x2Field; + } + set + { + this.float1x2Field = value; + } + } + + /// + public string float1x3 + { + get + { + return this.float1x3Field; + } + set + { + this.float1x3Field = value; + } + } + + /// + public string float1x4 + { + get + { + return this.float1x4Field; + } + set + { + this.float1x4Field = value; + } + } + + /// + public string float2x1 + { + get + { + return this.float2x1Field; + } + set + { + this.float2x1Field = value; + } + } + + /// + public string float2x2 + { + get + { + return this.float2x2Field; + } + set + { + this.float2x2Field = value; + } + } + + /// + public string float2x3 + { + get + { + return this.float2x3Field; + } + set + { + this.float2x3Field = value; + } + } + + /// + public string float2x4 + { + get + { + return this.float2x4Field; + } + set + { + this.float2x4Field = value; + } + } + + /// + public string float3x1 + { + get + { + return this.float3x1Field; + } + set + { + this.float3x1Field = value; + } + } + + /// + public string float3x2 + { + get + { + return this.float3x2Field; + } + set + { + this.float3x2Field = value; + } + } + + /// + public string float3x3 + { + get + { + return this.float3x3Field; + } + set + { + this.float3x3Field = value; + } + } + + /// + public string float3x4 + { + get + { + return this.float3x4Field; + } + set + { + this.float3x4Field = value; + } + } + + /// + public string float4x1 + { + get + { + return this.float4x1Field; + } + set + { + this.float4x1Field = value; + } + } + + /// + public string float4x2 + { + get + { + return this.float4x2Field; + } + set + { + this.float4x2Field = value; + } + } + + /// + public string float4x3 + { + get + { + return this.float4x3Field; + } + set + { + this.float4x3Field = value; + } + } + + /// + public string float4x4 + { + get + { + return this.float4x4Field; + } + set + { + this.float4x4Field = value; + } + } + + /// + public fx_surface_common surface + { + get + { + return this.surfaceField; + } + set + { + this.surfaceField = value; + } + } + + /// + public fx_sampler1D_common sampler1D + { + get + { + return this.sampler1DField; + } + set + { + this.sampler1DField = value; + } + } + + /// + public fx_sampler2D_common sampler2D + { + get + { + return this.sampler2DField; + } + set + { + this.sampler2DField = value; + } + } + + /// + public fx_sampler3D_common sampler3D + { + get + { + return this.sampler3DField; + } + set + { + this.sampler3DField = value; + } + } + + /// + public fx_samplerCUBE_common samplerCUBE + { + get + { + return this.samplerCUBEField; + } + set + { + this.samplerCUBEField = value; + } + } + + /// + public fx_samplerRECT_common samplerRECT + { + get + { + return this.samplerRECTField; + } + set + { + this.samplerRECTField = value; + } + } + + /// + public fx_samplerDEPTH_common samplerDEPTH + { + get + { + return this.samplerDEPTHField; + } + set + { + this.samplerDEPTHField = value; + } + } + + /// + public string @enum + { + get + { + return this.enumField; + } + set + { + this.enumField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class InputLocalOffset + { + + private ulong offsetField; + + private string semanticField; + + private string sourceField; + + private ulong setField; + + private bool setFieldSpecified; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong offset + { + get + { + return this.offsetField; + } + set + { + this.offsetField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong set + { + get + { + return this.setField; + } + set + { + this.setField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool setSpecified + { + get + { + return this.setFieldSpecified; + } + set + { + this.setFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class TargetableFloat + { + + private string sidField; + + private double valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public double Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class InputLocal + { + + private string semanticField; + + private string sourceField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class instance_material + { + + private instance_materialBind[] bindField; + + private instance_materialBind_vertex_input[] bind_vertex_inputField; + + private extra[] extraField; + + private string symbolField; + + private string targetField; + + private string sidField; + + private string nameField; + + /// + [System.Xml.Serialization.XmlElementAttribute("bind")] + public instance_materialBind[] bind + { + get + { + return this.bindField; + } + set + { + this.bindField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("bind_vertex_input")] + public instance_materialBind_vertex_input[] bind_vertex_input + { + get + { + return this.bind_vertex_inputField; + } + set + { + this.bind_vertex_inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string symbol + { + get + { + return this.symbolField; + } + set + { + this.symbolField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string target + { + get + { + return this.targetField; + } + set + { + this.targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_materialBind + { + + private string semanticField; + + private string targetField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string target + { + get + { + return this.targetField; + } + set + { + this.targetField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_materialBind_vertex_input + { + + private string semanticField; + + private string input_semanticField; + + private ulong input_setField; + + private bool input_setFieldSpecified; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string input_semantic + { + get + { + return this.input_semanticField; + } + set + { + this.input_semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong input_set + { + get + { + return this.input_setField; + } + set + { + this.input_setField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool input_setSpecified + { + get + { + return this.input_setFieldSpecified; + } + set + { + this.input_setFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class assetUnit + { + + private double meterField; + + private string nameField; + + public assetUnit() + { + this.meterField = 1D; + this.nameField = "meter"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double meter + { + get + { + return this.meterField; + } + set + { + this.meterField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + [System.ComponentModel.DefaultValueAttribute("meter")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum UpAxisType + { + + /// + X_UP, + + /// + Y_UP, + + /// + Z_UP, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_animation_clips + { + + private asset assetField; + + private animation_clip[] animation_clipField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("animation_clip")] + public animation_clip[] animation_clip + { + get + { + return this.animation_clipField; + } + set + { + this.animation_clipField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class animation_clip + { + + private asset assetField; + + private InstanceWithExtra[] instance_animationField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + private double startField; + + private double endField; + + private bool endFieldSpecified; + + public animation_clip() + { + this.startField = 0D; + } + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_animation")] + public InstanceWithExtra[] instance_animation + { + get + { + return this.instance_animationField; + } + set + { + this.instance_animationField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double start + { + get + { + return this.startField; + } + set + { + this.startField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public double end + { + get + { + return this.endField; + } + set + { + this.endField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool endSpecified + { + get + { + return this.endFieldSpecified; + } + set + { + this.endFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute("instance_camera", Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class InstanceWithExtra + { + + private extra[] extraField; + + private string urlField; + + private string sidField; + + private string nameField; + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string url + { + get + { + return this.urlField; + } + set + { + this.urlField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_animations + { + + private asset assetField; + + private animation[] animationField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("animation")] + public animation[] animation + { + get + { + return this.animationField; + } + set + { + this.animationField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class animation + { + + private asset assetField; + + private object[] itemsField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("animation", typeof(animation))] + [System.Xml.Serialization.XmlElementAttribute("channel", typeof(channel))] + [System.Xml.Serialization.XmlElementAttribute("sampler", typeof(sampler))] + [System.Xml.Serialization.XmlElementAttribute("source", typeof(source))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class channel + { + + private string sourceField; + + private string targetField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string target + { + get + { + return this.targetField; + } + set + { + this.targetField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class sampler + { + + private InputLocal[] inputField; + + private string idField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocal[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class source + { + + private asset assetField; + + private object itemField; + + private sourceTechnique_common technique_commonField; + + private technique[] techniqueField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("IDREF_array", typeof(IDREF_array))] + [System.Xml.Serialization.XmlElementAttribute("Name_array", typeof(Name_array))] + [System.Xml.Serialization.XmlElementAttribute("bool_array", typeof(bool_array))] + [System.Xml.Serialization.XmlElementAttribute("float_array", typeof(float_array))] + [System.Xml.Serialization.XmlElementAttribute("int_array", typeof(int_array))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + public sourceTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class IDREF_array + { + + private string idField; + + private string nameField; + + private ulong countField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "IDREFS")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class Name_array + { + + private string idField; + + private string nameField; + + private ulong countField; + + private string[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertNameArray(value); } + } + + /// + [XmlIgnore] + public string[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class bool_array + { + + private string idField; + + private string nameField; + + private ulong countField; + + private bool[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertBoolArray(value); } + } + + /// + [XmlIgnore] + public bool[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class float_array + { + + private string idField; + + private string nameField; + + private ulong countField; + + private short digitsField; + + private short magnitudeField; + + private double[] textField; + + public float_array() + { + this.digitsField = ((short)(6)); + this.magnitudeField = ((short)(38)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(short), "6")] + public short digits + { + get + { + return this.digitsField; + } + set + { + this.digitsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(short), "38")] + public short magnitude + { + get + { + return this.magnitudeField; + } + set + { + this.magnitudeField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class int_array + { + + private string idField; + + private string nameField; + + private ulong countField; + + private string minInclusiveField; + + private string maxInclusiveField; + + private long[] textField; + + public int_array() + { + this.minInclusiveField = "-2147483648"; + this.maxInclusiveField = "2147483647"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "integer")] + [System.ComponentModel.DefaultValueAttribute("-2147483648")] + public string minInclusive + { + get + { + return this.minInclusiveField; + } + set + { + this.minInclusiveField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "integer")] + [System.ComponentModel.DefaultValueAttribute("2147483647")] + public string maxInclusive + { + get + { + return this.maxInclusiveField; + } + set + { + this.maxInclusiveField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertLongArray(value); } + } + + /// + [XmlIgnore] + public long[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class sourceTechnique_common + { + + private accessor accessorField; + + /// + public accessor accessor + { + get + { + return this.accessorField; + } + set + { + this.accessorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class accessor + { + + private param[] paramField; + + private ulong countField; + + private ulong offsetField; + + private string sourceField; + + private ulong strideField; + + public accessor() + { + this.offsetField = ((ulong)(0m)); + this.strideField = ((ulong)(1m)); + } + + /// + [System.Xml.Serialization.XmlElementAttribute("param")] + public param[] param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(ulong), "0")] + public ulong offset + { + get + { + return this.offsetField; + } + set + { + this.offsetField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(ulong), "1")] + public ulong stride + { + get + { + return this.strideField; + } + set + { + this.strideField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class param + { + + private string nameField; + + private string sidField; + + private string semanticField; + + private string typeField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + public string semantic + { + get + { + return this.semanticField; + } + set + { + this.semanticField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NMTOKEN")] + public string type + { + get + { + return this.typeField; + } + set + { + this.typeField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_cameras + { + + private asset assetField; + + private camera[] cameraField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("camera")] + public camera[] camera + { + get + { + return this.cameraField; + } + set + { + this.cameraField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class camera + { + + private asset assetField; + + private cameraOptics opticsField; + + private cameraImager imagerField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + public cameraOptics optics + { + get + { + return this.opticsField; + } + set + { + this.opticsField = value; + } + } + + /// + public cameraImager imager + { + get + { + return this.imagerField; + } + set + { + this.imagerField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cameraOptics + { + + private cameraOpticsTechnique_common technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + /// + public cameraOpticsTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cameraOpticsTechnique_common + { + + private object itemField; + + /// + [System.Xml.Serialization.XmlElementAttribute("orthographic", typeof(cameraOpticsTechnique_commonOrthographic))] + [System.Xml.Serialization.XmlElementAttribute("perspective", typeof(cameraOpticsTechnique_commonPerspective))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cameraOpticsTechnique_commonOrthographic + { + + private TargetableFloat[] itemsField; + + private ItemsChoiceType[] itemsElementNameField; + + private TargetableFloat znearField; + + private TargetableFloat zfarField; + + /// + [System.Xml.Serialization.XmlElementAttribute("aspect_ratio", typeof(TargetableFloat))] + [System.Xml.Serialization.XmlElementAttribute("xmag", typeof(TargetableFloat))] + [System.Xml.Serialization.XmlElementAttribute("ymag", typeof(TargetableFloat))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public TargetableFloat[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + public TargetableFloat znear + { + get + { + return this.znearField; + } + set + { + this.znearField = value; + } + } + + /// + public TargetableFloat zfar + { + get + { + return this.zfarField; + } + set + { + this.zfarField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType + { + + /// + aspect_ratio, + + /// + xmag, + + /// + ymag, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cameraOpticsTechnique_commonPerspective + { + + private TargetableFloat[] itemsField; + + private ItemsChoiceType1[] itemsElementNameField; + + private TargetableFloat znearField; + + private TargetableFloat zfarField; + + /// + [System.Xml.Serialization.XmlElementAttribute("aspect_ratio", typeof(TargetableFloat))] + [System.Xml.Serialization.XmlElementAttribute("xfov", typeof(TargetableFloat))] + [System.Xml.Serialization.XmlElementAttribute("yfov", typeof(TargetableFloat))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public TargetableFloat[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType1[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + public TargetableFloat znear + { + get + { + return this.znearField; + } + set + { + this.znearField = value; + } + } + + /// + public TargetableFloat zfar + { + get + { + return this.zfarField; + } + set + { + this.zfarField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType1 + { + + /// + aspect_ratio, + + /// + xfov, + + /// + yfov, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class cameraImager + { + + private technique[] techniqueField; + + private extra[] extraField; + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_controllers + { + + private asset assetField; + + private controller[] controllerField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("controller")] + public controller[] controller + { + get + { + return this.controllerField; + } + set + { + this.controllerField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class controller + { + + private asset assetField; + + private object itemField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("morph", typeof(morph))] + [System.Xml.Serialization.XmlElementAttribute("skin", typeof(skin))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class morph + { + + private source[] sourceField; + + private morphTargets targetsField; + + private extra[] extraField; + + private MorphMethodType methodField; + + private string source1Field; + + public morph() + { + this.methodField = MorphMethodType.NORMALIZED; + } + + /// + [System.Xml.Serialization.XmlElementAttribute("source")] + public source[] source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + public morphTargets targets + { + get + { + return this.targetsField; + } + set + { + this.targetsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(MorphMethodType.NORMALIZED)] + public MorphMethodType method + { + get + { + return this.methodField; + } + set + { + this.methodField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute("source", DataType = "anyURI")] + public string source1 + { + get + { + return this.source1Field; + } + set + { + this.source1Field = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class morphTargets + { + + private InputLocal[] inputField; + + private extra[] extraField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocal[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum MorphMethodType + { + + /// + NORMALIZED, + + /// + RELATIVE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class skin + { + + private string bind_shape_matrixField; + + private source[] sourceField; + + private skinJoints jointsField; + + private skinVertex_weights vertex_weightsField; + + private extra[] extraField; + + private string source1Field; + + /// + public string bind_shape_matrix + { + get + { + return this.bind_shape_matrixField; + } + set + { + this.bind_shape_matrixField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("source")] + public source[] source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + public skinJoints joints + { + get + { + return this.jointsField; + } + set + { + this.jointsField = value; + } + } + + /// + public skinVertex_weights vertex_weights + { + get + { + return this.vertex_weightsField; + } + set + { + this.vertex_weightsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute("source", DataType = "anyURI")] + public string source1 + { + get + { + return this.source1Field; + } + set + { + this.source1Field = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class skinJoints + { + + private InputLocal[] inputField; + + private extra[] extraField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocal[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class skinVertex_weights + { + + private InputLocalOffset[] inputField; + + private string vcountField; + + private string vField; + + private extra[] extraField; + + private ulong countField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + public string vcount + { + get + { + return this.vcountField; + } + set + { + this.vcountField = value; + } + } + + /// + public string v + { + get + { + return this.vField; + } + set + { + this.vField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_effects + { + + private asset assetField; + + private effect[] effectField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("effect")] + public effect[] effect + { + get + { + return this.effectField; + } + set + { + this.effectField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class effect + { + + private asset assetField; + + private fx_annotate_common[] annotateField; + + private image[] imageField; + + private fx_newparam_common[] newparamField; + + private object[] itemsField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image")] + public image[] image + { + get + { + return this.imageField; + } + set + { + this.imageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("newparam")] + public fx_newparam_common[] newparam + { + get + { + return this.newparamField; + } + set + { + this.newparamField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("profile_CG", typeof(effectFx_profile_abstractProfile_CG))] + [System.Xml.Serialization.XmlElementAttribute("profile_COMMON", typeof(effectFx_profile_abstractProfile_COMMON))] + [System.Xml.Serialization.XmlElementAttribute("profile_GLES", typeof(effectFx_profile_abstractProfile_GLES))] + [System.Xml.Serialization.XmlElementAttribute("profile_GLSL", typeof(effectFx_profile_abstractProfile_GLSL))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class image + { + + private asset assetField; + + private object itemField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + private string formatField; + + private ulong heightField; + + private bool heightFieldSpecified; + + private ulong widthField; + + private bool widthFieldSpecified; + + private ulong depthField; + + public image() + { + this.depthField = ((ulong)(1m)); + } + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("data", typeof(byte[]), DataType = "hexBinary")] + [System.Xml.Serialization.XmlElementAttribute("init_from", typeof(string), DataType = "anyURI")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string format + { + get + { + return this.formatField; + } + set + { + this.formatField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong height + { + get + { + return this.heightField; + } + set + { + this.heightField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool heightSpecified + { + get + { + return this.heightFieldSpecified; + } + set + { + this.heightFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong width + { + get + { + return this.widthField; + } + set + { + this.widthField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool widthSpecified + { + get + { + return this.widthFieldSpecified; + } + set + { + this.widthFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(ulong), "1")] + public ulong depth + { + get + { + return this.depthField; + } + set + { + this.depthField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute("profile_CG", Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class effectFx_profile_abstractProfile_CG + { + + private asset assetField; + + private object[] itemsField; + + private object[] items1Field; + + private effectFx_profile_abstractProfile_CGTechnique[] techniqueField; + + private extra[] extraField; + + private string idField; + + private string platformField; + + public effectFx_profile_abstractProfile_CG() + { + this.platformField = "PC"; + } + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("code", typeof(fx_code_profile))] + [System.Xml.Serialization.XmlElementAttribute("include", typeof(fx_include_common))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(cg_newparam))] + public object[] Items1 + { + get + { + return this.items1Field; + } + set + { + this.items1Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public effectFx_profile_abstractProfile_CGTechnique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + [System.ComponentModel.DefaultValueAttribute("PC")] + public string platform + { + get + { + return this.platformField; + } + set + { + this.platformField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_CGTechnique + { + + private asset assetField; + + private fx_annotate_common[] annotateField; + + private object[] itemsField; + + private object[] items1Field; + + private effectFx_profile_abstractProfile_CGTechniquePass[] passField; + + private extra[] extraField; + + private string idField; + + private string sidField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("code", typeof(fx_code_profile))] + [System.Xml.Serialization.XmlElementAttribute("include", typeof(fx_include_common))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(cg_newparam))] + [System.Xml.Serialization.XmlElementAttribute("setparam", typeof(cg_setparam))] + public object[] Items1 + { + get + { + return this.items1Field; + } + set + { + this.items1Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("pass")] + public effectFx_profile_abstractProfile_CGTechniquePass[] pass + { + get + { + return this.passField; + } + set + { + this.passField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_CGTechniquePass + { + + private fx_annotate_common[] annotateField; + + private fx_colortarget_common[] color_targetField; + + private fx_depthtarget_common[] depth_targetField; + + private fx_stenciltarget_common[] stencil_targetField; + + private fx_clearcolor_common[] color_clearField; + + private fx_cleardepth_common[] depth_clearField; + + private fx_clearstencil_common[] stencil_clearField; + + private string drawField; + + private object[] itemsField; + + private extra[] extraField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("color_target")] + public fx_colortarget_common[] color_target + { + get + { + return this.color_targetField; + } + set + { + this.color_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("depth_target")] + public fx_depthtarget_common[] depth_target + { + get + { + return this.depth_targetField; + } + set + { + this.depth_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("stencil_target")] + public fx_stenciltarget_common[] stencil_target + { + get + { + return this.stencil_targetField; + } + set + { + this.stencil_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("color_clear")] + public fx_clearcolor_common[] color_clear + { + get + { + return this.color_clearField; + } + set + { + this.color_clearField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("depth_clear")] + public fx_cleardepth_common[] depth_clear + { + get + { + return this.depth_clearField; + } + set + { + this.depth_clearField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("stencil_clear")] + public fx_clearstencil_common[] stencil_clear + { + get + { + return this.stencil_clearField; + } + set + { + this.stencil_clearField = value; + } + } + + /// + public string draw + { + get + { + return this.drawField; + } + set + { + this.drawField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("alpha_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_func))] + [System.Xml.Serialization.XmlElementAttribute("alpha_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("auto_normal_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassAuto_normal_enable))] + [System.Xml.Serialization.XmlElementAttribute("blend_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_color))] + [System.Xml.Serialization.XmlElementAttribute("blend_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_enable))] + [System.Xml.Serialization.XmlElementAttribute("blend_equation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation))] + [System.Xml.Serialization.XmlElementAttribute("blend_equation_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separate))] + [System.Xml.Serialization.XmlElementAttribute("blend_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func))] + [System.Xml.Serialization.XmlElementAttribute("blend_func_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separate))] + [System.Xml.Serialization.XmlElementAttribute("clear_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClear_color))] + [System.Xml.Serialization.XmlElementAttribute("clear_depth", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClear_depth))] + [System.Xml.Serialization.XmlElementAttribute("clear_stencil", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClear_stencil))] + [System.Xml.Serialization.XmlElementAttribute("clip_plane", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane))] + [System.Xml.Serialization.XmlElementAttribute("clip_plane_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane_enable))] + [System.Xml.Serialization.XmlElementAttribute("color_logic_op_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_logic_op_enable))] + [System.Xml.Serialization.XmlElementAttribute("color_mask", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_mask))] + [System.Xml.Serialization.XmlElementAttribute("color_material", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_material))] + [System.Xml.Serialization.XmlElementAttribute("color_material_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_material_enable))] + [System.Xml.Serialization.XmlElementAttribute("cull_face", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassCull_face))] + [System.Xml.Serialization.XmlElementAttribute("cull_face_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassCull_face_enable))] + [System.Xml.Serialization.XmlElementAttribute("depth_bounds", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_bounds))] + [System.Xml.Serialization.XmlElementAttribute("depth_bounds_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_bounds_enable))] + [System.Xml.Serialization.XmlElementAttribute("depth_clamp_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_clamp_enable))] + [System.Xml.Serialization.XmlElementAttribute("depth_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_func))] + [System.Xml.Serialization.XmlElementAttribute("depth_mask", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_mask))] + [System.Xml.Serialization.XmlElementAttribute("depth_range", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_range))] + [System.Xml.Serialization.XmlElementAttribute("depth_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("dither_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDither_enable))] + [System.Xml.Serialization.XmlElementAttribute("fog_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_color))] + [System.Xml.Serialization.XmlElementAttribute("fog_coord_src", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_coord_src))] + [System.Xml.Serialization.XmlElementAttribute("fog_density", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_density))] + [System.Xml.Serialization.XmlElementAttribute("fog_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_enable))] + [System.Xml.Serialization.XmlElementAttribute("fog_end", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_end))] + [System.Xml.Serialization.XmlElementAttribute("fog_mode", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_mode))] + [System.Xml.Serialization.XmlElementAttribute("fog_start", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_start))] + [System.Xml.Serialization.XmlElementAttribute("front_face", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFront_face))] + [System.Xml.Serialization.XmlElementAttribute("gl_hook_abstract", typeof(object))] + [System.Xml.Serialization.XmlElementAttribute("light_ambient", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_ambient))] + [System.Xml.Serialization.XmlElementAttribute("light_constant_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_constant_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_diffuse", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_diffuse))] + [System.Xml.Serialization.XmlElementAttribute("light_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_linear_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_linear_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_model_ambient", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_ambient))] + [System.Xml.Serialization.XmlElementAttribute("light_model_color_control", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_color_control))] + [System.Xml.Serialization.XmlElementAttribute("light_model_local_viewer_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_local_viewer_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_model_two_side_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_two_side_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_position", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_position))] + [System.Xml.Serialization.XmlElementAttribute("light_quadratic_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_quadratic_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_specular", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_specular))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_cutoff", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_cutoff))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_direction", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_direction))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_exponent", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_exponent))] + [System.Xml.Serialization.XmlElementAttribute("lighting_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLighting_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_smooth_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_stipple", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple))] + [System.Xml.Serialization.XmlElementAttribute("line_stipple_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_width", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_width))] + [System.Xml.Serialization.XmlElementAttribute("logic_op", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op))] + [System.Xml.Serialization.XmlElementAttribute("logic_op_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op_enable))] + [System.Xml.Serialization.XmlElementAttribute("material_ambient", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_ambient))] + [System.Xml.Serialization.XmlElementAttribute("material_diffuse", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_diffuse))] + [System.Xml.Serialization.XmlElementAttribute("material_emission", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_emission))] + [System.Xml.Serialization.XmlElementAttribute("material_shininess", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_shininess))] + [System.Xml.Serialization.XmlElementAttribute("material_specular", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_specular))] + [System.Xml.Serialization.XmlElementAttribute("model_view_matrix", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassModel_view_matrix))] + [System.Xml.Serialization.XmlElementAttribute("multisample_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMultisample_enable))] + [System.Xml.Serialization.XmlElementAttribute("normalize_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassNormalize_enable))] + [System.Xml.Serialization.XmlElementAttribute("point_distance_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_distance_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("point_fade_threshold_size", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_fade_threshold_size))] + [System.Xml.Serialization.XmlElementAttribute("point_size", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size))] + [System.Xml.Serialization.XmlElementAttribute("point_size_max", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_max))] + [System.Xml.Serialization.XmlElementAttribute("point_size_min", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_min))] + [System.Xml.Serialization.XmlElementAttribute("point_smooth_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_mode", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_mode))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset_fill_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_fill_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset_line_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_line_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset_point_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_point_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_smooth_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_stipple_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_stipple_enable))] + [System.Xml.Serialization.XmlElementAttribute("projection_matrix", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassProjection_matrix))] + [System.Xml.Serialization.XmlElementAttribute("rescale_normal_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassRescale_normal_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_alpha_to_coverage_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_coverage_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_alpha_to_one_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_one_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_coverage_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassSample_coverage_enable))] + [System.Xml.Serialization.XmlElementAttribute("scissor", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassScissor))] + [System.Xml.Serialization.XmlElementAttribute("scissor_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassScissor_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("shade_model", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassShade_model))] + [System.Xml.Serialization.XmlElementAttribute("shader", typeof(effectFx_profile_abstractProfile_CGTechniquePassShader))] + [System.Xml.Serialization.XmlElementAttribute("stencil_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func))] + [System.Xml.Serialization.XmlElementAttribute("stencil_func_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separate))] + [System.Xml.Serialization.XmlElementAttribute("stencil_mask", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask))] + [System.Xml.Serialization.XmlElementAttribute("stencil_mask_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separate))] + [System.Xml.Serialization.XmlElementAttribute("stencil_op", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op))] + [System.Xml.Serialization.XmlElementAttribute("stencil_op_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separate))] + [System.Xml.Serialization.XmlElementAttribute("stencil_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture1D", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture1D))] + [System.Xml.Serialization.XmlElementAttribute("texture1D_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture1D_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture2D", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture2D))] + [System.Xml.Serialization.XmlElementAttribute("texture2D_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture2D_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture3D", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture3D))] + [System.Xml.Serialization.XmlElementAttribute("texture3D_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture3D_enable))] + [System.Xml.Serialization.XmlElementAttribute("textureCUBE", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureCUBE))] + [System.Xml.Serialization.XmlElementAttribute("textureCUBE_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureCUBE_enable))] + [System.Xml.Serialization.XmlElementAttribute("textureDEPTH", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("textureDEPTH_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureDEPTH_enable))] + [System.Xml.Serialization.XmlElementAttribute("textureRECT", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureRECT))] + [System.Xml.Serialization.XmlElementAttribute("textureRECT_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureRECT_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture_env_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture_env_color))] + [System.Xml.Serialization.XmlElementAttribute("texture_env_mode", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture_env_mode))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_func + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcFunc funcField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcValue valueField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcFunc func + { + get + { + return this.funcField; + } + set + { + this.funcField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcValue value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcFunc + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcFunc() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_func_type + { + + /// + NEVER, + + /// + LESS, + + /// + LEQUAL, + + /// + EQUAL, + + /// + GREATER, + + /// + NOTEQUAL, + + /// + GEQUAL, + + /// + ALWAYS, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcValue + { + + private float valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_funcValue() + { + this.valueField = ((float)(0F)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassAuto_normal_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassAuto_normal_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_color + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_color() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation + { + + private gl_blend_equation_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation() + { + this.valueField = gl_blend_equation_type.FUNC_ADD; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_equation_type.FUNC_ADD)] + public gl_blend_equation_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_blend_equation_type + { + + /// + FUNC_ADD, + + /// + FUNC_SUBTRACT, + + /// + FUNC_REVERSE_SUBTRACT, + + /// + MIN, + + /// + MAX, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separate + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateRgb rgbField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateAlpha alphaField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateRgb rgb + { + get + { + return this.rgbField; + } + set + { + this.rgbField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateAlpha alpha + { + get + { + return this.alphaField; + } + set + { + this.alphaField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateRgb + { + + private gl_blend_equation_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateRgb() + { + this.valueField = gl_blend_equation_type.FUNC_ADD; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_equation_type.FUNC_ADD)] + public gl_blend_equation_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateAlpha + { + + private gl_blend_equation_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separateAlpha() + { + this.valueField = gl_blend_equation_type.FUNC_ADD; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_equation_type.FUNC_ADD)] + public gl_blend_equation_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcSrc srcField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcDest destField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcSrc src + { + get + { + return this.srcField; + } + set + { + this.srcField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcDest dest + { + get + { + return this.destField; + } + set + { + this.destField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcSrc + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcSrc() + { + this.valueField = gl_blend_type.ONE; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ONE)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_blend_type + { + + /// + ZERO, + + /// + ONE, + + /// + SRC_COLOR, + + /// + ONE_MINUS_SRC_COLOR, + + /// + DEST_COLOR, + + /// + ONE_MINUS_DEST_COLOR, + + /// + SRC_ALPHA, + + /// + ONE_MINUS_SRC_ALPHA, + + /// + DST_ALPHA, + + /// + ONE_MINUS_DST_ALPHA, + + /// + CONSTANT_COLOR, + + /// + ONE_MINUS_CONSTANT_COLOR, + + /// + CONSTANT_ALPHA, + + /// + ONE_MINUS_CONSTANT_ALPHA, + + /// + SRC_ALPHA_SATURATE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcDest + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_funcDest() + { + this.valueField = gl_blend_type.ZERO; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ZERO)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separate + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_rgb src_rgbField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_rgb dest_rgbField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_alpha src_alphaField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_alpha dest_alphaField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_rgb src_rgb + { + get + { + return this.src_rgbField; + } + set + { + this.src_rgbField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_rgb dest_rgb + { + get + { + return this.dest_rgbField; + } + set + { + this.dest_rgbField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_alpha src_alpha + { + get + { + return this.src_alphaField; + } + set + { + this.src_alphaField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_alpha dest_alpha + { + get + { + return this.dest_alphaField; + } + set + { + this.dest_alphaField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_rgb + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_rgb() + { + this.valueField = gl_blend_type.ONE; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ONE)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_rgb + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_rgb() + { + this.valueField = gl_blend_type.ZERO; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ZERO)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_alpha + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateSrc_alpha() + { + this.valueField = gl_blend_type.ONE; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ONE)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_alpha + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separateDest_alpha() + { + this.valueField = gl_blend_type.ZERO; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ZERO)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassClear_color + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassClear_color() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassClear_depth + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassClear_depth() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassClear_stencil + { + + private long valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassClear_stencil() + { + this.valueField = ((long)(0)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(long), "0")] + public long value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassColor_logic_op_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassColor_logic_op_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassColor_mask + { + + private bool[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassColor_mask() + { + this.valueField = new bool[] { + true, + true, + true, + true}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Boolean[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public bool[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassColor_material + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialFace faceField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialMode modeField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialFace face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialMode mode + { + get + { + return this.modeField; + } + set + { + this.modeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialFace + { + + private gl_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialFace() + { + this.valueField = gl_face_type.FRONT_AND_BACK; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_face_type.FRONT_AND_BACK)] + public gl_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_face_type + { + + /// + FRONT, + + /// + BACK, + + /// + FRONT_AND_BACK, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialMode + { + + private gl_material_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassColor_materialMode() + { + this.valueField = gl_material_type.AMBIENT_AND_DIFFUSE; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_material_type.AMBIENT_AND_DIFFUSE)] + public gl_material_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_material_type + { + + /// + EMISSION, + + /// + AMBIENT, + + /// + DIFFUSE, + + /// + SPECULAR, + + /// + AMBIENT_AND_DIFFUSE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassColor_material_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassColor_material_enable() + { + this.valueField = true; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(true)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassCull_face + { + + private gl_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassCull_face() + { + this.valueField = gl_face_type.BACK; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_face_type.BACK)] + public gl_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassCull_face_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassCull_face_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDepth_bounds + { + + private double[] valueField; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDepth_bounds_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassDepth_bounds_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDepth_clamp_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassDepth_clamp_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDepth_func + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassDepth_func() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDepth_mask + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassDepth_mask() + { + this.valueField = true; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(true)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDepth_range + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassDepth_range() + { + this.valueField = new double[] { + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDepth_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassDepth_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassDither_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassDither_enable() + { + this.valueField = true; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(true)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFog_color + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFog_color() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFog_coord_src + { + + private gl_fog_coord_src_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFog_coord_src() + { + this.valueField = gl_fog_coord_src_type.FOG_COORDINATE; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_fog_coord_src_type.FOG_COORDINATE)] + public gl_fog_coord_src_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_fog_coord_src_type + { + + /// + FOG_COORDINATE, + + /// + FRAGMENT_DEPTH, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFog_density + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFog_density() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFog_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFog_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFog_end + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFog_end() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFog_mode + { + + private gl_fog_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFog_mode() + { + this.valueField = gl_fog_type.EXP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_fog_type.EXP)] + public gl_fog_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_fog_type + { + + /// + LINEAR, + + /// + EXP, + + /// + EXP2, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFog_start + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFog_start() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassFront_face + { + + private gl_front_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassFront_face() + { + this.valueField = gl_front_face_type.CCW; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_front_face_type.CCW)] + public gl_front_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_front_face_type + { + + /// + CW, + + /// + CCW, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_ambient + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_ambient() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_constant_attenuation + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_constant_attenuation() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_diffuse + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_diffuse() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_linear_attenuation + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_linear_attenuation() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_ambient + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_ambient() + { + this.valueField = new double[] { + 0.2D, + 0.2D, + 0.2D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_color_control + { + + private gl_light_model_color_control_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_color_control() + { + this.valueField = gl_light_model_color_control_type.SINGLE_COLOR; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_light_model_color_control_type.SINGLE_COLOR)] + public gl_light_model_color_control_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_light_model_color_control_type + { + + /// + SINGLE_COLOR, + + /// + SEPARATE_SPECULAR_COLOR, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_local_viewer_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_local_viewer_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_two_side_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_two_side_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_position + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_position() + { + this.valueField = new double[] { + 0D, + 0D, + 1D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_quadratic_attenuation + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_quadratic_attenuation() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_specular + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_specular() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_cutoff + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_cutoff() + { + this.valueField = 180D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(180D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_direction + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_direction() + { + this.valueField = new double[] { + 0D, + 0D, + -1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_exponent + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_exponent() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLighting_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLighting_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLine_smooth_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLine_smooth_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple + { + + private long[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple() + { + this.valueField = new long[] { + ((long)(1)), + ((long)(65536))}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Int64[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public long[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLine_width + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLine_width() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op + { + + private gl_logic_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op() + { + this.valueField = gl_logic_op_type.COPY; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_logic_op_type.COPY)] + public gl_logic_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_logic_op_type + { + + /// + CLEAR, + + /// + AND, + + /// + AND_REVERSE, + + /// + COPY, + + /// + AND_INVERTED, + + /// + NOOP, + + /// + XOR, + + /// + OR, + + /// + NOR, + + /// + EQUIV, + + /// + INVERT, + + /// + OR_REVERSE, + + /// + COPY_INVERTED, + + /// + NAND, + + /// + SET, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_ambient + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_ambient() + { + this.valueField = new double[] { + 0.2D, + 0.2D, + 0.2D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_diffuse + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_diffuse() + { + this.valueField = new double[] { + 0.8D, + 0.8D, + 0.8D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_emission + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_emission() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_shininess + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_shininess() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_specular + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_specular() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassModel_view_matrix + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassModel_view_matrix() + { + this.valueField = new double[] { + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassMultisample_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassMultisample_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassNormalize_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassNormalize_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPoint_distance_attenuation + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPoint_distance_attenuation() + { + this.valueField = new double[] { + 1D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPoint_fade_threshold_size + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPoint_fade_threshold_size() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_max + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_max() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_min + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_min() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPoint_smooth_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPoint_smooth_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_mode + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeFace faceField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeMode modeField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeFace face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeMode mode + { + get + { + return this.modeField; + } + set + { + this.modeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeFace + { + + private gl_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeFace() + { + this.valueField = gl_face_type.FRONT_AND_BACK; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_face_type.FRONT_AND_BACK)] + public gl_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeMode + { + + private gl_polygon_mode_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_modeMode() + { + this.valueField = gl_polygon_mode_type.FILL; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_polygon_mode_type.FILL)] + public gl_polygon_mode_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_polygon_mode_type + { + + /// + POINT, + + /// + LINE, + + /// + FILL, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset() + { + this.valueField = new double[] { + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_fill_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_fill_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_line_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_line_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_point_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_point_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_smooth_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_smooth_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_stipple_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_stipple_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassProjection_matrix + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassProjection_matrix() + { + this.valueField = new double[] { + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassRescale_normal_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassRescale_normal_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_coverage_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_coverage_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_one_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_one_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassSample_coverage_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassSample_coverage_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassScissor + { + + private long[] valueField; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public long[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassScissor_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassScissor_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassShade_model + { + + private gl_shade_model_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassShade_model() + { + this.valueField = gl_shade_model_type.SMOOTH; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_shade_model_type.SMOOTH)] + public gl_shade_model_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_shade_model_type + { + + /// + FLAT, + + /// + SMOOTH, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_CGTechniquePassShader + { + + private fx_annotate_common[] annotateField; + + private effectFx_profile_abstractProfile_CGTechniquePassShaderCompiler_target compiler_targetField; + + private string compiler_optionsField; + + private effectFx_profile_abstractProfile_CGTechniquePassShaderName nameField; + + private effectFx_profile_abstractProfile_CGTechniquePassShaderBind[] bindField; + + private cg_pipeline_stage stageField; + + private bool stageFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + public effectFx_profile_abstractProfile_CGTechniquePassShaderCompiler_target compiler_target + { + get + { + return this.compiler_targetField; + } + set + { + this.compiler_targetField = value; + } + } + + /// + public string compiler_options + { + get + { + return this.compiler_optionsField; + } + set + { + this.compiler_optionsField = value; + } + } + + /// + public effectFx_profile_abstractProfile_CGTechniquePassShaderName name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("bind")] + public effectFx_profile_abstractProfile_CGTechniquePassShaderBind[] bind + { + get + { + return this.bindField; + } + set + { + this.bindField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public cg_pipeline_stage stage + { + get + { + return this.stageField; + } + set + { + this.stageField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool stageSpecified + { + get + { + return this.stageFieldSpecified; + } + set + { + this.stageFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_CGTechniquePassShaderCompiler_target + { + + private string valueField; + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NMTOKEN")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_CGTechniquePassShaderName + { + + private string sourceField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NCName")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_CGTechniquePassShaderBind + { + + private object itemField; + + private ItemChoiceType6 itemElementNameField; + + private string symbolField; + + /// + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool1x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x1", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4x4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("fixed", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("fixed4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half1x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half2x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half3x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x1", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("half4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int1x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x1", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4x4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("param", typeof(effectFx_profile_abstractProfile_CGTechniquePassShaderBindParam))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(cg_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(cg_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(cg_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(cg_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(cg_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(cg_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("string", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(cg_surface_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemChoiceType6 ItemElementName + { + get + { + return this.itemElementNameField; + } + set + { + this.itemElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string symbol + { + get + { + return this.symbolField; + } + set + { + this.symbolField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_CGTechniquePassShaderBindParam + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemChoiceType6 + { + + /// + @bool, + + /// + bool1, + + /// + bool1x1, + + /// + bool1x2, + + /// + bool1x3, + + /// + bool1x4, + + /// + bool2, + + /// + bool2x1, + + /// + bool2x2, + + /// + bool2x3, + + /// + bool2x4, + + /// + bool3, + + /// + bool3x1, + + /// + bool3x2, + + /// + bool3x3, + + /// + bool3x4, + + /// + bool4, + + /// + bool4x1, + + /// + bool4x2, + + /// + bool4x3, + + /// + bool4x4, + + /// + @enum, + + /// + @fixed, + + /// + fixed1, + + /// + fixed1x1, + + /// + fixed1x2, + + /// + fixed1x3, + + /// + fixed1x4, + + /// + fixed2, + + /// + fixed2x1, + + /// + fixed2x2, + + /// + fixed2x3, + + /// + fixed2x4, + + /// + fixed3, + + /// + fixed3x1, + + /// + fixed3x2, + + /// + fixed3x3, + + /// + fixed3x4, + + /// + fixed4, + + /// + fixed4x1, + + /// + fixed4x2, + + /// + fixed4x3, + + /// + fixed4x4, + + /// + @float, + + /// + float1, + + /// + float1x1, + + /// + float1x2, + + /// + float1x3, + + /// + float1x4, + + /// + float2, + + /// + float2x1, + + /// + float2x2, + + /// + float2x3, + + /// + float2x4, + + /// + float3, + + /// + float3x1, + + /// + float3x2, + + /// + float3x3, + + /// + float3x4, + + /// + float4, + + /// + float4x1, + + /// + float4x2, + + /// + float4x3, + + /// + float4x4, + + /// + half, + + /// + half1, + + /// + half1x1, + + /// + half1x2, + + /// + half1x3, + + /// + half1x4, + + /// + half2, + + /// + half2x1, + + /// + half2x2, + + /// + half2x3, + + /// + half2x4, + + /// + half3, + + /// + half3x1, + + /// + half3x2, + + /// + half3x3, + + /// + half3x4, + + /// + half4, + + /// + half4x1, + + /// + half4x2, + + /// + half4x3, + + /// + half4x4, + + /// + @int, + + /// + int1, + + /// + int1x1, + + /// + int1x2, + + /// + int1x3, + + /// + int1x4, + + /// + int2, + + /// + int2x1, + + /// + int2x2, + + /// + int2x3, + + /// + int2x4, + + /// + int3, + + /// + int3x1, + + /// + int3x2, + + /// + int3x3, + + /// + int3x4, + + /// + int4, + + /// + int4x1, + + /// + int4x2, + + /// + int4x3, + + /// + int4x4, + + /// + param, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + @string, + + /// + surface, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum cg_pipeline_stage + { + + /// + VERTEX, + + /// + FRAGMENT, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcFunc funcField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcRef refField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcMask maskField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcFunc func + { + get + { + return this.funcField; + } + set + { + this.funcField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcRef @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcMask mask + { + get + { + return this.maskField; + } + set + { + this.maskField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcFunc + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcFunc() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcRef + { + + private byte valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcRef() + { + this.valueField = ((byte)(0)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "0")] + public byte value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcMask + { + + private byte valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_funcMask() + { + this.valueField = ((byte)(255)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separate + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateFront frontField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateBack backField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateRef refField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateMask maskField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateFront front + { + get + { + return this.frontField; + } + set + { + this.frontField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateBack back + { + get + { + return this.backField; + } + set + { + this.backField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateRef @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateMask mask + { + get + { + return this.maskField; + } + set + { + this.maskField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateFront + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateFront() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateBack + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateBack() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateRef + { + + private byte valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateRef() + { + this.valueField = ((byte)(0)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "0")] + public byte value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateMask + { + + private byte valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separateMask() + { + this.valueField = ((byte)(255)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask + { + + private long valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask() + { + this.valueField = ((long)(4294967295)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(long), "4294967295")] + public long value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separate + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateFace faceField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateMask maskField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateFace face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateMask mask + { + get + { + return this.maskField; + } + set + { + this.maskField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateFace + { + + private gl_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateFace() + { + this.valueField = gl_face_type.FRONT_AND_BACK; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_face_type.FRONT_AND_BACK)] + public gl_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateMask + { + + private byte valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separateMask() + { + this.valueField = ((byte)(255)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opFail failField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZfail zfailField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZpass zpassField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opFail fail + { + get + { + return this.failField; + } + set + { + this.failField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZfail zfail + { + get + { + return this.zfailField; + } + set + { + this.zfailField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZpass zpass + { + get + { + return this.zpassField; + } + set + { + this.zpassField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opFail + { + + private gl_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opFail() + { + this.valueField = gl_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_stencil_op_type.KEEP)] + public gl_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gl_stencil_op_type + { + + /// + KEEP, + + /// + ZERO, + + /// + REPLACE, + + /// + INCR, + + /// + DECR, + + /// + INVERT, + + /// + INCR_WRAP, + + /// + DECR_WRAP, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZfail + { + + private gl_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZfail() + { + this.valueField = gl_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_stencil_op_type.KEEP)] + public gl_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZpass + { + + private gl_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_opZpass() + { + this.valueField = gl_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_stencil_op_type.KEEP)] + public gl_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separate + { + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFace faceField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFail failField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZfail zfailField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZpass zpassField; + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFace face + { + get + { + return this.faceField; + } + set + { + this.faceField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFail fail + { + get + { + return this.failField; + } + set + { + this.failField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZfail zfail + { + get + { + return this.zfailField; + } + set + { + this.zfailField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZpass zpass + { + get + { + return this.zpassField; + } + set + { + this.zpassField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFace + { + + private gl_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFace() + { + this.valueField = gl_face_type.FRONT_AND_BACK; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_face_type.FRONT_AND_BACK)] + public gl_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFail + { + + private gl_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateFail() + { + this.valueField = gl_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_stencil_op_type.KEEP)] + public gl_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZfail + { + + private gl_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZfail() + { + this.valueField = gl_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_stencil_op_type.KEEP)] + public gl_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZpass + { + + private gl_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separateZpass() + { + this.valueField = gl_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_stencil_op_type.KEEP)] + public gl_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassStencil_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassStencil_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture1D + { + + private object itemField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlElementAttribute("param", typeof(string), DataType = "NCName")] + [System.Xml.Serialization.XmlElementAttribute("value", typeof(gl_sampler1D))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture1D_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassTexture1D_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture2D + { + + private object itemField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlElementAttribute("param", typeof(string), DataType = "NCName")] + [System.Xml.Serialization.XmlElementAttribute("value", typeof(gl_sampler2D))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture2D_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassTexture2D_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture3D + { + + private object itemField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlElementAttribute("param", typeof(string), DataType = "NCName")] + [System.Xml.Serialization.XmlElementAttribute("value", typeof(gl_sampler3D))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture3D_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassTexture3D_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTextureCUBE + { + + private object itemField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlElementAttribute("param", typeof(string), DataType = "NCName")] + [System.Xml.Serialization.XmlElementAttribute("value", typeof(gl_samplerCUBE))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTextureCUBE_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassTextureCUBE_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTextureDEPTH + { + + private object itemField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlElementAttribute("param", typeof(string), DataType = "NCName")] + [System.Xml.Serialization.XmlElementAttribute("value", typeof(gl_samplerDEPTH))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTextureDEPTH_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassTextureDEPTH_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTextureRECT + { + + private object itemField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlElementAttribute("param", typeof(string), DataType = "NCName")] + [System.Xml.Serialization.XmlElementAttribute("value", typeof(gl_samplerRECT))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTextureRECT_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLSLTechniquePassTextureRECT_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture_env_color + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassTexture_env_mode + { + + private string valueField; + + private string paramField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute("profile_COMMON", Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class effectFx_profile_abstractProfile_COMMON + { + + private asset assetField; + + private object[] itemsField; + + private effectFx_profile_abstractProfile_COMMONTechnique techniqueField; + + private extra[] extraField; + + private string idField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(common_newparam_type))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + public effectFx_profile_abstractProfile_COMMONTechnique technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_COMMONTechnique + { + + private asset assetField; + + private object[] itemsField; + + private object itemField; + + private extra[] extraField; + + private string idField; + + private string sidField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(common_newparam_type))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("blinn", typeof(effectFx_profile_abstractProfile_COMMONTechniqueBlinn))] + [System.Xml.Serialization.XmlElementAttribute("constant", typeof(effectFx_profile_abstractProfile_COMMONTechniqueConstant))] + [System.Xml.Serialization.XmlElementAttribute("lambert", typeof(effectFx_profile_abstractProfile_COMMONTechniqueLambert))] + [System.Xml.Serialization.XmlElementAttribute("phong", typeof(effectFx_profile_abstractProfile_COMMONTechniquePhong))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_COMMONTechniqueBlinn + { + + private common_color_or_texture_type emissionField; + + private common_color_or_texture_type ambientField; + + private common_color_or_texture_type diffuseField; + + private common_color_or_texture_type specularField; + + private common_float_or_param_type shininessField; + + private common_color_or_texture_type reflectiveField; + + private common_float_or_param_type reflectivityField; + + private common_transparent_type transparentField; + + private common_float_or_param_type transparencyField; + + private common_float_or_param_type index_of_refractionField; + + /// + public common_color_or_texture_type emission + { + get + { + return this.emissionField; + } + set + { + this.emissionField = value; + } + } + + /// + public common_color_or_texture_type ambient + { + get + { + return this.ambientField; + } + set + { + this.ambientField = value; + } + } + + /// + public common_color_or_texture_type diffuse + { + get + { + return this.diffuseField; + } + set + { + this.diffuseField = value; + } + } + + /// + public common_color_or_texture_type specular + { + get + { + return this.specularField; + } + set + { + this.specularField = value; + } + } + + /// + public common_float_or_param_type shininess + { + get + { + return this.shininessField; + } + set + { + this.shininessField = value; + } + } + + /// + public common_color_or_texture_type reflective + { + get + { + return this.reflectiveField; + } + set + { + this.reflectiveField = value; + } + } + + /// + public common_float_or_param_type reflectivity + { + get + { + return this.reflectivityField; + } + set + { + this.reflectivityField = value; + } + } + + /// + public common_transparent_type transparent + { + get + { + return this.transparentField; + } + set + { + this.transparentField = value; + } + } + + /// + public common_float_or_param_type transparency + { + get + { + return this.transparencyField; + } + set + { + this.transparencyField = value; + } + } + + /// + public common_float_or_param_type index_of_refraction + { + get + { + return this.index_of_refractionField; + } + set + { + this.index_of_refractionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_COMMONTechniqueConstant + { + + private common_color_or_texture_type emissionField; + + private common_color_or_texture_type reflectiveField; + + private common_float_or_param_type reflectivityField; + + private common_transparent_type transparentField; + + private common_float_or_param_type transparencyField; + + private common_float_or_param_type index_of_refractionField; + + /// + public common_color_or_texture_type emission + { + get + { + return this.emissionField; + } + set + { + this.emissionField = value; + } + } + + /// + public common_color_or_texture_type reflective + { + get + { + return this.reflectiveField; + } + set + { + this.reflectiveField = value; + } + } + + /// + public common_float_or_param_type reflectivity + { + get + { + return this.reflectivityField; + } + set + { + this.reflectivityField = value; + } + } + + /// + public common_transparent_type transparent + { + get + { + return this.transparentField; + } + set + { + this.transparentField = value; + } + } + + /// + public common_float_or_param_type transparency + { + get + { + return this.transparencyField; + } + set + { + this.transparencyField = value; + } + } + + /// + public common_float_or_param_type index_of_refraction + { + get + { + return this.index_of_refractionField; + } + set + { + this.index_of_refractionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_COMMONTechniqueLambert + { + + private common_color_or_texture_type emissionField; + + private common_color_or_texture_type ambientField; + + private common_color_or_texture_type diffuseField; + + private common_color_or_texture_type reflectiveField; + + private common_float_or_param_type reflectivityField; + + private common_transparent_type transparentField; + + private common_float_or_param_type transparencyField; + + private common_float_or_param_type index_of_refractionField; + + /// + public common_color_or_texture_type emission + { + get + { + return this.emissionField; + } + set + { + this.emissionField = value; + } + } + + /// + public common_color_or_texture_type ambient + { + get + { + return this.ambientField; + } + set + { + this.ambientField = value; + } + } + + /// + public common_color_or_texture_type diffuse + { + get + { + return this.diffuseField; + } + set + { + this.diffuseField = value; + } + } + + /// + public common_color_or_texture_type reflective + { + get + { + return this.reflectiveField; + } + set + { + this.reflectiveField = value; + } + } + + /// + public common_float_or_param_type reflectivity + { + get + { + return this.reflectivityField; + } + set + { + this.reflectivityField = value; + } + } + + /// + public common_transparent_type transparent + { + get + { + return this.transparentField; + } + set + { + this.transparentField = value; + } + } + + /// + public common_float_or_param_type transparency + { + get + { + return this.transparencyField; + } + set + { + this.transparencyField = value; + } + } + + /// + public common_float_or_param_type index_of_refraction + { + get + { + return this.index_of_refractionField; + } + set + { + this.index_of_refractionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_COMMONTechniquePhong + { + + private common_color_or_texture_type emissionField; + + private common_color_or_texture_type ambientField; + + private common_color_or_texture_type diffuseField; + + private common_color_or_texture_type specularField; + + private common_float_or_param_type shininessField; + + private common_color_or_texture_type reflectiveField; + + private common_float_or_param_type reflectivityField; + + private common_transparent_type transparentField; + + private common_float_or_param_type transparencyField; + + private common_float_or_param_type index_of_refractionField; + + /// + public common_color_or_texture_type emission + { + get + { + return this.emissionField; + } + set + { + this.emissionField = value; + } + } + + /// + public common_color_or_texture_type ambient + { + get + { + return this.ambientField; + } + set + { + this.ambientField = value; + } + } + + /// + public common_color_or_texture_type diffuse + { + get + { + return this.diffuseField; + } + set + { + this.diffuseField = value; + } + } + + /// + public common_color_or_texture_type specular + { + get + { + return this.specularField; + } + set + { + this.specularField = value; + } + } + + /// + public common_float_or_param_type shininess + { + get + { + return this.shininessField; + } + set + { + this.shininessField = value; + } + } + + /// + public common_color_or_texture_type reflective + { + get + { + return this.reflectiveField; + } + set + { + this.reflectiveField = value; + } + } + + /// + public common_float_or_param_type reflectivity + { + get + { + return this.reflectivityField; + } + set + { + this.reflectivityField = value; + } + } + + /// + public common_transparent_type transparent + { + get + { + return this.transparentField; + } + set + { + this.transparentField = value; + } + } + + /// + public common_float_or_param_type transparency + { + get + { + return this.transparencyField; + } + set + { + this.transparencyField = value; + } + } + + /// + public common_float_or_param_type index_of_refraction + { + get + { + return this.index_of_refractionField; + } + set + { + this.index_of_refractionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute("profile_GLES", Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class effectFx_profile_abstractProfile_GLES + { + + private asset assetField; + + private object[] itemsField; + + private effectFx_profile_abstractProfile_GLESTechnique[] techniqueField; + + private extra[] extraField; + + private string idField; + + private string platformField; + + public effectFx_profile_abstractProfile_GLES() + { + this.platformField = "PC"; + } + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(gles_newparam))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public effectFx_profile_abstractProfile_GLESTechnique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + [System.ComponentModel.DefaultValueAttribute("PC")] + public string platform + { + get + { + return this.platformField; + } + set + { + this.platformField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechnique + { + + private asset assetField; + + private fx_annotate_common[] annotateField; + + private object[] itemsField; + + private effectFx_profile_abstractProfile_GLESTechniquePass[] passField; + + private extra[] extraField; + + private string idField; + + private string sidField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(gles_newparam))] + [System.Xml.Serialization.XmlElementAttribute("setparam", typeof(effectFx_profile_abstractProfile_GLESTechniqueSetparam))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("pass")] + public effectFx_profile_abstractProfile_GLESTechniquePass[] pass + { + get + { + return this.passField; + } + set + { + this.passField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniqueSetparam + { + + private fx_annotate_common[] annotateField; + + private bool boolField; + + private string bool2Field; + + private string bool3Field; + + private string bool4Field; + + private long intField; + + private string int2Field; + + private string int3Field; + + private string int4Field; + + private double floatField; + + private string float2Field; + + private string float3Field; + + private string float4Field; + + private double float1x1Field; + + private string float1x2Field; + + private string float1x3Field; + + private string float1x4Field; + + private string float2x1Field; + + private string float2x2Field; + + private string float2x3Field; + + private string float2x4Field; + + private string float3x1Field; + + private string float3x2Field; + + private string float3x3Field; + + private string float3x4Field; + + private string float4x1Field; + + private string float4x2Field; + + private string float4x3Field; + + private string float4x4Field; + + private fx_surface_common surfaceField; + + private gles_texture_pipeline texture_pipelineField; + + private gles_sampler_state sampler_stateField; + + private gles_texture_unit texture_unitField; + + private string enumField; + + private string refField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + public bool @bool + { + get + { + return this.boolField; + } + set + { + this.boolField = value; + } + } + + /// + public string bool2 + { + get + { + return this.bool2Field; + } + set + { + this.bool2Field = value; + } + } + + /// + public string bool3 + { + get + { + return this.bool3Field; + } + set + { + this.bool3Field = value; + } + } + + /// + public string bool4 + { + get + { + return this.bool4Field; + } + set + { + this.bool4Field = value; + } + } + + /// + public long @int + { + get + { + return this.intField; + } + set + { + this.intField = value; + } + } + + /// + public string int2 + { + get + { + return this.int2Field; + } + set + { + this.int2Field = value; + } + } + + /// + public string int3 + { + get + { + return this.int3Field; + } + set + { + this.int3Field = value; + } + } + + /// + public string int4 + { + get + { + return this.int4Field; + } + set + { + this.int4Field = value; + } + } + + /// + public double @float + { + get + { + return this.floatField; + } + set + { + this.floatField = value; + } + } + + /// + public string float2 + { + get + { + return this.float2Field; + } + set + { + this.float2Field = value; + } + } + + /// + public string float3 + { + get + { + return this.float3Field; + } + set + { + this.float3Field = value; + } + } + + /// + public string float4 + { + get + { + return this.float4Field; + } + set + { + this.float4Field = value; + } + } + + /// + public double float1x1 + { + get + { + return this.float1x1Field; + } + set + { + this.float1x1Field = value; + } + } + + /// + public string float1x2 + { + get + { + return this.float1x2Field; + } + set + { + this.float1x2Field = value; + } + } + + /// + public string float1x3 + { + get + { + return this.float1x3Field; + } + set + { + this.float1x3Field = value; + } + } + + /// + public string float1x4 + { + get + { + return this.float1x4Field; + } + set + { + this.float1x4Field = value; + } + } + + /// + public string float2x1 + { + get + { + return this.float2x1Field; + } + set + { + this.float2x1Field = value; + } + } + + /// + public string float2x2 + { + get + { + return this.float2x2Field; + } + set + { + this.float2x2Field = value; + } + } + + /// + public string float2x3 + { + get + { + return this.float2x3Field; + } + set + { + this.float2x3Field = value; + } + } + + /// + public string float2x4 + { + get + { + return this.float2x4Field; + } + set + { + this.float2x4Field = value; + } + } + + /// + public string float3x1 + { + get + { + return this.float3x1Field; + } + set + { + this.float3x1Field = value; + } + } + + /// + public string float3x2 + { + get + { + return this.float3x2Field; + } + set + { + this.float3x2Field = value; + } + } + + /// + public string float3x3 + { + get + { + return this.float3x3Field; + } + set + { + this.float3x3Field = value; + } + } + + /// + public string float3x4 + { + get + { + return this.float3x4Field; + } + set + { + this.float3x4Field = value; + } + } + + /// + public string float4x1 + { + get + { + return this.float4x1Field; + } + set + { + this.float4x1Field = value; + } + } + + /// + public string float4x2 + { + get + { + return this.float4x2Field; + } + set + { + this.float4x2Field = value; + } + } + + /// + public string float4x3 + { + get + { + return this.float4x3Field; + } + set + { + this.float4x3Field = value; + } + } + + /// + public string float4x4 + { + get + { + return this.float4x4Field; + } + set + { + this.float4x4Field = value; + } + } + + /// + public fx_surface_common surface + { + get + { + return this.surfaceField; + } + set + { + this.surfaceField = value; + } + } + + /// + public gles_texture_pipeline texture_pipeline + { + get + { + return this.texture_pipelineField; + } + set + { + this.texture_pipelineField = value; + } + } + + /// + public gles_sampler_state sampler_state + { + get + { + return this.sampler_stateField; + } + set + { + this.sampler_stateField = value; + } + } + + /// + public gles_texture_unit texture_unit + { + get + { + return this.texture_unitField; + } + set + { + this.texture_unitField = value; + } + } + + /// + public string @enum + { + get + { + return this.enumField; + } + set + { + this.enumField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePass + { + + private fx_annotate_common[] annotateField; + + private string color_targetField; + + private string depth_targetField; + + private string stencil_targetField; + + private string color_clearField; + + private double depth_clearField; + + private bool depth_clearFieldSpecified; + + private sbyte stencil_clearField; + + private bool stencil_clearFieldSpecified; + + private string drawField; + + private object[] itemsField; + + private extra[] extraField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string color_target + { + get + { + return this.color_targetField; + } + set + { + this.color_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string depth_target + { + get + { + return this.depth_targetField; + } + set + { + this.depth_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType = "NCName")] + public string stencil_target + { + get + { + return this.stencil_targetField; + } + set + { + this.stencil_targetField = value; + } + } + + /// + public string color_clear + { + get + { + return this.color_clearField; + } + set + { + this.color_clearField = value; + } + } + + /// + public double depth_clear + { + get + { + return this.depth_clearField; + } + set + { + this.depth_clearField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool depth_clearSpecified + { + get + { + return this.depth_clearFieldSpecified; + } + set + { + this.depth_clearFieldSpecified = value; + } + } + + /// + public sbyte stencil_clear + { + get + { + return this.stencil_clearField; + } + set + { + this.stencil_clearField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool stencil_clearSpecified + { + get + { + return this.stencil_clearFieldSpecified; + } + set + { + this.stencil_clearFieldSpecified = value; + } + } + + /// + public string draw + { + get + { + return this.drawField; + } + set + { + this.drawField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("alpha_func", typeof(effectFx_profile_abstractProfile_GLESTechniquePassAlpha_func))] + [System.Xml.Serialization.XmlElementAttribute("alpha_test_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassAlpha_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("blend_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassBlend_enable))] + [System.Xml.Serialization.XmlElementAttribute("blend_func", typeof(effectFx_profile_abstractProfile_GLESTechniquePassBlend_func))] + [System.Xml.Serialization.XmlElementAttribute("clear_color", typeof(effectFx_profile_abstractProfile_GLESTechniquePassClear_color))] + [System.Xml.Serialization.XmlElementAttribute("clear_depth", typeof(effectFx_profile_abstractProfile_GLESTechniquePassClear_depth))] + [System.Xml.Serialization.XmlElementAttribute("clear_stencil", typeof(effectFx_profile_abstractProfile_GLESTechniquePassClear_stencil))] + [System.Xml.Serialization.XmlElementAttribute("clip_plane", typeof(effectFx_profile_abstractProfile_GLESTechniquePassClip_plane))] + [System.Xml.Serialization.XmlElementAttribute("clip_plane_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassClip_plane_enable))] + [System.Xml.Serialization.XmlElementAttribute("color_logic_op_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassColor_logic_op_enable))] + [System.Xml.Serialization.XmlElementAttribute("color_mask", typeof(effectFx_profile_abstractProfile_GLESTechniquePassColor_mask))] + [System.Xml.Serialization.XmlElementAttribute("color_material_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassColor_material_enable))] + [System.Xml.Serialization.XmlElementAttribute("cull_face", typeof(effectFx_profile_abstractProfile_GLESTechniquePassCull_face))] + [System.Xml.Serialization.XmlElementAttribute("cull_face_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassCull_face_enable))] + [System.Xml.Serialization.XmlElementAttribute("depth_func", typeof(effectFx_profile_abstractProfile_GLESTechniquePassDepth_func))] + [System.Xml.Serialization.XmlElementAttribute("depth_mask", typeof(effectFx_profile_abstractProfile_GLESTechniquePassDepth_mask))] + [System.Xml.Serialization.XmlElementAttribute("depth_range", typeof(effectFx_profile_abstractProfile_GLESTechniquePassDepth_range))] + [System.Xml.Serialization.XmlElementAttribute("depth_test_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassDepth_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("dither_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassDither_enable))] + [System.Xml.Serialization.XmlElementAttribute("fog_color", typeof(effectFx_profile_abstractProfile_GLESTechniquePassFog_color))] + [System.Xml.Serialization.XmlElementAttribute("fog_density", typeof(effectFx_profile_abstractProfile_GLESTechniquePassFog_density))] + [System.Xml.Serialization.XmlElementAttribute("fog_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassFog_enable))] + [System.Xml.Serialization.XmlElementAttribute("fog_end", typeof(effectFx_profile_abstractProfile_GLESTechniquePassFog_end))] + [System.Xml.Serialization.XmlElementAttribute("fog_mode", typeof(effectFx_profile_abstractProfile_GLESTechniquePassFog_mode))] + [System.Xml.Serialization.XmlElementAttribute("fog_start", typeof(effectFx_profile_abstractProfile_GLESTechniquePassFog_start))] + [System.Xml.Serialization.XmlElementAttribute("front_face", typeof(effectFx_profile_abstractProfile_GLESTechniquePassFront_face))] + [System.Xml.Serialization.XmlElementAttribute("light_ambient", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_ambient))] + [System.Xml.Serialization.XmlElementAttribute("light_constant_attenuation", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_constant_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_diffuse", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_diffuse))] + [System.Xml.Serialization.XmlElementAttribute("light_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_linear_attenutation", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_linear_attenutation))] + [System.Xml.Serialization.XmlElementAttribute("light_model_ambient", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_model_ambient))] + [System.Xml.Serialization.XmlElementAttribute("light_model_two_side_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_model_two_side_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_position", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_position))] + [System.Xml.Serialization.XmlElementAttribute("light_quadratic_attenuation", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_quadratic_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_specular", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_specular))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_cutoff", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_cutoff))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_direction", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_direction))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_exponent", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_exponent))] + [System.Xml.Serialization.XmlElementAttribute("lighting_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLighting_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_smooth_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLine_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_width", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLine_width))] + [System.Xml.Serialization.XmlElementAttribute("logic_op", typeof(effectFx_profile_abstractProfile_GLESTechniquePassLogic_op))] + [System.Xml.Serialization.XmlElementAttribute("material_ambient", typeof(effectFx_profile_abstractProfile_GLESTechniquePassMaterial_ambient))] + [System.Xml.Serialization.XmlElementAttribute("material_diffuse", typeof(effectFx_profile_abstractProfile_GLESTechniquePassMaterial_diffuse))] + [System.Xml.Serialization.XmlElementAttribute("material_emission", typeof(effectFx_profile_abstractProfile_GLESTechniquePassMaterial_emission))] + [System.Xml.Serialization.XmlElementAttribute("material_shininess", typeof(effectFx_profile_abstractProfile_GLESTechniquePassMaterial_shininess))] + [System.Xml.Serialization.XmlElementAttribute("material_specular", typeof(effectFx_profile_abstractProfile_GLESTechniquePassMaterial_specular))] + [System.Xml.Serialization.XmlElementAttribute("model_view_matrix", typeof(effectFx_profile_abstractProfile_GLESTechniquePassModel_view_matrix))] + [System.Xml.Serialization.XmlElementAttribute("multisample_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassMultisample_enable))] + [System.Xml.Serialization.XmlElementAttribute("normalize_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassNormalize_enable))] + [System.Xml.Serialization.XmlElementAttribute("point_distance_attenuation", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPoint_distance_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("point_fade_threshold_size", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPoint_fade_threshold_size))] + [System.Xml.Serialization.XmlElementAttribute("point_size", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPoint_size))] + [System.Xml.Serialization.XmlElementAttribute("point_size_max", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPoint_size_max))] + [System.Xml.Serialization.XmlElementAttribute("point_size_min", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPoint_size_min))] + [System.Xml.Serialization.XmlElementAttribute("point_smooth_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPoint_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPolygon_offset))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset_fill_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassPolygon_offset_fill_enable))] + [System.Xml.Serialization.XmlElementAttribute("projection_matrix", typeof(effectFx_profile_abstractProfile_GLESTechniquePassProjection_matrix))] + [System.Xml.Serialization.XmlElementAttribute("rescale_normal_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassRescale_normal_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_alpha_to_coverage_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassSample_alpha_to_coverage_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_alpha_to_one_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassSample_alpha_to_one_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_coverage_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassSample_coverage_enable))] + [System.Xml.Serialization.XmlElementAttribute("scissor", typeof(effectFx_profile_abstractProfile_GLESTechniquePassScissor))] + [System.Xml.Serialization.XmlElementAttribute("scissor_test_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassScissor_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("shade_model", typeof(effectFx_profile_abstractProfile_GLESTechniquePassShade_model))] + [System.Xml.Serialization.XmlElementAttribute("stencil_func", typeof(effectFx_profile_abstractProfile_GLESTechniquePassStencil_func))] + [System.Xml.Serialization.XmlElementAttribute("stencil_mask", typeof(effectFx_profile_abstractProfile_GLESTechniquePassStencil_mask))] + [System.Xml.Serialization.XmlElementAttribute("stencil_op", typeof(effectFx_profile_abstractProfile_GLESTechniquePassStencil_op))] + [System.Xml.Serialization.XmlElementAttribute("stencil_test_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassStencil_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture_pipeline", typeof(effectFx_profile_abstractProfile_GLESTechniquePassTexture_pipeline))] + [System.Xml.Serialization.XmlElementAttribute("texture_pipeline_enable", typeof(effectFx_profile_abstractProfile_GLESTechniquePassTexture_pipeline_enable))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassAlpha_func + { + + private effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcFunc funcField; + + private effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcValue valueField; + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcFunc func + { + get + { + return this.funcField; + } + set + { + this.funcField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcValue value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcFunc + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcFunc() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcValue + { + + private float valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassAlpha_funcValue() + { + this.valueField = ((float)(0F)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(float), "0")] + public float value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassAlpha_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassAlpha_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassBlend_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassBlend_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassBlend_func + { + + private effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcSrc srcField; + + private effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcDest destField; + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcSrc src + { + get + { + return this.srcField; + } + set + { + this.srcField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcDest dest + { + get + { + return this.destField; + } + set + { + this.destField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcSrc + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcSrc() + { + this.valueField = gl_blend_type.ONE; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ONE)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcDest + { + + private gl_blend_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassBlend_funcDest() + { + this.valueField = gl_blend_type.ZERO; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_blend_type.ZERO)] + public gl_blend_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassClear_color + { + + private double[] valueField; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassClear_depth + { + + private double valueField; + + private bool valueFieldSpecified; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool valueSpecified + { + get + { + return this.valueFieldSpecified; + } + set + { + this.valueFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassClear_stencil + { + + private long valueField; + + private bool valueFieldSpecified; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public long value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool valueSpecified + { + get + { + return this.valueFieldSpecified; + } + set + { + this.valueFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassClip_plane + { + + private bool[] valueField; + + private string paramField; + + private string indexField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public bool[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassClip_plane_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassClip_plane_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassColor_logic_op_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassColor_logic_op_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassColor_mask + { + + private bool[] valueField; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public bool[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassColor_material_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassColor_material_enable() + { + this.valueField = true; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(true)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassCull_face + { + + private gl_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassCull_face() + { + this.valueField = gl_face_type.BACK; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_face_type.BACK)] + public gl_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassCull_face_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassCull_face_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassDepth_func + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassDepth_func() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassDepth_mask + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassDepth_mask() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassDepth_range + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassDepth_range() + { + this.valueField = new double[] { + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassDepth_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassDepth_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassDither_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassDither_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassFog_color + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassFog_color() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassFog_density + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassFog_density() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassFog_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassFog_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassFog_end + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassFog_end() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassFog_mode + { + + private gl_fog_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassFog_mode() + { + this.valueField = gl_fog_type.EXP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_fog_type.EXP)] + public gl_fog_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassFog_start + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassFog_start() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassFront_face + { + + private gl_front_face_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassFront_face() + { + this.valueField = gl_front_face_type.CCW; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_front_face_type.CCW)] + public gl_front_face_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_ambient + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_ambient() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_constant_attenuation + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_constant_attenuation() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_diffuse + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_diffuse() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_enable + { + + private bool valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_linear_attenutation + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_linear_attenutation() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_model_ambient + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_model_ambient() + { + this.valueField = new double[] { + 0.2D, + 0.2D, + 0.2D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_model_two_side_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_model_two_side_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_position + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_position() + { + this.valueField = new double[] { + 0D, + 0D, + 1D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_quadratic_attenuation + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_quadratic_attenuation() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_specular + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_specular() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_cutoff + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_cutoff() + { + this.valueField = 180D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(180D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_direction + { + + private double[] valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_direction() + { + this.valueField = new double[] { + 0D, + 0D, + -1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_exponent + { + + private double valueField; + + private string paramField; + + private string indexField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLight_spot_exponent() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "nonNegativeInteger")] + public string index + { + get + { + return this.indexField; + } + set + { + this.indexField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLighting_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLighting_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLine_smooth_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLine_smooth_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLine_width + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLine_width() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassLogic_op + { + + private gl_logic_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassLogic_op() + { + this.valueField = gl_logic_op_type.COPY; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_logic_op_type.COPY)] + public gl_logic_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassMaterial_ambient + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassMaterial_ambient() + { + this.valueField = new double[] { + 0.2D, + 0.2D, + 0.2D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassMaterial_diffuse + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassMaterial_diffuse() + { + this.valueField = new double[] { + 0.8D, + 0.8D, + 0.8D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassMaterial_emission + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassMaterial_emission() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassMaterial_shininess + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassMaterial_shininess() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassMaterial_specular + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassMaterial_specular() + { + this.valueField = new double[] { + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassModel_view_matrix + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassModel_view_matrix() + { + this.valueField = new double[] { + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassMultisample_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassMultisample_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassNormalize_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassNormalize_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPoint_distance_attenuation + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPoint_distance_attenuation() + { + this.valueField = new double[] { + 1D, + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPoint_fade_threshold_size + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPoint_fade_threshold_size() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPoint_size + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPoint_size() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPoint_size_max + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPoint_size_max() + { + this.valueField = 1D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(1D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPoint_size_min + { + + private double valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPoint_size_min() + { + this.valueField = 0D; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(0D)] + public double value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPoint_smooth_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPoint_smooth_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPolygon_offset + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPolygon_offset() + { + this.valueField = new double[] { + 0D, + 0D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassPolygon_offset_fill_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassPolygon_offset_fill_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassProjection_matrix + { + + private double[] valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassProjection_matrix() + { + this.valueField = new double[] { + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D, + 0D, + 0D, + 0D, + 0D, + 1D}; + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type System.Double[] is not supported in this version of the .Net Framework. + [System.Xml.Serialization.XmlAttributeAttribute()] + public double[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassRescale_normal_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassRescale_normal_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassSample_alpha_to_coverage_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassSample_alpha_to_coverage_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassSample_alpha_to_one_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassSample_alpha_to_one_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassSample_coverage_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassSample_coverage_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassScissor + { + + private long[] valueField; + + private string paramField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public long[] value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassScissor_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassScissor_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassShade_model + { + + private gl_shade_model_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassShade_model() + { + this.valueField = gl_shade_model_type.SMOOTH; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_shade_model_type.SMOOTH)] + public gl_shade_model_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_func + { + + private effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcFunc funcField; + + private effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcRef refField; + + private effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcMask maskField; + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcFunc func + { + get + { + return this.funcField; + } + set + { + this.funcField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcRef @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcMask mask + { + get + { + return this.maskField; + } + set + { + this.maskField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcFunc + { + + private gl_func_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcFunc() + { + this.valueField = gl_func_type.ALWAYS; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gl_func_type.ALWAYS)] + public gl_func_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcRef + { + + private byte valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcRef() + { + this.valueField = ((byte)(0)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "0")] + public byte value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcMask + { + + private byte valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_funcMask() + { + this.valueField = ((byte)(255)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(byte), "255")] + public byte value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_mask + { + + private long valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_mask() + { + this.valueField = ((long)(4294967295)); + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(typeof(long), "4294967295")] + public long value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_op + { + + private effectFx_profile_abstractProfile_GLESTechniquePassStencil_opFail failField; + + private effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZfail zfailField; + + private effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZpass zpassField; + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_opFail fail + { + get + { + return this.failField; + } + set + { + this.failField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZfail zfail + { + get + { + return this.zfailField; + } + set + { + this.zfailField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZpass zpass + { + get + { + return this.zpassField; + } + set + { + this.zpassField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_opFail + { + + private gles_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_opFail() + { + this.valueField = gles_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gles_stencil_op_type.KEEP)] + public gles_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum gles_stencil_op_type + { + + /// + KEEP, + + /// + ZERO, + + /// + REPLACE, + + /// + INCR, + + /// + DECR, + + /// + INVERT, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZfail + { + + private gles_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZfail() + { + this.valueField = gles_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gles_stencil_op_type.KEEP)] + public gles_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZpass + { + + private gles_stencil_op_type valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_opZpass() + { + this.valueField = gles_stencil_op_type.KEEP; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(gles_stencil_op_type.KEEP)] + public gles_stencil_op_type value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassStencil_test_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassStencil_test_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassTexture_pipeline + { + + private gles_texture_pipeline valueField; + + private string paramField; + + /// + public gles_texture_pipeline value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLESTechniquePassTexture_pipeline_enable + { + + private bool valueField; + + private string paramField; + + public effectFx_profile_abstractProfile_GLESTechniquePassTexture_pipeline_enable() + { + this.valueField = false; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute("profile_GLSL", Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class effectFx_profile_abstractProfile_GLSL + { + + private asset assetField; + + private object[] itemsField; + + private object[] items1Field; + + private effectFx_profile_abstractProfile_GLSLTechnique[] techniqueField; + + private extra[] extraField; + + private string idField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("code", typeof(fx_code_profile))] + [System.Xml.Serialization.XmlElementAttribute("include", typeof(fx_include_common))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(glsl_newparam))] + public object[] Items1 + { + get + { + return this.items1Field; + } + set + { + this.items1Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public effectFx_profile_abstractProfile_GLSLTechnique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechnique + { + + private fx_annotate_common[] annotateField; + + private object[] itemsField; + + private object[] items1Field; + + private effectFx_profile_abstractProfile_GLSLTechniquePass[] passField; + + private extra[] extraField; + + private string idField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("code", typeof(fx_code_profile))] + [System.Xml.Serialization.XmlElementAttribute("include", typeof(fx_include_common))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image", typeof(image))] + [System.Xml.Serialization.XmlElementAttribute("newparam", typeof(glsl_newparam))] + [System.Xml.Serialization.XmlElementAttribute("setparam", typeof(glsl_setparam))] + public object[] Items1 + { + get + { + return this.items1Field; + } + set + { + this.items1Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("pass")] + public effectFx_profile_abstractProfile_GLSLTechniquePass[] pass + { + get + { + return this.passField; + } + set + { + this.passField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePass + { + + private fx_annotate_common[] annotateField; + + private fx_colortarget_common[] color_targetField; + + private fx_depthtarget_common[] depth_targetField; + + private fx_stenciltarget_common[] stencil_targetField; + + private fx_clearcolor_common[] color_clearField; + + private fx_cleardepth_common[] depth_clearField; + + private fx_clearstencil_common[] stencil_clearField; + + private string drawField; + + private object[] itemsField; + + private extra[] extraField; + + private string sidField; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("color_target")] + public fx_colortarget_common[] color_target + { + get + { + return this.color_targetField; + } + set + { + this.color_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("depth_target")] + public fx_depthtarget_common[] depth_target + { + get + { + return this.depth_targetField; + } + set + { + this.depth_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("stencil_target")] + public fx_stenciltarget_common[] stencil_target + { + get + { + return this.stencil_targetField; + } + set + { + this.stencil_targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("color_clear")] + public fx_clearcolor_common[] color_clear + { + get + { + return this.color_clearField; + } + set + { + this.color_clearField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("depth_clear")] + public fx_cleardepth_common[] depth_clear + { + get + { + return this.depth_clearField; + } + set + { + this.depth_clearField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("stencil_clear")] + public fx_clearstencil_common[] stencil_clear + { + get + { + return this.stencil_clearField; + } + set + { + this.stencil_clearField = value; + } + } + + /// + public string draw + { + get + { + return this.drawField; + } + set + { + this.drawField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("alpha_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_func))] + [System.Xml.Serialization.XmlElementAttribute("alpha_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassAlpha_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("auto_normal_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassAuto_normal_enable))] + [System.Xml.Serialization.XmlElementAttribute("blend_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_color))] + [System.Xml.Serialization.XmlElementAttribute("blend_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_enable))] + [System.Xml.Serialization.XmlElementAttribute("blend_equation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation))] + [System.Xml.Serialization.XmlElementAttribute("blend_equation_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_equation_separate))] + [System.Xml.Serialization.XmlElementAttribute("blend_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func))] + [System.Xml.Serialization.XmlElementAttribute("blend_func_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassBlend_func_separate))] + [System.Xml.Serialization.XmlElementAttribute("clear_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClear_color))] + [System.Xml.Serialization.XmlElementAttribute("clear_depth", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClear_depth))] + [System.Xml.Serialization.XmlElementAttribute("clear_stencil", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClear_stencil))] + [System.Xml.Serialization.XmlElementAttribute("clip_plane", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane))] + [System.Xml.Serialization.XmlElementAttribute("clip_plane_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassClip_plane_enable))] + [System.Xml.Serialization.XmlElementAttribute("color_logic_op_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_logic_op_enable))] + [System.Xml.Serialization.XmlElementAttribute("color_mask", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_mask))] + [System.Xml.Serialization.XmlElementAttribute("color_material", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_material))] + [System.Xml.Serialization.XmlElementAttribute("color_material_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassColor_material_enable))] + [System.Xml.Serialization.XmlElementAttribute("cull_face", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassCull_face))] + [System.Xml.Serialization.XmlElementAttribute("cull_face_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassCull_face_enable))] + [System.Xml.Serialization.XmlElementAttribute("depth_bounds", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_bounds))] + [System.Xml.Serialization.XmlElementAttribute("depth_bounds_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_bounds_enable))] + [System.Xml.Serialization.XmlElementAttribute("depth_clamp_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_clamp_enable))] + [System.Xml.Serialization.XmlElementAttribute("depth_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_func))] + [System.Xml.Serialization.XmlElementAttribute("depth_mask", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_mask))] + [System.Xml.Serialization.XmlElementAttribute("depth_range", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_range))] + [System.Xml.Serialization.XmlElementAttribute("depth_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDepth_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("dither_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassDither_enable))] + [System.Xml.Serialization.XmlElementAttribute("fog_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_color))] + [System.Xml.Serialization.XmlElementAttribute("fog_coord_src", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_coord_src))] + [System.Xml.Serialization.XmlElementAttribute("fog_density", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_density))] + [System.Xml.Serialization.XmlElementAttribute("fog_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_enable))] + [System.Xml.Serialization.XmlElementAttribute("fog_end", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_end))] + [System.Xml.Serialization.XmlElementAttribute("fog_mode", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_mode))] + [System.Xml.Serialization.XmlElementAttribute("fog_start", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFog_start))] + [System.Xml.Serialization.XmlElementAttribute("front_face", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassFront_face))] + [System.Xml.Serialization.XmlElementAttribute("gl_hook_abstract", typeof(object))] + [System.Xml.Serialization.XmlElementAttribute("light_ambient", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_ambient))] + [System.Xml.Serialization.XmlElementAttribute("light_constant_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_constant_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_diffuse", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_diffuse))] + [System.Xml.Serialization.XmlElementAttribute("light_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_linear_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_linear_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_model_ambient", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_ambient))] + [System.Xml.Serialization.XmlElementAttribute("light_model_color_control", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_color_control))] + [System.Xml.Serialization.XmlElementAttribute("light_model_local_viewer_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_local_viewer_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_model_two_side_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_model_two_side_enable))] + [System.Xml.Serialization.XmlElementAttribute("light_position", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_position))] + [System.Xml.Serialization.XmlElementAttribute("light_quadratic_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_quadratic_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("light_specular", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_specular))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_cutoff", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_cutoff))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_direction", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_direction))] + [System.Xml.Serialization.XmlElementAttribute("light_spot_exponent", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLight_spot_exponent))] + [System.Xml.Serialization.XmlElementAttribute("lighting_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLighting_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_smooth_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_stipple", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple))] + [System.Xml.Serialization.XmlElementAttribute("line_stipple_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_stipple_enable))] + [System.Xml.Serialization.XmlElementAttribute("line_width", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLine_width))] + [System.Xml.Serialization.XmlElementAttribute("logic_op", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op))] + [System.Xml.Serialization.XmlElementAttribute("logic_op_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassLogic_op_enable))] + [System.Xml.Serialization.XmlElementAttribute("material_ambient", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_ambient))] + [System.Xml.Serialization.XmlElementAttribute("material_diffuse", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_diffuse))] + [System.Xml.Serialization.XmlElementAttribute("material_emission", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_emission))] + [System.Xml.Serialization.XmlElementAttribute("material_shininess", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_shininess))] + [System.Xml.Serialization.XmlElementAttribute("material_specular", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMaterial_specular))] + [System.Xml.Serialization.XmlElementAttribute("model_view_matrix", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassModel_view_matrix))] + [System.Xml.Serialization.XmlElementAttribute("multisample_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassMultisample_enable))] + [System.Xml.Serialization.XmlElementAttribute("normalize_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassNormalize_enable))] + [System.Xml.Serialization.XmlElementAttribute("point_distance_attenuation", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_distance_attenuation))] + [System.Xml.Serialization.XmlElementAttribute("point_fade_threshold_size", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_fade_threshold_size))] + [System.Xml.Serialization.XmlElementAttribute("point_size", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size))] + [System.Xml.Serialization.XmlElementAttribute("point_size_max", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_max))] + [System.Xml.Serialization.XmlElementAttribute("point_size_min", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_size_min))] + [System.Xml.Serialization.XmlElementAttribute("point_smooth_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPoint_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_mode", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_mode))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset_fill_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_fill_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset_line_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_line_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_offset_point_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_offset_point_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_smooth_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_smooth_enable))] + [System.Xml.Serialization.XmlElementAttribute("polygon_stipple_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassPolygon_stipple_enable))] + [System.Xml.Serialization.XmlElementAttribute("projection_matrix", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassProjection_matrix))] + [System.Xml.Serialization.XmlElementAttribute("rescale_normal_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassRescale_normal_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_alpha_to_coverage_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_coverage_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_alpha_to_one_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassSample_alpha_to_one_enable))] + [System.Xml.Serialization.XmlElementAttribute("sample_coverage_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassSample_coverage_enable))] + [System.Xml.Serialization.XmlElementAttribute("scissor", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassScissor))] + [System.Xml.Serialization.XmlElementAttribute("scissor_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassScissor_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("shade_model", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassShade_model))] + [System.Xml.Serialization.XmlElementAttribute("shader", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassShader))] + [System.Xml.Serialization.XmlElementAttribute("stencil_func", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func))] + [System.Xml.Serialization.XmlElementAttribute("stencil_func_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_func_separate))] + [System.Xml.Serialization.XmlElementAttribute("stencil_mask", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask))] + [System.Xml.Serialization.XmlElementAttribute("stencil_mask_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_mask_separate))] + [System.Xml.Serialization.XmlElementAttribute("stencil_op", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op))] + [System.Xml.Serialization.XmlElementAttribute("stencil_op_separate", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_op_separate))] + [System.Xml.Serialization.XmlElementAttribute("stencil_test_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassStencil_test_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture1D", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture1D))] + [System.Xml.Serialization.XmlElementAttribute("texture1D_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture1D_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture2D", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture2D))] + [System.Xml.Serialization.XmlElementAttribute("texture2D_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture2D_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture3D", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture3D))] + [System.Xml.Serialization.XmlElementAttribute("texture3D_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture3D_enable))] + [System.Xml.Serialization.XmlElementAttribute("textureCUBE", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureCUBE))] + [System.Xml.Serialization.XmlElementAttribute("textureCUBE_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureCUBE_enable))] + [System.Xml.Serialization.XmlElementAttribute("textureDEPTH", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("textureDEPTH_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureDEPTH_enable))] + [System.Xml.Serialization.XmlElementAttribute("textureRECT", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureRECT))] + [System.Xml.Serialization.XmlElementAttribute("textureRECT_enable", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTextureRECT_enable))] + [System.Xml.Serialization.XmlElementAttribute("texture_env_color", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture_env_color))] + [System.Xml.Serialization.XmlElementAttribute("texture_env_mode", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassTexture_env_mode))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassShader + { + + private fx_annotate_common[] annotateField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassShaderCompiler_target compiler_targetField; + + private string compiler_optionsField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassShaderName nameField; + + private effectFx_profile_abstractProfile_GLSLTechniquePassShaderBind[] bindField; + + private glsl_pipeline_stage stageField; + + private bool stageFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute("annotate")] + public fx_annotate_common[] annotate + { + get + { + return this.annotateField; + } + set + { + this.annotateField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassShaderCompiler_target compiler_target + { + get + { + return this.compiler_targetField; + } + set + { + this.compiler_targetField = value; + } + } + + /// + public string compiler_options + { + get + { + return this.compiler_optionsField; + } + set + { + this.compiler_optionsField = value; + } + } + + /// + public effectFx_profile_abstractProfile_GLSLTechniquePassShaderName name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("bind")] + public effectFx_profile_abstractProfile_GLSLTechniquePassShaderBind[] bind + { + get + { + return this.bindField; + } + set + { + this.bindField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public glsl_pipeline_stage stage + { + get + { + return this.stageField; + } + set + { + this.stageField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool stageSpecified + { + get + { + return this.stageFieldSpecified; + } + set + { + this.stageFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassShaderCompiler_target + { + + private string valueField; + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NMTOKEN")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassShaderName + { + + private string sourceField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType = "NCName")] + public string Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassShaderBind + { + + private object itemField; + + private ItemChoiceType5 itemElementNameField; + + private string symbolField; + + /// + [System.Xml.Serialization.XmlElementAttribute("bool", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool2", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool3", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("bool4", typeof(bool))] + [System.Xml.Serialization.XmlElementAttribute("enum", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("float", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float2x2", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float3x3", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("float4x4", typeof(float))] + [System.Xml.Serialization.XmlElementAttribute("int", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int2", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int3", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("int4", typeof(int))] + [System.Xml.Serialization.XmlElementAttribute("param", typeof(effectFx_profile_abstractProfile_GLSLTechniquePassShaderBindParam))] + [System.Xml.Serialization.XmlElementAttribute("sampler1D", typeof(gl_sampler1D))] + [System.Xml.Serialization.XmlElementAttribute("sampler2D", typeof(gl_sampler2D))] + [System.Xml.Serialization.XmlElementAttribute("sampler3D", typeof(gl_sampler3D))] + [System.Xml.Serialization.XmlElementAttribute("samplerCUBE", typeof(gl_samplerCUBE))] + [System.Xml.Serialization.XmlElementAttribute("samplerDEPTH", typeof(gl_samplerDEPTH))] + [System.Xml.Serialization.XmlElementAttribute("samplerRECT", typeof(gl_samplerRECT))] + [System.Xml.Serialization.XmlElementAttribute("surface", typeof(glsl_surface_type))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemChoiceType5 ItemElementName + { + get + { + return this.itemElementNameField; + } + set + { + this.itemElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string symbol + { + get + { + return this.symbolField; + } + set + { + this.symbolField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class effectFx_profile_abstractProfile_GLSLTechniquePassShaderBindParam + { + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemChoiceType5 + { + + /// + @bool, + + /// + bool2, + + /// + bool3, + + /// + bool4, + + /// + @enum, + + /// + @float, + + /// + float2, + + /// + float2x2, + + /// + float3, + + /// + float3x3, + + /// + float4, + + /// + float4x4, + + /// + @int, + + /// + int2, + + /// + int3, + + /// + int4, + + /// + param, + + /// + sampler1D, + + /// + sampler2D, + + /// + sampler3D, + + /// + samplerCUBE, + + /// + samplerDEPTH, + + /// + samplerRECT, + + /// + surface, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum glsl_pipeline_stage + { + + /// + VERTEXPROGRAM, + + /// + FRAGMENTPROGRAM, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_force_fields + { + + private asset assetField; + + private force_field[] force_fieldField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("force_field")] + public force_field[] force_field + { + get + { + return this.force_fieldField; + } + set + { + this.force_fieldField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class force_field + { + + private asset assetField; + + private technique[] techniqueField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_geometries + { + + private asset assetField; + + private geometry[] geometryField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("geometry")] + public geometry[] geometry + { + get + { + return this.geometryField; + } + set + { + this.geometryField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class geometry + { + + private asset assetField; + + private object itemField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("convex_mesh", typeof(convex_mesh))] + [System.Xml.Serialization.XmlElementAttribute("mesh", typeof(mesh))] + [System.Xml.Serialization.XmlElementAttribute("spline", typeof(spline))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class convex_mesh + { + + private source[] sourceField; + + private vertices verticesField; + + private object[] itemsField; + + private extra[] extraField; + + private string convex_hull_ofField; + + /// + [System.Xml.Serialization.XmlElementAttribute("source")] + public source[] source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + public vertices vertices + { + get + { + return this.verticesField; + } + set + { + this.verticesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("lines", typeof(lines))] + [System.Xml.Serialization.XmlElementAttribute("linestrips", typeof(linestrips))] + [System.Xml.Serialization.XmlElementAttribute("polygons", typeof(polygons))] + [System.Xml.Serialization.XmlElementAttribute("polylist", typeof(polylist))] + [System.Xml.Serialization.XmlElementAttribute("triangles", typeof(triangles))] + [System.Xml.Serialization.XmlElementAttribute("trifans", typeof(trifans))] + [System.Xml.Serialization.XmlElementAttribute("tristrips", typeof(tristrips))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string convex_hull_of + { + get + { + return this.convex_hull_ofField; + } + set + { + this.convex_hull_ofField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class vertices + { + + private InputLocal[] inputField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocal[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class lines + { + + private InputLocalOffset[] inputField; + + private string pField; + + private extra[] extraField; + + private string nameField; + + private ulong countField; + + private string materialField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + public string p + { + get + { + return this.pField; + } + set + { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class linestrips + { + + private InputLocalOffset[] inputField; + + private string[] pField; + + private extra[] extraField; + + private string nameField; + + private ulong countField; + + private string materialField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("p")] + public string[] p + { + get + { + return this.pField; + } + set + { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class polygons + { + + private InputLocalOffset[] inputField; + + private object[] itemsField; + + private extra[] extraField; + + private string nameField; + + private ulong countField; + + private string materialField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("p", typeof(string))] + [System.Xml.Serialization.XmlElementAttribute("ph", typeof(polygonsPH))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class polygonsPH + { + + private string pField; + + private string[] hField; + + /// + public string p + { + get + { + return this.pField; + } + set + { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("h")] + public string[] h + { + get + { + return this.hField; + } + set + { + this.hField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class polylist + { + + private InputLocalOffset[] inputField; + + private string vcountField; + + private string pField; + + private extra[] extraField; + + private string nameField; + + private ulong countField; + + private string materialField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + public string vcount + { + get + { + return this.vcountField; + } + set + { + this.vcountField = value; + } + } + + /// + public string p + { + get + { + return this.pField; + } + set + { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class triangles + { + + private InputLocalOffset[] inputField; + + private string pField; + + private extra[] extraField; + + private string nameField; + + private ulong countField; + + private string materialField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + public string p + { + get + { + return this.pField; + } + set + { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class trifans + { + + private InputLocalOffset[] inputField; + + private string[] pField; + + private extra[] extraField; + + private string nameField; + + private ulong countField; + + private string materialField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("p")] + public string[] p + { + get + { + return this.pField; + } + set + { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class tristrips + { + + private InputLocalOffset[] inputField; + + private string[] pField; + + private extra[] extraField; + + private string nameField; + + private ulong countField; + + private string materialField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocalOffset[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("p")] + public string[] p + { + get + { + return this.pField; + } + set + { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong count + { + get + { + return this.countField; + } + set + { + this.countField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class mesh + { + + private source[] sourceField; + + private vertices verticesField; + + private object[] itemsField; + + private extra[] extraField; + + /// + [System.Xml.Serialization.XmlElementAttribute("source")] + public source[] source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + public vertices vertices + { + get + { + return this.verticesField; + } + set + { + this.verticesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("lines", typeof(lines))] + [System.Xml.Serialization.XmlElementAttribute("linestrips", typeof(linestrips))] + [System.Xml.Serialization.XmlElementAttribute("polygons", typeof(polygons))] + [System.Xml.Serialization.XmlElementAttribute("polylist", typeof(polylist))] + [System.Xml.Serialization.XmlElementAttribute("triangles", typeof(triangles))] + [System.Xml.Serialization.XmlElementAttribute("trifans", typeof(trifans))] + [System.Xml.Serialization.XmlElementAttribute("tristrips", typeof(tristrips))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class spline + { + + private source[] sourceField; + + private splineControl_vertices control_verticesField; + + private extra[] extraField; + + private bool closedField; + + public spline() + { + this.closedField = false; + } + + /// + [System.Xml.Serialization.XmlElementAttribute("source")] + public source[] source + { + get + { + return this.sourceField; + } + set + { + this.sourceField = value; + } + } + + /// + public splineControl_vertices control_vertices + { + get + { + return this.control_verticesField; + } + set + { + this.control_verticesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(false)] + public bool closed + { + get + { + return this.closedField; + } + set + { + this.closedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class splineControl_vertices + { + + private InputLocal[] inputField; + + private extra[] extraField; + + /// + [System.Xml.Serialization.XmlElementAttribute("input")] + public InputLocal[] input + { + get + { + return this.inputField; + } + set + { + this.inputField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_images + { + + private asset assetField; + + private image[] imageField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("image")] + public image[] image + { + get + { + return this.imageField; + } + set + { + this.imageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_lights + { + + private asset assetField; + + private light[] lightField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("light")] + public light[] light + { + get + { + return this.lightField; + } + set + { + this.lightField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class light + { + + private asset assetField; + + private lightTechnique_common technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + public lightTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class lightTechnique_common + { + + private object itemField; + + /// + [System.Xml.Serialization.XmlElementAttribute("ambient", typeof(lightTechnique_commonAmbient))] + [System.Xml.Serialization.XmlElementAttribute("directional", typeof(lightTechnique_commonDirectional))] + [System.Xml.Serialization.XmlElementAttribute("point", typeof(lightTechnique_commonPoint))] + [System.Xml.Serialization.XmlElementAttribute("spot", typeof(lightTechnique_commonSpot))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class lightTechnique_commonAmbient + { + + private TargetableFloat3 colorField; + + /// + public TargetableFloat3 color + { + get + { + return this.colorField; + } + set + { + this.colorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute("scale", Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class TargetableFloat3 + { + + private string sidField; + + private double[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class lightTechnique_commonDirectional + { + + private TargetableFloat3 colorField; + + /// + public TargetableFloat3 color + { + get + { + return this.colorField; + } + set + { + this.colorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class lightTechnique_commonPoint + { + + private TargetableFloat3 colorField; + + private TargetableFloat constant_attenuationField; + + private TargetableFloat linear_attenuationField; + + private TargetableFloat quadratic_attenuationField; + + /// + public TargetableFloat3 color + { + get + { + return this.colorField; + } + set + { + this.colorField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='1.0' attribute. + public TargetableFloat constant_attenuation + { + get + { + return this.constant_attenuationField; + } + set + { + this.constant_attenuationField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat linear_attenuation + { + get + { + return this.linear_attenuationField; + } + set + { + this.linear_attenuationField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat quadratic_attenuation + { + get + { + return this.quadratic_attenuationField; + } + set + { + this.quadratic_attenuationField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class lightTechnique_commonSpot + { + + private TargetableFloat3 colorField; + + private TargetableFloat constant_attenuationField; + + private TargetableFloat linear_attenuationField; + + private TargetableFloat quadratic_attenuationField; + + private TargetableFloat falloff_angleField; + + private TargetableFloat falloff_exponentField; + + /// + public TargetableFloat3 color + { + get + { + return this.colorField; + } + set + { + this.colorField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='1.0' attribute. + public TargetableFloat constant_attenuation + { + get + { + return this.constant_attenuationField; + } + set + { + this.constant_attenuationField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat linear_attenuation + { + get + { + return this.linear_attenuationField; + } + set + { + this.linear_attenuationField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat quadratic_attenuation + { + get + { + return this.quadratic_attenuationField; + } + set + { + this.quadratic_attenuationField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='180.0' attribute. + public TargetableFloat falloff_angle + { + get + { + return this.falloff_angleField; + } + set + { + this.falloff_angleField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat falloff_exponent + { + get + { + return this.falloff_exponentField; + } + set + { + this.falloff_exponentField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_materials + { + + private asset assetField; + + private material[] materialField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("material")] + public material[] material + { + get + { + return this.materialField; + } + set + { + this.materialField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class material + { + + private asset assetField; + + private instance_effect instance_effectField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + public instance_effect instance_effect + { + get + { + return this.instance_effectField; + } + set + { + this.instance_effectField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class instance_effect + { + + private instance_effectTechnique_hint[] technique_hintField; + + private instance_effectSetparam[] setparamField; + + private extra[] extraField; + + private string urlField; + + private string sidField; + + private string nameField; + + /// + [System.Xml.Serialization.XmlElementAttribute("technique_hint")] + public instance_effectTechnique_hint[] technique_hint + { + get + { + return this.technique_hintField; + } + set + { + this.technique_hintField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("setparam")] + public instance_effectSetparam[] setparam + { + get + { + return this.setparamField; + } + set + { + this.setparamField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string url + { + get + { + return this.urlField; + } + set + { + this.urlField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_effectTechnique_hint + { + + private string platformField; + + private string profileField; + + private string refField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string platform + { + get + { + return this.platformField; + } + set + { + this.platformField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string profile + { + get + { + return this.profileField; + } + set + { + this.profileField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_effectSetparam + { + + private bool boolField; + + private string bool2Field; + + private string bool3Field; + + private string bool4Field; + + private long intField; + + private string int2Field; + + private string int3Field; + + private string int4Field; + + private double floatField; + + private string float2Field; + + private string float3Field; + + private string float4Field; + + private double float1x1Field; + + private string float1x2Field; + + private string float1x3Field; + + private string float1x4Field; + + private string float2x1Field; + + private string float2x2Field; + + private string float2x3Field; + + private string float2x4Field; + + private string float3x1Field; + + private string float3x2Field; + + private string float3x3Field; + + private string float3x4Field; + + private string float4x1Field; + + private string float4x2Field; + + private string float4x3Field; + + private string float4x4Field; + + private fx_surface_common surfaceField; + + private fx_sampler1D_common sampler1DField; + + private fx_sampler2D_common sampler2DField; + + private fx_sampler3D_common sampler3DField; + + private fx_samplerCUBE_common samplerCUBEField; + + private fx_samplerRECT_common samplerRECTField; + + private fx_samplerDEPTH_common samplerDEPTHField; + + private string enumField; + + private string refField; + + /// + public bool @bool + { + get + { + return this.boolField; + } + set + { + this.boolField = value; + } + } + + /// + public string bool2 + { + get + { + return this.bool2Field; + } + set + { + this.bool2Field = value; + } + } + + /// + public string bool3 + { + get + { + return this.bool3Field; + } + set + { + this.bool3Field = value; + } + } + + /// + public string bool4 + { + get + { + return this.bool4Field; + } + set + { + this.bool4Field = value; + } + } + + /// + public long @int + { + get + { + return this.intField; + } + set + { + this.intField = value; + } + } + + /// + public string int2 + { + get + { + return this.int2Field; + } + set + { + this.int2Field = value; + } + } + + /// + public string int3 + { + get + { + return this.int3Field; + } + set + { + this.int3Field = value; + } + } + + /// + public string int4 + { + get + { + return this.int4Field; + } + set + { + this.int4Field = value; + } + } + + /// + public double @float + { + get + { + return this.floatField; + } + set + { + this.floatField = value; + } + } + + /// + public string float2 + { + get + { + return this.float2Field; + } + set + { + this.float2Field = value; + } + } + + /// + public string float3 + { + get + { + return this.float3Field; + } + set + { + this.float3Field = value; + } + } + + /// + public string float4 + { + get + { + return this.float4Field; + } + set + { + this.float4Field = value; + } + } + + /// + public double float1x1 + { + get + { + return this.float1x1Field; + } + set + { + this.float1x1Field = value; + } + } + + /// + public string float1x2 + { + get + { + return this.float1x2Field; + } + set + { + this.float1x2Field = value; + } + } + + /// + public string float1x3 + { + get + { + return this.float1x3Field; + } + set + { + this.float1x3Field = value; + } + } + + /// + public string float1x4 + { + get + { + return this.float1x4Field; + } + set + { + this.float1x4Field = value; + } + } + + /// + public string float2x1 + { + get + { + return this.float2x1Field; + } + set + { + this.float2x1Field = value; + } + } + + /// + public string float2x2 + { + get + { + return this.float2x2Field; + } + set + { + this.float2x2Field = value; + } + } + + /// + public string float2x3 + { + get + { + return this.float2x3Field; + } + set + { + this.float2x3Field = value; + } + } + + /// + public string float2x4 + { + get + { + return this.float2x4Field; + } + set + { + this.float2x4Field = value; + } + } + + /// + public string float3x1 + { + get + { + return this.float3x1Field; + } + set + { + this.float3x1Field = value; + } + } + + /// + public string float3x2 + { + get + { + return this.float3x2Field; + } + set + { + this.float3x2Field = value; + } + } + + /// + public string float3x3 + { + get + { + return this.float3x3Field; + } + set + { + this.float3x3Field = value; + } + } + + /// + public string float3x4 + { + get + { + return this.float3x4Field; + } + set + { + this.float3x4Field = value; + } + } + + /// + public string float4x1 + { + get + { + return this.float4x1Field; + } + set + { + this.float4x1Field = value; + } + } + + /// + public string float4x2 + { + get + { + return this.float4x2Field; + } + set + { + this.float4x2Field = value; + } + } + + /// + public string float4x3 + { + get + { + return this.float4x3Field; + } + set + { + this.float4x3Field = value; + } + } + + /// + public string float4x4 + { + get + { + return this.float4x4Field; + } + set + { + this.float4x4Field = value; + } + } + + /// + public fx_surface_common surface + { + get + { + return this.surfaceField; + } + set + { + this.surfaceField = value; + } + } + + /// + public fx_sampler1D_common sampler1D + { + get + { + return this.sampler1DField; + } + set + { + this.sampler1DField = value; + } + } + + /// + public fx_sampler2D_common sampler2D + { + get + { + return this.sampler2DField; + } + set + { + this.sampler2DField = value; + } + } + + /// + public fx_sampler3D_common sampler3D + { + get + { + return this.sampler3DField; + } + set + { + this.sampler3DField = value; + } + } + + /// + public fx_samplerCUBE_common samplerCUBE + { + get + { + return this.samplerCUBEField; + } + set + { + this.samplerCUBEField = value; + } + } + + /// + public fx_samplerRECT_common samplerRECT + { + get + { + return this.samplerRECTField; + } + set + { + this.samplerRECTField = value; + } + } + + /// + public fx_samplerDEPTH_common samplerDEPTH + { + get + { + return this.samplerDEPTHField; + } + set + { + this.samplerDEPTHField = value; + } + } + + /// + public string @enum + { + get + { + return this.enumField; + } + set + { + this.enumField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")] + public string @ref + { + get + { + return this.refField; + } + set + { + this.refField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_nodes + { + + private asset assetField; + + private node[] nodeField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("node")] + public node[] node + { + get + { + return this.nodeField; + } + set + { + this.nodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class node + { + + private asset assetField; + + private object[] itemsField; + + private ItemsChoiceType7[] itemsElementNameField; + + private InstanceWithExtra[] instance_cameraField; + + private instance_controller[] instance_controllerField; + + private instance_geometry[] instance_geometryField; + + private InstanceWithExtra[] instance_lightField; + + private InstanceWithExtra[] instance_nodeField; + + private node[] node1Field; + + private extra[] extraField; + + private string idField; + + private string nameField; + + private string sidField; + + private NodeType typeField; + + private string[] layerField; + + public node() + { + this.typeField = NodeType.NODE; + } + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("lookat", typeof(lookat))] + [System.Xml.Serialization.XmlElementAttribute("matrix", typeof(matrix))] + [System.Xml.Serialization.XmlElementAttribute("rotate", typeof(rotate))] + [System.Xml.Serialization.XmlElementAttribute("scale", typeof(TargetableFloat3))] + [System.Xml.Serialization.XmlElementAttribute("skew", typeof(skew))] + [System.Xml.Serialization.XmlElementAttribute("translate", typeof(TargetableFloat3))] + [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] + [System.Xml.Serialization.XmlIgnoreAttribute()] + public ItemsChoiceType7[] ItemsElementName + { + get + { + return this.itemsElementNameField; + } + set + { + this.itemsElementNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_camera")] + public InstanceWithExtra[] instance_camera + { + get + { + return this.instance_cameraField; + } + set + { + this.instance_cameraField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_controller")] + public instance_controller[] instance_controller + { + get + { + return this.instance_controllerField; + } + set + { + this.instance_controllerField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_geometry")] + public instance_geometry[] instance_geometry + { + get + { + return this.instance_geometryField; + } + set + { + this.instance_geometryField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_light")] + public InstanceWithExtra[] instance_light + { + get + { + return this.instance_lightField; + } + set + { + this.instance_lightField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_node")] + public InstanceWithExtra[] instance_node + { + get + { + return this.instance_nodeField; + } + set + { + this.instance_nodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("node")] + public node[] node1 + { + get + { + return this.node1Field; + } + set + { + this.node1Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute(NodeType.NODE)] + public NodeType type + { + get + { + return this.typeField; + } + set + { + this.typeField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "Name")] + public string[] layer + { + get + { + return this.layerField; + } + set + { + this.layerField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class lookat + { + + private string sidField; + + private double[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class matrix + { + + private string sidField; + + private double[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class rotate + { + + private string sidField; + + private double[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class skew + { + + private string sidField; + + private double[] textField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + [XmlText] + public string _Text_ + { + get { return COLLADA.ConvertFromArray(textField); } + set { textField = COLLADA.ConvertDoubleArray(value); } + } + /// + [XmlIgnore] + public double[] Values + { + get + { + return this.textField; + } + set + { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IncludeInSchema = false)] + public enum ItemsChoiceType7 + { + + /// + lookat, + + /// + matrix, + + /// + rotate, + + /// + scale, + + /// + skew, + + /// + translate, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class instance_controller + { + + private string[] skeletonField; + + private bind_material bind_materialField; + + private extra[] extraField; + + private string urlField; + + private string sidField; + + private string nameField; + + /// + [System.Xml.Serialization.XmlElementAttribute("skeleton", DataType = "anyURI")] + public string[] skeleton + { + get + { + return this.skeletonField; + } + set + { + this.skeletonField = value; + } + } + + /// + public bind_material bind_material + { + get + { + return this.bind_materialField; + } + set + { + this.bind_materialField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string url + { + get + { + return this.urlField; + } + set + { + this.urlField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class bind_material + { + + private param[] paramField; + + private instance_material[] technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + /// + [System.Xml.Serialization.XmlElementAttribute("param")] + public param[] param + { + get + { + return this.paramField; + } + set + { + this.paramField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("instance_material", IsNullable = false)] + public instance_material[] technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class instance_geometry + { + + private bind_material bind_materialField; + + private extra[] extraField; + + private string urlField; + + private string sidField; + + private string nameField; + + /// + public bind_material bind_material + { + get + { + return this.bind_materialField; + } + set + { + this.bind_materialField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string url + { + get + { + return this.urlField; + } + set + { + this.urlField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum NodeType + { + + /// + JOINT, + + /// + NODE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_physics_materials + { + + private asset assetField; + + private physics_material[] physics_materialField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("physics_material")] + public physics_material[] physics_material + { + get + { + return this.physics_materialField; + } + set + { + this.physics_materialField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class physics_material + { + + private asset assetField; + + private physics_materialTechnique_common technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + public physics_materialTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class physics_materialTechnique_common + { + + private TargetableFloat dynamic_frictionField; + + private TargetableFloat restitutionField; + + private TargetableFloat static_frictionField; + + /// + public TargetableFloat dynamic_friction + { + get + { + return this.dynamic_frictionField; + } + set + { + this.dynamic_frictionField = value; + } + } + + /// + public TargetableFloat restitution + { + get + { + return this.restitutionField; + } + set + { + this.restitutionField = value; + } + } + + /// + public TargetableFloat static_friction + { + get + { + return this.static_frictionField; + } + set + { + this.static_frictionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_physics_models + { + + private asset assetField; + + private physics_model[] physics_modelField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("physics_model")] + public physics_model[] physics_model + { + get + { + return this.physics_modelField; + } + set + { + this.physics_modelField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class physics_model + { + + private asset assetField; + + private rigid_body[] rigid_bodyField; + + private rigid_constraint[] rigid_constraintField; + + private instance_physics_model[] instance_physics_modelField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("rigid_body")] + public rigid_body[] rigid_body + { + get + { + return this.rigid_bodyField; + } + set + { + this.rigid_bodyField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("rigid_constraint")] + public rigid_constraint[] rigid_constraint + { + get + { + return this.rigid_constraintField; + } + set + { + this.rigid_constraintField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_physics_model")] + public instance_physics_model[] instance_physics_model + { + get + { + return this.instance_physics_modelField; + } + set + { + this.instance_physics_modelField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class rigid_body + { + + private rigid_bodyTechnique_common technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + private string sidField; + + private string nameField; + + /// + public rigid_bodyTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_bodyTechnique_common + { + + private rigid_bodyTechnique_commonDynamic dynamicField; + + private TargetableFloat massField; + + private object[] mass_frameField; + + private TargetableFloat3 inertiaField; + + private object itemField; + + private rigid_bodyTechnique_commonShape[] shapeField; + + /// + public rigid_bodyTechnique_commonDynamic dynamic + { + get + { + return this.dynamicField; + } + set + { + this.dynamicField = value; + } + } + + /// + public TargetableFloat mass + { + get + { + return this.massField; + } + set + { + this.massField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("rotate", typeof(rotate), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("translate", typeof(TargetableFloat3), IsNullable = false)] + public object[] mass_frame + { + get + { + return this.mass_frameField; + } + set + { + this.mass_frameField = value; + } + } + + /// + public TargetableFloat3 inertia + { + get + { + return this.inertiaField; + } + set + { + this.inertiaField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_physics_material", typeof(InstanceWithExtra))] + [System.Xml.Serialization.XmlElementAttribute("physics_material", typeof(physics_material))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("shape")] + public rigid_bodyTechnique_commonShape[] shape + { + get + { + return this.shapeField; + } + set + { + this.shapeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_bodyTechnique_commonDynamic + { + + private string sidField; + + private bool valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public bool Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_bodyTechnique_commonShape + { + + private rigid_bodyTechnique_commonShapeHollow hollowField; + + private TargetableFloat massField; + + private TargetableFloat densityField; + + private object itemField; + + private object item1Field; + + private object[] itemsField; + + private extra[] extraField; + + /// + public rigid_bodyTechnique_commonShapeHollow hollow + { + get + { + return this.hollowField; + } + set + { + this.hollowField = value; + } + } + + /// + public TargetableFloat mass + { + get + { + return this.massField; + } + set + { + this.massField = value; + } + } + + /// + public TargetableFloat density + { + get + { + return this.densityField; + } + set + { + this.densityField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_physics_material", typeof(InstanceWithExtra))] + [System.Xml.Serialization.XmlElementAttribute("physics_material", typeof(physics_material))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("box", typeof(box))] + [System.Xml.Serialization.XmlElementAttribute("capsule", typeof(capsule))] + [System.Xml.Serialization.XmlElementAttribute("cylinder", typeof(cylinder))] + [System.Xml.Serialization.XmlElementAttribute("instance_geometry", typeof(instance_geometry))] + [System.Xml.Serialization.XmlElementAttribute("plane", typeof(plane))] + [System.Xml.Serialization.XmlElementAttribute("sphere", typeof(sphere))] + [System.Xml.Serialization.XmlElementAttribute("tapered_capsule", typeof(tapered_capsule))] + [System.Xml.Serialization.XmlElementAttribute("tapered_cylinder", typeof(tapered_cylinder))] + public object Item1 + { + get + { + return this.item1Field; + } + set + { + this.item1Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("rotate", typeof(rotate))] + [System.Xml.Serialization.XmlElementAttribute("translate", typeof(TargetableFloat3))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_bodyTechnique_commonShapeHollow + { + + private string sidField; + + private bool valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public bool Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class box + { + + private string half_extentsField; + + private extra[] extraField; + + /// + public string half_extents + { + get + { + return this.half_extentsField; + } + set + { + this.half_extentsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class capsule + { + + private double heightField; + + private string radiusField; + + private extra[] extraField; + + /// + public double height + { + get + { + return this.heightField; + } + set + { + this.heightField = value; + } + } + + /// + public string radius + { + get + { + return this.radiusField; + } + set + { + this.radiusField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class cylinder + { + + private double heightField; + + private string radiusField; + + private extra[] extraField; + + /// + public double height + { + get + { + return this.heightField; + } + set + { + this.heightField = value; + } + } + + /// + public string radius + { + get + { + return this.radiusField; + } + set + { + this.radiusField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class plane + { + + private string equationField; + + private extra[] extraField; + + /// + public string equation + { + get + { + return this.equationField; + } + set + { + this.equationField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class sphere + { + + private double radiusField; + + private extra[] extraField; + + /// + public double radius + { + get + { + return this.radiusField; + } + set + { + this.radiusField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class tapered_capsule + { + + private double heightField; + + private string radius1Field; + + private string radius2Field; + + private extra[] extraField; + + /// + public double height + { + get + { + return this.heightField; + } + set + { + this.heightField = value; + } + } + + /// + public string radius1 + { + get + { + return this.radius1Field; + } + set + { + this.radius1Field = value; + } + } + + /// + public string radius2 + { + get + { + return this.radius2Field; + } + set + { + this.radius2Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class tapered_cylinder + { + + private double heightField; + + private string radius1Field; + + private string radius2Field; + + private extra[] extraField; + + /// + public double height + { + get + { + return this.heightField; + } + set + { + this.heightField = value; + } + } + + /// + public string radius1 + { + get + { + return this.radius1Field; + } + set + { + this.radius1Field = value; + } + } + + /// + public string radius2 + { + get + { + return this.radius2Field; + } + set + { + this.radius2Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class rigid_constraint + { + + private rigid_constraintRef_attachment ref_attachmentField; + + private rigid_constraintAttachment attachmentField; + + private rigid_constraintTechnique_common technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + private string sidField; + + private string nameField; + + /// + public rigid_constraintRef_attachment ref_attachment + { + get + { + return this.ref_attachmentField; + } + set + { + this.ref_attachmentField = value; + } + } + + /// + public rigid_constraintAttachment attachment + { + get + { + return this.attachmentField; + } + set + { + this.attachmentField = value; + } + } + + /// + public rigid_constraintTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintRef_attachment + { + + private object[] itemsField; + + private string rigid_bodyField; + + /// + [System.Xml.Serialization.XmlElementAttribute("extra", typeof(extra))] + [System.Xml.Serialization.XmlElementAttribute("rotate", typeof(rotate))] + [System.Xml.Serialization.XmlElementAttribute("translate", typeof(TargetableFloat3))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string rigid_body + { + get + { + return this.rigid_bodyField; + } + set + { + this.rigid_bodyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintAttachment + { + + private object[] itemsField; + + private string rigid_bodyField; + + /// + [System.Xml.Serialization.XmlElementAttribute("extra", typeof(extra))] + [System.Xml.Serialization.XmlElementAttribute("rotate", typeof(rotate))] + [System.Xml.Serialization.XmlElementAttribute("translate", typeof(TargetableFloat3))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string rigid_body + { + get + { + return this.rigid_bodyField; + } + set + { + this.rigid_bodyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_common + { + + private rigid_constraintTechnique_commonEnabled enabledField; + + private rigid_constraintTechnique_commonInterpenetrate interpenetrateField; + + private rigid_constraintTechnique_commonLimits limitsField; + + private rigid_constraintTechnique_commonSpring springField; + + /// + // CODEGEN Warning: DefaultValue attribute on members of type rigid_constraintTechnique_commonEnabled is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='true' attribute. + public rigid_constraintTechnique_commonEnabled enabled + { + get + { + return this.enabledField; + } + set + { + this.enabledField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type rigid_constraintTechnique_commonInterpenetrate is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='false' attribute. + public rigid_constraintTechnique_commonInterpenetrate interpenetrate + { + get + { + return this.interpenetrateField; + } + set + { + this.interpenetrateField = value; + } + } + + /// + public rigid_constraintTechnique_commonLimits limits + { + get + { + return this.limitsField; + } + set + { + this.limitsField = value; + } + } + + /// + public rigid_constraintTechnique_commonSpring spring + { + get + { + return this.springField; + } + set + { + this.springField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonEnabled + { + + private string sidField; + + private bool valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public bool Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonInterpenetrate + { + + private string sidField; + + private bool valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public bool Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonLimits + { + + private rigid_constraintTechnique_commonLimitsSwing_cone_and_twist swing_cone_and_twistField; + + private rigid_constraintTechnique_commonLimitsLinear linearField; + + /// + public rigid_constraintTechnique_commonLimitsSwing_cone_and_twist swing_cone_and_twist + { + get + { + return this.swing_cone_and_twistField; + } + set + { + this.swing_cone_and_twistField = value; + } + } + + /// + public rigid_constraintTechnique_commonLimitsLinear linear + { + get + { + return this.linearField; + } + set + { + this.linearField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonLimitsSwing_cone_and_twist + { + + private TargetableFloat3 minField; + + private TargetableFloat3 maxField; + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat3 is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0 0.0 0.0' attribute. + public TargetableFloat3 min + { + get + { + return this.minField; + } + set + { + this.minField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat3 is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0 0.0 0.0' attribute. + public TargetableFloat3 max + { + get + { + return this.maxField; + } + set + { + this.maxField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonLimitsLinear + { + + private TargetableFloat3 minField; + + private TargetableFloat3 maxField; + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat3 is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0 0.0 0.0' attribute. + public TargetableFloat3 min + { + get + { + return this.minField; + } + set + { + this.minField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat3 is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0 0.0 0.0' attribute. + public TargetableFloat3 max + { + get + { + return this.maxField; + } + set + { + this.maxField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonSpring + { + + private rigid_constraintTechnique_commonSpringAngular angularField; + + private rigid_constraintTechnique_commonSpringLinear linearField; + + /// + public rigid_constraintTechnique_commonSpringAngular angular + { + get + { + return this.angularField; + } + set + { + this.angularField = value; + } + } + + /// + public rigid_constraintTechnique_commonSpringLinear linear + { + get + { + return this.linearField; + } + set + { + this.linearField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonSpringAngular + { + + private TargetableFloat stiffnessField; + + private TargetableFloat dampingField; + + private TargetableFloat target_valueField; + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='1.0' attribute. + public TargetableFloat stiffness + { + get + { + return this.stiffnessField; + } + set + { + this.stiffnessField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat damping + { + get + { + return this.dampingField; + } + set + { + this.dampingField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat target_value + { + get + { + return this.target_valueField; + } + set + { + this.target_valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class rigid_constraintTechnique_commonSpringLinear + { + + private TargetableFloat stiffnessField; + + private TargetableFloat dampingField; + + private TargetableFloat target_valueField; + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='1.0' attribute. + public TargetableFloat stiffness + { + get + { + return this.stiffnessField; + } + set + { + this.stiffnessField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat damping + { + get + { + return this.dampingField; + } + set + { + this.dampingField = value; + } + } + + /// + // CODEGEN Warning: DefaultValue attribute on members of type TargetableFloat is not supported in this version of the .Net Framework. + // CODEGEN Warning: 'default' attribute supported only for primitive types. Ignoring default='0.0' attribute. + public TargetableFloat target_value + { + get + { + return this.target_valueField; + } + set + { + this.target_valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class instance_physics_model + { + + private InstanceWithExtra[] instance_force_fieldField; + + private instance_rigid_body[] instance_rigid_bodyField; + + private instance_rigid_constraint[] instance_rigid_constraintField; + + private extra[] extraField; + + private string urlField; + + private string sidField; + + private string nameField; + + private string parentField; + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_force_field")] + public InstanceWithExtra[] instance_force_field + { + get + { + return this.instance_force_fieldField; + } + set + { + this.instance_force_fieldField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_rigid_body")] + public instance_rigid_body[] instance_rigid_body + { + get + { + return this.instance_rigid_bodyField; + } + set + { + this.instance_rigid_bodyField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_rigid_constraint")] + public instance_rigid_constraint[] instance_rigid_constraint + { + get + { + return this.instance_rigid_constraintField; + } + set + { + this.instance_rigid_constraintField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string url + { + get + { + return this.urlField; + } + set + { + this.urlField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string parent + { + get + { + return this.parentField; + } + set + { + this.parentField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class instance_rigid_body + { + + private instance_rigid_bodyTechnique_common technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + private string bodyField; + + private string sidField; + + private string nameField; + + private string targetField; + + /// + public instance_rigid_bodyTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string body + { + get + { + return this.bodyField; + } + set + { + this.bodyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string target + { + get + { + return this.targetField; + } + set + { + this.targetField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_rigid_bodyTechnique_common + { + + private string angular_velocityField; + + private string velocityField; + + private instance_rigid_bodyTechnique_commonDynamic dynamicField; + + private TargetableFloat massField; + + private object[] mass_frameField; + + private TargetableFloat3 inertiaField; + + private object itemField; + + private instance_rigid_bodyTechnique_commonShape[] shapeField; + + public instance_rigid_bodyTechnique_common() + { + this.angular_velocityField = "0.0 0.0 0.0"; + this.velocityField = "0.0 0.0 0.0"; + } + + /// + [System.ComponentModel.DefaultValueAttribute("0.0 0.0 0.0")] + public string angular_velocity + { + get + { + return this.angular_velocityField; + } + set + { + this.angular_velocityField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute("0.0 0.0 0.0")] + public string velocity + { + get + { + return this.velocityField; + } + set + { + this.velocityField = value; + } + } + + /// + public instance_rigid_bodyTechnique_commonDynamic dynamic + { + get + { + return this.dynamicField; + } + set + { + this.dynamicField = value; + } + } + + /// + public TargetableFloat mass + { + get + { + return this.massField; + } + set + { + this.massField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("rotate", typeof(rotate), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("translate", typeof(TargetableFloat3), IsNullable = false)] + public object[] mass_frame + { + get + { + return this.mass_frameField; + } + set + { + this.mass_frameField = value; + } + } + + /// + public TargetableFloat3 inertia + { + get + { + return this.inertiaField; + } + set + { + this.inertiaField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_physics_material", typeof(InstanceWithExtra))] + [System.Xml.Serialization.XmlElementAttribute("physics_material", typeof(physics_material))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("shape")] + public instance_rigid_bodyTechnique_commonShape[] shape + { + get + { + return this.shapeField; + } + set + { + this.shapeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_rigid_bodyTechnique_commonDynamic + { + + private string sidField; + + private bool valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public bool Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_rigid_bodyTechnique_commonShape + { + + private instance_rigid_bodyTechnique_commonShapeHollow hollowField; + + private TargetableFloat massField; + + private TargetableFloat densityField; + + private object itemField; + + private object item1Field; + + private object[] itemsField; + + private extra[] extraField; + + /// + public instance_rigid_bodyTechnique_commonShapeHollow hollow + { + get + { + return this.hollowField; + } + set + { + this.hollowField = value; + } + } + + /// + public TargetableFloat mass + { + get + { + return this.massField; + } + set + { + this.massField = value; + } + } + + /// + public TargetableFloat density + { + get + { + return this.densityField; + } + set + { + this.densityField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_physics_material", typeof(InstanceWithExtra))] + [System.Xml.Serialization.XmlElementAttribute("physics_material", typeof(physics_material))] + public object Item + { + get + { + return this.itemField; + } + set + { + this.itemField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("box", typeof(box))] + [System.Xml.Serialization.XmlElementAttribute("capsule", typeof(capsule))] + [System.Xml.Serialization.XmlElementAttribute("cylinder", typeof(cylinder))] + [System.Xml.Serialization.XmlElementAttribute("instance_geometry", typeof(instance_geometry))] + [System.Xml.Serialization.XmlElementAttribute("plane", typeof(plane))] + [System.Xml.Serialization.XmlElementAttribute("sphere", typeof(sphere))] + [System.Xml.Serialization.XmlElementAttribute("tapered_capsule", typeof(tapered_capsule))] + [System.Xml.Serialization.XmlElementAttribute("tapered_cylinder", typeof(tapered_cylinder))] + public object Item1 + { + get + { + return this.item1Field; + } + set + { + this.item1Field = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("rotate", typeof(rotate))] + [System.Xml.Serialization.XmlElementAttribute("translate", typeof(TargetableFloat3))] + public object[] Items + { + get + { + return this.itemsField; + } + set + { + this.itemsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class instance_rigid_bodyTechnique_commonShapeHollow + { + + private string sidField; + + private bool valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public bool Value + { + get + { + return this.valueField; + } + set + { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class instance_rigid_constraint + { + + private extra[] extraField; + + private string constraintField; + + private string sidField; + + private string nameField; + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string constraint + { + get + { + return this.constraintField; + } + set + { + this.constraintField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string sid + { + get + { + return this.sidField; + } + set + { + this.sidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_physics_scenes + { + + private asset assetField; + + private physics_scene[] physics_sceneField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("physics_scene")] + public physics_scene[] physics_scene + { + get + { + return this.physics_sceneField; + } + set + { + this.physics_sceneField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class physics_scene + { + + private asset assetField; + + private InstanceWithExtra[] instance_force_fieldField; + + private instance_physics_model[] instance_physics_modelField; + + private physics_sceneTechnique_common technique_commonField; + + private technique[] techniqueField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_force_field")] + public InstanceWithExtra[] instance_force_field + { + get + { + return this.instance_force_fieldField; + } + set + { + this.instance_force_fieldField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_physics_model")] + public instance_physics_model[] instance_physics_model + { + get + { + return this.instance_physics_modelField; + } + set + { + this.instance_physics_modelField = value; + } + } + + /// + public physics_sceneTechnique_common technique_common + { + get + { + return this.technique_commonField; + } + set + { + this.technique_commonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("technique")] + public technique[] technique + { + get + { + return this.techniqueField; + } + set + { + this.techniqueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class physics_sceneTechnique_common + { + + private TargetableFloat3 gravityField; + + private TargetableFloat time_stepField; + + /// + public TargetableFloat3 gravity + { + get + { + return this.gravityField; + } + set + { + this.gravityField = value; + } + } + + /// + public TargetableFloat time_step + { + get + { + return this.time_stepField; + } + set + { + this.time_stepField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class library_visual_scenes + { + + private asset assetField; + + private visual_scene[] visual_sceneField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("visual_scene")] + public visual_scene[] visual_scene + { + get + { + return this.visual_sceneField; + } + set + { + this.visual_sceneField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class visual_scene + { + + private asset assetField; + + private node[] nodeField; + + private visual_sceneEvaluate_scene[] evaluate_sceneField; + + private extra[] extraField; + + private string idField; + + private string nameField; + + /// + public asset asset + { + get + { + return this.assetField; + } + set + { + this.assetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("node")] + public node[] node + { + get + { + return this.nodeField; + } + set + { + this.nodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("evaluate_scene")] + public visual_sceneEvaluate_scene[] evaluate_scene + { + get + { + return this.evaluate_sceneField; + } + set + { + this.evaluate_sceneField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "ID")] + public string id + { + get + { + return this.idField; + } + set + { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class visual_sceneEvaluate_scene + { + + private visual_sceneEvaluate_sceneRender[] renderField; + + private string nameField; + + /// + [System.Xml.Serialization.XmlElementAttribute("render")] + public visual_sceneEvaluate_sceneRender[] render + { + get + { + return this.renderField; + } + set + { + this.renderField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "NCName")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class visual_sceneEvaluate_sceneRender + { + + private string[] layerField; + + private instance_effect instance_effectField; + + private string camera_nodeField; + + /// + [System.Xml.Serialization.XmlElementAttribute("layer", DataType = "NCName")] + public string[] layer + { + get + { + return this.layerField; + } + set + { + this.layerField = value; + } + } + + /// + public instance_effect instance_effect + { + get + { + return this.instance_effectField; + } + set + { + this.instance_effectField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")] + public string camera_node + { + get + { + return this.camera_nodeField; + } + set + { + this.camera_nodeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public partial class COLLADAScene + { + + private InstanceWithExtra[] instance_physics_sceneField; + + private InstanceWithExtra instance_visual_sceneField; + + private extra[] extraField; + + /// + [System.Xml.Serialization.XmlElementAttribute("instance_physics_scene")] + public InstanceWithExtra[] instance_physics_scene + { + get + { + return this.instance_physics_sceneField; + } + set + { + this.instance_physics_sceneField = value; + } + } + + /// + public InstanceWithExtra instance_visual_scene + { + get + { + return this.instance_visual_sceneField; + } + set + { + this.instance_visual_sceneField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("extra")] + public extra[] extra + { + get + { + return this.extraField; + } + set + { + this.extraField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + public enum VersionType + { + + /// + [System.Xml.Serialization.XmlEnumAttribute("1.4.0")] + Item140, + + /// + [System.Xml.Serialization.XmlEnumAttribute("1.4.1")] + Item141, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.collada.org/2005/11/COLLADASchema")] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.collada.org/2005/11/COLLADASchema", IsNullable = false)] + public partial class ellipsoid + { + + private string sizeField; + + /// + public string size + { + get + { + return this.sizeField; + } + set + { + this.sizeField = value; + } + } + } + + public partial class COLLADA + { + public static string ConvertFromArray(double[] values) + { + if (values == null) return string.Empty; + string[] tmp = new string[values.Length]; + for (int i = 0; i < values.Length; i++) + { + tmp[i] = values[i].ToString(System.Globalization.CultureInfo.InvariantCulture); + } + return string.Join(" ", tmp); + } + + public static string ConvertFromArray(long[] values) + { + if (values == null) return string.Empty; + string[] tmp = new string[values.Length]; + for (int i = 0; i < values.Length; i++) + { + tmp[i] = values[i].ToString(System.Globalization.CultureInfo.InvariantCulture); + } + return string.Join(" ", tmp); + } + + public static string ConvertFromArray(bool[] values) + { + if (values == null) return string.Empty; + string[] tmp = new string[values.Length]; + for (int i = 0; i < values.Length; i++) + { + tmp[i] = values[i] ? "true" : "false"; + } + return string.Join(" ", tmp); + } + + public static string ConvertFromArray(string[] values) + { + if (values == null) return string.Empty; + return string.Join(" ", values); + } + + public static double[] ConvertDoubleArray(string val) + { + string[] vals = Regex.Split(val, @"\s+"); + double[] ret = new double[vals.Length]; + for (int i = 0; i < vals.Length; i++) + { + double.TryParse(vals[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out ret[i]); + } + return ret; + } + + public static long[] ConvertLongArray(string val) + { + string[] vals = Regex.Split(val, @"\s+"); + long[] ret = new long[vals.Length]; + for (int i = 0; i < vals.Length; i++) + { + long.TryParse(vals[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out ret[i]); + } + return ret; + } + + public static bool[] ConvertBoolArray(string val) + { + string[] vals = Regex.Split(val, @"\s+"); + var ret = new bool[vals.Length]; + for (int i = 0; i < vals.Length; i++) + { + ret[i] = vals[i] == "true"; + } + return ret; + } + + public static string[] ConvertNameArray(string val) + { + return Regex.Split(val, @"\s+"); + } + } +} diff --git a/OpenMetaverse/ImportExport/ColladalLoader.cs b/OpenMetaverse/ImportExport/ColladalLoader.cs new file mode 100644 index 0000000..02b8fec --- /dev/null +++ b/OpenMetaverse/ImportExport/ColladalLoader.cs @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.IO; +using System.Xml; +using System.Drawing; +using System.Xml.Serialization; +using OpenMetaverse.ImportExport.Collada14; +using OpenMetaverse.Rendering; +using OpenMetaverse.Imaging; + +namespace OpenMetaverse.ImportExport +{ + /// + /// Parsing Collada model files into data structures + /// + public class ColladaLoader + { + COLLADA Model; + static XmlSerializer Serializer = null; + List Nodes; + List Materials; + Dictionary MatSymTarget; + string FileName; + + class Node + { + public Matrix4 Transform = Matrix4.Identity; + public string Name; + public string ID; + public string MeshID; + } + + /// + /// Parses Collada document + /// + /// Load .dae model from this file + /// Load and decode images for uploading with model + /// A list of mesh prims that were parsed from the collada file + public List Load(string filename, bool loadImages) + { + try + { + // Create an instance of the XmlSerializer specifying type and namespace. + if (Serializer == null) + { + Serializer = new XmlSerializer(typeof(COLLADA)); + } + + this.FileName = filename; + + // A FileStream is needed to read the XML document. + FileStream fs = new FileStream(filename, FileMode.Open); + XmlReader reader = XmlReader.Create(fs); + Model = (COLLADA)Serializer.Deserialize(reader); + fs.Close(); + var prims = Parse(); + if (loadImages) + { + LoadImages(prims); + } + return prims; + } + catch (Exception ex) + { + Logger.Log("Failed parsing collada file: " + ex.Message, Helpers.LogLevel.Error, ex); + return new List(); + } + } + + void LoadImages(List prims) + { + foreach (var prim in prims) + { + foreach (var face in prim.Faces) + { + if (!string.IsNullOrEmpty(face.Material.Texture)) + { + LoadImage(face.Material); + } + } + } + } + + void LoadImage(ModelMaterial material) + { + var fname = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(FileName), material.Texture); + + try + { + string ext = System.IO.Path.GetExtension(material.Texture).ToLower(); + + Bitmap bitmap = null; + + if (ext == ".jp2" || ext == ".j2c") + { + material.TextureData = File.ReadAllBytes(fname); + return; + } + + if (ext == ".tga") + { + bitmap = LoadTGAClass.LoadTGA(fname); + } + else + { + bitmap = (Bitmap)Image.FromFile(fname); + } + + int width = bitmap.Width; + int height = bitmap.Height; + + // Handle resizing to prevent excessively large images and irregular dimensions + if (!IsPowerOfTwo((uint)width) || !IsPowerOfTwo((uint)height) || width > 1024 || height > 1024) + { + var origWidth = width; + var origHieght = height; + + width = ClosestPowerOwTwo(width); + height = ClosestPowerOwTwo(height); + + width = width > 1024 ? 1024 : width; + height = height > 1024 ? 1024 : height; + + Logger.Log("Image has irregular dimensions " + origWidth + "x" + origHieght + ". Resizing to " + width + "x" + height, Helpers.LogLevel.Info); + + Bitmap resized = new Bitmap(width, height, bitmap.PixelFormat); + Graphics graphics = Graphics.FromImage(resized); + + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + graphics.InterpolationMode = + System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + graphics.DrawImage(bitmap, 0, 0, width, height); + + bitmap.Dispose(); + bitmap = resized; + } + + material.TextureData = OpenJPEG.EncodeFromImage(bitmap, false); + + Logger.Log("Successfully encoded " + fname, Helpers.LogLevel.Info); + } + catch (Exception ex) + { + Logger.Log("Failed loading " + fname + ": " + ex.Message, Helpers.LogLevel.Warning); + } + + } + + bool IsPowerOfTwo(uint n) + { + return (n & (n - 1)) == 0 && n != 0; + } + + int ClosestPowerOwTwo(int n) + { + int res = 1; + + while (res < n) + { + res <<= 1; + } + + return res > 1 ? res / 2 : 1; + } + + ModelMaterial ExtractMaterial(object diffuse) + { + ModelMaterial ret = new ModelMaterial(); + if (diffuse is common_color_or_texture_typeColor) + { + var col = (common_color_or_texture_typeColor)diffuse; + ret.DiffuseColor = new Color4((float)col.Values[0], (float)col.Values[1], (float)col.Values[2], (float)col.Values[3]); + } + else if (diffuse is common_color_or_texture_typeTexture) + { + var tex = (common_color_or_texture_typeTexture)diffuse; + ret.Texture = tex.texcoord; + } + return ret; + + } + + void ParseMaterials() + { + + if (Model == null) return; + + Materials = new List(); + + // Material -> effect mapping + Dictionary matEffect = new Dictionary(); + List tmpEffects = new List(); + + // Image ID -> filename mapping + Dictionary imgMap = new Dictionary(); + + foreach (var item in Model.Items) + { + if (item is library_images) + { + var images = (library_images)item; + if (images.image != null) + { + foreach (var image in images.image) + { + var img = (image)image; + string ID = img.id; + if (img.Item is string) + { + imgMap[ID] = (string)img.Item; + } + } + } + } + } + + foreach (var item in Model.Items) + { + if (item is library_materials) + { + var materials = (library_materials)item; + if (materials.material != null) + { + foreach (var material in materials.material) + { + var ID = material.id; + if (material.instance_effect != null) + { + if (!string.IsNullOrEmpty(material.instance_effect.url)) + { + matEffect[material.instance_effect.url.Substring(1)] = ID; + } + } + } + } + } + } + + foreach (var item in Model.Items) + { + if (item is library_effects) + { + var effects = (library_effects)item; + if (effects.effect != null) + { + foreach (var effect in effects.effect) + { + string ID = effect.id; + foreach (var effItem in effect.Items) + { + if (effItem is effectFx_profile_abstractProfile_COMMON) + { + var teq = ((effectFx_profile_abstractProfile_COMMON)effItem).technique; + if (teq != null) + { + if (teq.Item is effectFx_profile_abstractProfile_COMMONTechniquePhong) + { + var shader = (effectFx_profile_abstractProfile_COMMONTechniquePhong)teq.Item; + if (shader.diffuse != null) + { + var material = ExtractMaterial(shader.diffuse.Item); + material.ID = ID; + tmpEffects.Add(material); + } + } + else if (teq.Item is effectFx_profile_abstractProfile_COMMONTechniqueLambert) + { + var shader = (effectFx_profile_abstractProfile_COMMONTechniqueLambert)teq.Item; + if (shader.diffuse != null) + { + var material = ExtractMaterial(shader.diffuse.Item); + material.ID = ID; + tmpEffects.Add(material); + } + } + } + } + } + } + } + } + } + + foreach (var effect in tmpEffects) + { + if (matEffect.ContainsKey(effect.ID)) + { + effect.ID = matEffect[effect.ID]; + if (!string.IsNullOrEmpty(effect.Texture)) + { + if (imgMap.ContainsKey(effect.Texture)) + { + effect.Texture = imgMap[effect.Texture]; + } + } + Materials.Add(effect); + } + } + } + + void ProcessNode(node node) + { + Node n = new Node(); + n.ID = node.id; + + if (node.Items != null) + // Try finding matrix + foreach (var i in node.Items) + { + if (i is matrix) + { + var m = (matrix)i; + for (int a = 0; a < 4; a++) + for (int b = 0; b < 4; b++) + { + n.Transform[b, a] = (float)m.Values[a * 4 + b]; + } + } + } + + // Find geometry and material + if (node.instance_geometry != null && node.instance_geometry.Length > 0) + { + var instGeom = node.instance_geometry[0]; + if (!string.IsNullOrEmpty(instGeom.url)) + { + n.MeshID = instGeom.url.Substring(1); + } + if (instGeom.bind_material != null && instGeom.bind_material.technique_common != null) + { + foreach (var teq in instGeom.bind_material.technique_common) + { + var target = teq.target; + if (!string.IsNullOrEmpty(target)) + { + target = target.Substring(1); + MatSymTarget[teq.symbol] = target; + } + } + } + } + + if (node.Items != null && node.instance_geometry != null && node.instance_geometry.Length > 0) + Nodes.Add(n); + + // Recurse if the scene is hierarchical + if (node.node1 != null) + foreach (node nd in node.node1) + ProcessNode(nd); + } + + void ParseVisualScene() + { + Nodes = new List(); + if (Model == null) return; + + MatSymTarget = new Dictionary(); + + foreach (var item in Model.Items) + { + if (item is library_visual_scenes) + { + var scene = ((library_visual_scenes)item).visual_scene[0]; + foreach (var node in scene.node) + { + ProcessNode(node); + } + } + } + } + + List Parse() + { + var Prims = new List(); + + float DEG_TO_RAD = 0.017453292519943295769236907684886f; + + if (Model == null) return Prims; + + Matrix4 transform = Matrix4.Identity; + + UpAxisType upAxis = UpAxisType.Y_UP; + + var asset = Model.asset; + if (asset != null) + { + upAxis = asset.up_axis; + if (asset.unit != null) + { + float meter = (float)asset.unit.meter; + transform[0, 0] = meter; + transform[1, 1] = meter; + transform[2, 2] = meter; + } + } + + Matrix4 rotation = Matrix4.Identity; + + if (upAxis == UpAxisType.X_UP) + { + rotation = Matrix4.CreateFromEulers(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (upAxis == UpAxisType.Y_UP) + { + rotation = Matrix4.CreateFromEulers(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation = rotation * transform; + transform = rotation; + + ParseVisualScene(); + ParseMaterials(); + + foreach (var item in Model.Items) + { + if (item is library_geometries) + { + var geometries = (library_geometries)item; + foreach (var geo in geometries.geometry) + { + var mesh = geo.Item as mesh; + if (mesh == null) continue; + + var nodes = Nodes.FindAll(n => n.MeshID == geo.id); + if (nodes != null) + { + byte[] mesh_asset = null; + foreach (var node in nodes) + { + var prim = new ModelPrim(); + prim.ID = node.ID; + Prims.Add(prim); + Matrix4 primTransform = transform; + primTransform = primTransform * node.Transform; + + AddPositions(mesh, prim, primTransform); + + foreach (var mitem in mesh.Items) + { + if (mitem is triangles) + { + AddFacesFromPolyList(Triangles2Polylist((triangles)mitem), mesh, prim, primTransform); + } + if (mitem is polylist) + { + AddFacesFromPolyList((polylist)mitem, mesh, prim, primTransform); + } + } + + if (mesh_asset == null) + { + prim.CreateAsset(UUID.Zero); + mesh_asset = prim.Asset; + } + else + prim.Asset = mesh_asset; + } + } + } + } + } + + return Prims; + } + + source FindSource(source[] sources, string id) + { + id = id.Substring(1); + + foreach (var src in sources) + { + if (src.id == id) + return src; + } + return null; + } + + void AddPositions(mesh mesh, ModelPrim prim, Matrix4 transform) + { + prim.Positions = new List(); + source posSrc = FindSource(mesh.source, mesh.vertices.input[0].source); + double[] posVals = ((float_array)posSrc.Item).Values; + + for (int i = 0; i < posVals.Length / 3; i++) + { + Vector3 pos = new Vector3((float)posVals[i * 3], (float)posVals[i * 3 + 1], (float)posVals[i * 3 + 2]); + pos = Vector3.Transform(pos, transform); + prim.Positions.Add(pos); + } + + prim.BoundMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + prim.BoundMax = new Vector3(float.MinValue, float.MinValue, float.MinValue); + + foreach (var pos in prim.Positions) + { + if (pos.X > prim.BoundMax.X) prim.BoundMax.X = pos.X; + if (pos.Y > prim.BoundMax.Y) prim.BoundMax.Y = pos.Y; + if (pos.Z > prim.BoundMax.Z) prim.BoundMax.Z = pos.Z; + + if (pos.X < prim.BoundMin.X) prim.BoundMin.X = pos.X; + if (pos.Y < prim.BoundMin.Y) prim.BoundMin.Y = pos.Y; + if (pos.Z < prim.BoundMin.Z) prim.BoundMin.Z = pos.Z; + } + + prim.Scale = prim.BoundMax - prim.BoundMin; + prim.Position = prim.BoundMin + (prim.Scale / 2); + + // Fit vertex positions into identity cube -0.5 .. 0.5 + for (int i = 0; i < prim.Positions.Count; i++) + { + Vector3 pos = prim.Positions[i]; + pos = new Vector3( + prim.Scale.X == 0 ? 0 : ((pos.X - prim.BoundMin.X) / prim.Scale.X) - 0.5f, + prim.Scale.Y == 0 ? 0 : ((pos.Y - prim.BoundMin.Y) / prim.Scale.Y) - 0.5f, + prim.Scale.Z == 0 ? 0 : ((pos.Z - prim.BoundMin.Z) / prim.Scale.Z) - 0.5f + ); + prim.Positions[i] = pos; + } + + } + + int[] StrToArray(string s) + { + string[] vals = Regex.Split(s.Trim(), @"\s+"); + int[] ret = new int[vals.Length]; + + for (int i = 0; i < ret.Length; i++) + { + int.TryParse(vals[i], out ret[i]); + } + + return ret; + } + + void AddFacesFromPolyList(polylist list, mesh mesh, ModelPrim prim, Matrix4 transform) + { + string material = list.material; + source posSrc = null; + source normalSrc = null; + source uvSrc = null; + + ulong stride = 0; + int posOffset = -1; + int norOffset = -1; + int uvOffset = -1; + + foreach (var inp in list.input) + { + stride = Math.Max(stride, inp.offset); + + if (inp.semantic == "VERTEX") + { + posSrc = FindSource(mesh.source, mesh.vertices.input[0].source); + posOffset = (int)inp.offset; + } + else if (inp.semantic == "NORMAL") + { + normalSrc = FindSource(mesh.source, inp.source); + norOffset = (int)inp.offset; + } + else if (inp.semantic == "TEXCOORD") + { + uvSrc = FindSource(mesh.source, inp.source); + uvOffset = (int)inp.offset; + } + } + + stride += 1; + + if (posSrc == null) return; + + var vcount = StrToArray(list.vcount); + var idx = StrToArray(list.p); + + Vector3[] normals = null; + if (normalSrc != null) + { + var norVal = ((float_array)normalSrc.Item).Values; + normals = new Vector3[norVal.Length / 3]; + + for (int i = 0; i < normals.Length; i++) + { + normals[i] = new Vector3((float)norVal[i * 3 + 0], (float)norVal[i * 3 + 1], (float)norVal[i * 3 + 2]); + normals[i] = Vector3.TransformNormal(normals[i], transform); + normals[i].Normalize(); + } + } + + Vector2[] uvs = null; + if (uvSrc != null) + { + var uvVal = ((float_array)uvSrc.Item).Values; + uvs = new Vector2[uvVal.Length / 2]; + + for (int i = 0; i < uvs.Length; i++) + { + uvs[i] = new Vector2((float)uvVal[i * 2 + 0], (float)uvVal[i * 2 + 1]); + } + + } + + ModelFace face = new ModelFace(); + face.MaterialID = list.material; + if (face.MaterialID != null) + { + if (MatSymTarget.ContainsKey(list.material)) + { + ModelMaterial mat = Materials.Find(m => m.ID == MatSymTarget[list.material]); + if (mat != null) + { + face.Material = mat; + } + } + } + + int curIdx = 0; + + for (int i = 0; i < vcount.Length; i++) + { + var nvert = vcount[i]; + if (nvert < 3 || nvert > 4) + { + throw new InvalidDataException("Only triangles and quads supported"); + } + + Vertex[] verts = new Vertex[nvert]; + for (int j = 0; j < nvert; j++) + { + verts[j].Position = prim.Positions[idx[curIdx + posOffset + (int)stride * j]]; + + if (normals != null) + { + verts[j].Normal = normals[idx[curIdx + norOffset + (int)stride * j]]; + } + + if (uvs != null) + { + verts[j].TexCoord = uvs[idx[curIdx + uvOffset + (int)stride * j]]; + } + } + + + if (nvert == 3) // add the triangle + { + face.AddVertex(verts[0]); + face.AddVertex(verts[1]); + face.AddVertex(verts[2]); + } + else if (nvert == 4) // quad, add two triangles + { + face.AddVertex(verts[0]); + face.AddVertex(verts[1]); + face.AddVertex(verts[2]); + + face.AddVertex(verts[0]); + face.AddVertex(verts[2]); + face.AddVertex(verts[3]); + } + + curIdx += (int)stride * nvert; + } + + prim.Faces.Add(face); + + + } + + polylist Triangles2Polylist(triangles triangles) + { + polylist poly = new polylist(); + poly.count = triangles.count; + poly.input = triangles.input; + poly.material = triangles.material; + poly.name = triangles.name; + poly.p = triangles.p; + + string str = "3 "; + System.Text.StringBuilder builder = new System.Text.StringBuilder(str.Length * (int)poly.count); + for (int i = 0; i < (int)poly.count; i++) builder.Append(str); + poly.vcount = builder.ToString(); + + return poly; + } + + } +} diff --git a/OpenMetaverse/ImportExport/Model.cs b/OpenMetaverse/ImportExport/Model.cs new file mode 100644 index 0000000..54a6d9b --- /dev/null +++ b/OpenMetaverse/ImportExport/Model.cs @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse.Rendering; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.ImportExport +{ + + public class ModelMaterial + { + public string ID; + public Color4 DiffuseColor = Color4.White; + public string Texture; + public byte[] TextureData; + } + + public class ModelFace + { + public List Vertices = new List(); + public List Indices = new List(); + public string MaterialID = string.Empty; + public ModelMaterial Material = new ModelMaterial(); + + Dictionary LookUp = new Dictionary(); + + public void AddVertex(Vertex v) + { + int index; + + if (LookUp.ContainsKey(v)) + { + index = LookUp[v]; + } + else + { + index = Vertices.Count; + Vertices.Add(v); + LookUp[v] = index; + } + + Indices.Add((uint)index); + } + + } + + public class ModelPrim + { + public List Positions; + public Vector3 BoundMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + public Vector3 BoundMax = new Vector3(float.MinValue, float.MinValue, float.MinValue); + public Vector3 Position; + public Vector3 Scale; + public Quaternion Rotation = Quaternion.Identity; + public List Faces = new List(); + public string ID; + public byte[] Asset; + + public void CreateAsset(UUID creator) + { + OSDMap header = new OSDMap(); + header["version"] = 1; + header["creator"] = creator; + header["date"] = DateTime.Now; + + OSDArray faces = new OSDArray(); + foreach (var face in Faces) + { + OSDMap faceMap = new OSDMap(); + + // Find UV min/max + Vector2 uvMin = new Vector2(float.MaxValue, float.MaxValue); + Vector2 uvMax = new Vector2(float.MinValue, float.MinValue); + foreach (var v in face.Vertices) + { + if (v.TexCoord.X < uvMin.X) uvMin.X = v.TexCoord.X; + if (v.TexCoord.Y < uvMin.Y) uvMin.Y = v.TexCoord.Y; + + if (v.TexCoord.X > uvMax.X) uvMax.X = v.TexCoord.X; + if (v.TexCoord.Y > uvMax.Y) uvMax.Y = v.TexCoord.Y; + } + OSDMap uvDomain = new OSDMap(); + uvDomain["Min"] = uvMin; + uvDomain["Max"] = uvMax; + faceMap["TexCoord0Domain"] = uvDomain; + + + OSDMap positionDomain = new OSDMap(); + positionDomain["Min"] = new Vector3(-0.5f, -0.5f, -0.5f); + positionDomain["Max"] = new Vector3(0.5f, 0.5f, 0.5f); + faceMap["PositionDomain"] = positionDomain; + + List posBytes = new List(face.Vertices.Count * sizeof(UInt16) * 3); + List norBytes = new List(face.Vertices.Count * sizeof(UInt16) * 3); + List uvBytes = new List(face.Vertices.Count * sizeof(UInt16) * 2); + + foreach (var v in face.Vertices) + { + posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.X, -0.5f, 0.5f))); + posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.Y, -0.5f, 0.5f))); + posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.Z, -0.5f, 0.5f))); + + norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.X, -1f, 1f))); + norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.Y, -1f, 1f))); + norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.Z, -1f, 1f))); + + uvBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.TexCoord.X, uvMin.X, uvMax.X))); + uvBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.TexCoord.Y, uvMin.Y, uvMax.Y))); + } + + faceMap["Position"] = posBytes.ToArray(); + faceMap["Normal"] = norBytes.ToArray(); + faceMap["TexCoord0"] = uvBytes.ToArray(); + + List indexBytes = new List(face.Indices.Count * sizeof(UInt16)); + foreach (var t in face.Indices) + { + indexBytes.AddRange(Utils.UInt16ToBytes((ushort)t)); + } + faceMap["TriangleList"] = indexBytes.ToArray(); + + faces.Add(faceMap); + } + + byte[] physicStubBytes = Helpers.ZCompressOSD(PhysicsStub()); + + byte[] meshBytes = Helpers.ZCompressOSD(faces); + int n = 0; + + OSDMap lodParms = new OSDMap(); + lodParms["offset"] = n; + lodParms["size"] = meshBytes.Length; + header["high_lod"] = lodParms; + n += meshBytes.Length; + + lodParms = new OSDMap(); + lodParms["offset"] = n; + lodParms["size"] = physicStubBytes.Length; + header["physics_convex"] = lodParms; + n += physicStubBytes.Length; + + byte[] headerBytes = OSDParser.SerializeLLSDBinary(header, false); + n += headerBytes.Length; + + Asset = new byte[n]; + + int offset = 0; + Buffer.BlockCopy(headerBytes, 0, Asset, offset, headerBytes.Length); + offset += headerBytes.Length; + + Buffer.BlockCopy(meshBytes, 0, Asset, offset, meshBytes.Length); + offset += meshBytes.Length; + + Buffer.BlockCopy(physicStubBytes, 0, Asset, offset, physicStubBytes.Length); + offset += physicStubBytes.Length; + + } + + public static OSD PhysicsStub() + { + OSDMap ret = new OSDMap(); + ret["Max"] = new Vector3(0.5f, 0.5f, 0.5f); + ret["Min"] = new Vector3(-0.5f, -0.5f, -0.5f); + ret["BoundingVerts"] = new byte[] { 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 255, 255, 255, 127, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 127, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255 }; + return ret; + } + + } +} \ No newline at end of file diff --git a/OpenMetaverse/ImportExport/ModelUploader.cs b/OpenMetaverse/ImportExport/ModelUploader.cs new file mode 100644 index 0000000..99758f8 --- /dev/null +++ b/OpenMetaverse/ImportExport/ModelUploader.cs @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; + +namespace OpenMetaverse.ImportExport +{ + /// + /// Implements mesh upload communications with the simulator + /// + public class ModelUploader + { + /// + /// Inlcude stub convex hull physics, required for uploading to Second Life + /// + public bool IncludePhysicsStub; + + /// + /// Use the same mesh used for geometry as the physical mesh upload + /// + public bool UseModelAsPhysics; + + GridClient Client; + List Prims; + + /// + /// Callback for mesh upload operations + /// + /// null on failure, result from server on success + public delegate void ModelUploadCallback(OSD result); + + + string InvName, InvDescription; + + /// + /// Creates instance of the mesh uploader + /// + /// GridClient instance to communicate with the simulator + /// List of ModelPrimitive objects to upload as a linkset + /// Inventory name for newly uploaded object + /// Inventory description for newly upload object + public ModelUploader(GridClient client, List prims, string newInvName, string newInvDesc) + { + this.Client = client; + this.Prims = prims; + this.InvName = newInvName; + this.InvDescription = newInvDesc; + } + + List Images; + Dictionary ImgIndex; + + OSD AssetResources(bool upload) + { + OSDArray instanceList = new OSDArray(); + List meshes = new List(); + List textures = new List(); + + foreach (var prim in Prims) + { + OSDMap primMap = new OSDMap(); + + OSDArray faceList = new OSDArray(); + + foreach (var face in prim.Faces) + { + OSDMap faceMap = new OSDMap(); + + faceMap["diffuse_color"] = face.Material.DiffuseColor; + faceMap["fullbright"] = false; + + if (face.Material.TextureData != null) + { + int index; + if (ImgIndex.ContainsKey(face.Material.Texture)) + { + index = ImgIndex[face.Material.Texture]; + } + else + { + index = Images.Count; + ImgIndex[face.Material.Texture] = index; + Images.Add(face.Material.TextureData); + } + faceMap["image"] = index; + faceMap["scales"] = 1.0f; + faceMap["scalet"] = 1.0f; + faceMap["offsets"] = 0.0f; + faceMap["offsett"] = 0.0f; + faceMap["imagerot"] = 0.0f; + } + + faceList.Add(faceMap); + } + + primMap["face_list"] = faceList; + + primMap["position"] = prim.Position; + primMap["rotation"] = prim.Rotation; + primMap["scale"] = prim.Scale; + + primMap["material"] = 3; // always sent as "wood" material + primMap["physics_shape_type"] = 2; // always sent as "convex hull"; + primMap["mesh"] = meshes.Count; + meshes.Add(prim.Asset); + + + instanceList.Add(primMap); + } + + OSDMap resources = new OSDMap(); + resources["instance_list"] = instanceList; + + OSDArray meshList = new OSDArray(); + foreach (var mesh in meshes) + { + meshList.Add(OSD.FromBinary(mesh)); + } + resources["mesh_list"] = meshList; + + OSDArray textureList = new OSDArray(); + for (int i = 0; i < Images.Count; i++) + { + if (upload) + { + textureList.Add(new OSDBinary(Images[i])); + } + else + { + textureList.Add(new OSDBinary(Utils.EmptyBytes)); + } + } + + resources["texture_list"] = textureList; + + resources["metric"] = "MUT_Unspecified"; + + return resources; + } + + /// + /// Performs model upload in one go, without first checking for the price + /// + public void Upload() + { + Upload(null); + } + + /// + /// Performs model upload in one go, without first checking for the price + /// + /// Callback that will be invoke upon completion of the upload. Null is sent on request failure + public void Upload(ModelUploadCallback callback) + { + PrepareUpload((result => + { + if (result == null && callback != null) + { + callback(null); + return; + } + + if (result is OSDMap) + { + var res = (OSDMap)result; + Uri uploader = new Uri(res["uploader"]); + PerformUpload(uploader, (contents => + { + if (contents != null) + { + var reply = (OSDMap)contents; + if (reply.ContainsKey("new_inventory_item") && reply.ContainsKey("new_asset")) + { + // Request full update on the item in order to update the local store + Client.Inventory.RequestFetchInventory(reply["new_inventory_item"].AsUUID(), Client.Self.AgentID); + } + } + if (callback != null) callback(contents); + })); + } + })); + + } + + /// + /// Ask server for details of cost and impact of the mesh upload + /// + /// Callback that will be invoke upon completion of the upload. Null is sent on request failure + public void PrepareUpload(ModelUploadCallback callback) + { + Uri url = null; + if (Client.Network.CurrentSim == null || + Client.Network.CurrentSim.Caps == null || + null == (url = Client.Network.CurrentSim.Caps.CapabilityURI("NewFileAgentInventory"))) + { + Logger.Log("Cannot upload mesh, no connection or NewFileAgentInventory not available", Helpers.LogLevel.Warning); + if (callback != null) callback(null); + return; + } + + Images = new List(); + ImgIndex = new Dictionary(); + + OSDMap req = new OSDMap(); + req["name"] = InvName; + req["description"] = InvDescription; + + req["asset_resources"] = AssetResources(false); + req["asset_type"] = "mesh"; + req["inventory_type"] = "object"; + + req["folder_id"] = Client.Inventory.FindFolderForType(AssetType.Object); + req["texture_folder_id"] = Client.Inventory.FindFolderForType(AssetType.Texture); + + req["everyone_mask"] = (int)PermissionMask.All; + req["group_mask"] = (int)PermissionMask.All; ; + req["next_owner_mask"] = (int)PermissionMask.All; + + CapsClient request = new CapsClient(url); + request.OnComplete += (client, result, error) => + { + if (error != null || result == null || result.Type != OSDType.Map) + { + Logger.Log("Mesh upload request failure", Helpers.LogLevel.Error); + if (callback != null) callback(null); + return; + } + OSDMap res = (OSDMap)result; + + if (res["state"] != "upload") + { + Logger.Log("Mesh upload failure: " + res["message"], Helpers.LogLevel.Error); + if (callback != null) callback(null); + return; + } + + Logger.Log("Response from mesh upload prepare:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug); + if (callback != null) callback(result); + }; + + request.BeginGetResponse(req, OSDFormat.Xml, 3 * 60 * 1000); + + } + + /// + /// Performas actual mesh and image upload + /// + /// Uri recieved in the upload prepare stage + /// Callback that will be invoke upon completion of the upload. Null is sent on request failure + public void PerformUpload(Uri uploader, ModelUploadCallback callback) + { + CapsClient request = new CapsClient(uploader); + request.OnComplete += (client, result, error) => + { + if (error != null || result == null || result.Type != OSDType.Map) + { + Logger.Log("Mesh upload request failure", Helpers.LogLevel.Error); + if (callback != null) callback(null); + return; + } + OSDMap res = (OSDMap)result; + Logger.Log("Response from mesh upload perform:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug); + if (callback != null) callback(res); + }; + + request.BeginGetResponse(AssetResources(true), OSDFormat.Xml, 60 * 1000); + } + + + } +} \ No newline at end of file diff --git a/OpenMetaverse/Interfaces/IMessage.cs b/OpenMetaverse/Interfaces/IMessage.cs new file mode 100644 index 0000000..99f9d42 --- /dev/null +++ b/OpenMetaverse/Interfaces/IMessage.cs @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse.StructuredData; + + +namespace OpenMetaverse.Interfaces +{ + /// + /// Interface requirements for Messaging system + /// + public interface IMessage + { + OSDMap Serialize(); + void Deserialize(OSDMap map); + } +} diff --git a/OpenMetaverse/Interfaces/IRendering.cs b/OpenMetaverse/Interfaces/IRendering.cs new file mode 100644 index 0000000..88ae10d --- /dev/null +++ b/OpenMetaverse/Interfaces/IRendering.cs @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace OpenMetaverse.Rendering +{ + [AttributeUsage(AttributeTargets.Class)] + public class RendererNameAttribute : System.Attribute + { + private string _name; + + public RendererNameAttribute(string name) + : base() + { + _name = name; + } + + public override string ToString() + { + return _name; + } + } + + /// + /// Abstract base for rendering plugins + /// + public interface IRendering + { + /// + /// Generates a basic mesh structure from a primitive + /// + /// Primitive to generate the mesh from + /// Level of detail to generate the mesh at + /// The generated mesh + SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod); + + /// + /// Generates a basic mesh structure from a sculpted primitive and + /// texture + /// + /// Sculpted primitive to generate the mesh from + /// Sculpt texture + /// Level of detail to generate the mesh at + /// The generated mesh + SimpleMesh GenerateSimpleSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod); + + /// + /// Generates a series of faces, each face containing a mesh and + /// metadata + /// + /// Primitive to generate the mesh from + /// Level of detail to generate the mesh at + /// The generated mesh + FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod); + + /// + /// Generates a series of faces for a sculpted prim, each face + /// containing a mesh and metadata + /// + /// Sculpted primitive to generate the mesh from + /// Sculpt texture + /// Level of detail to generate the mesh at + /// The generated mesh + FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod); + + /// + /// Apply texture coordinate modifications from a + /// to a list of vertices + /// + /// Vertex list to modify texture coordinates for + /// Center-point of the face + /// Face texture parameters + /// Scale of the prim + void TransformTexCoords (List vertices, Vector3 center, Primitive.TextureEntryFace teFace, Vector3 primScale); + } +} diff --git a/OpenMetaverse/InternalDictionary.cs b/OpenMetaverse/InternalDictionary.cs new file mode 100644 index 0000000..46b3551 --- /dev/null +++ b/OpenMetaverse/InternalDictionary.cs @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenMetaverse +{ + /// + /// The InternalDictionary class is used through the library for storing key/value pairs. + /// It is intended to be a replacement for the generic Dictionary class and should + /// be used in its place. It contains several methods for allowing access to the data from + /// outside the library that are read only and thread safe. + /// + /// + /// Key + /// Value + public class InternalDictionary + { + /// Internal dictionary that this class wraps around. Do not + /// modify or enumerate the contents of this dictionary without locking + /// on this member + internal Dictionary Dictionary; + + public Dictionary Copy() + { + lock (Dictionary) + return new Dictionary(Dictionary); + } + + /// + /// Gets the number of Key/Value pairs contained in the + /// + public int Count { get { return Dictionary.Count; } } + + /// + /// Initializes a new instance of the Class + /// with the specified key/value, has the default initial capacity. + /// + /// + /// + /// // initialize a new InternalDictionary named testDict with a string as the key and an int as the value. + /// public InternalDictionary<string, int> testDict = new InternalDictionary<string, int>(); + /// + /// + public InternalDictionary() + { + Dictionary = new Dictionary(); + } + + /// + /// Initializes a new instance of the Class + /// with the specified key/value, has its initial valies copied from the specified + /// + /// + /// + /// to copy initial values from + /// + /// + /// // initialize a new InternalDictionary named testAvName with a UUID as the key and an string as the value. + /// // populates with copied values from example KeyNameCache Dictionary. + /// + /// // create source dictionary + /// Dictionary<UUID, string> KeyNameCache = new Dictionary<UUID, string>(); + /// KeyNameCache.Add("8300f94a-7970-7810-cf2c-fc9aa6cdda24", "Jack Avatar"); + /// KeyNameCache.Add("27ba1e40-13f7-0708-3e98-5819d780bd62", "Jill Avatar"); + /// + /// // Initialize new dictionary. + /// public InternalDictionary<UUID, string> testAvName = new InternalDictionary<UUID, string>(KeyNameCache); + /// + /// + public InternalDictionary(IDictionary dictionary) + { + Dictionary = new Dictionary(dictionary); + } + + /// + /// Initializes a new instance of the Class + /// with the specified key/value, With its initial capacity specified. + /// + /// Initial size of dictionary + /// + /// + /// // initialize a new InternalDictionary named testDict with a string as the key and an int as the value, + /// // initially allocated room for 10 entries. + /// public InternalDictionary<string, int> testDict = new InternalDictionary<string, int>(10); + /// + /// + public InternalDictionary(int capacity) + { + Dictionary = new Dictionary(capacity); + } + + /// + /// Try to get entry from with specified key + /// + /// Key to use for lookup + /// Value returned + /// if specified key exists, if not found + /// + /// + /// // find your avatar using the Simulator.ObjectsAvatars InternalDictionary: + /// Avatar av; + /// if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.AgentID, out av)) + /// Console.WriteLine("Found Avatar {0}", av.Name); + /// + /// + /// + public bool TryGetValue(TKey key, out TValue value) + { + lock (Dictionary) + { + return Dictionary.TryGetValue(key, out value); + } + } + + /// + /// Finds the specified match. + /// + /// The match. + /// Matched value + /// + /// + /// // use a delegate to find a prim in the ObjectsPrimitives InternalDictionary + /// // with the ID 95683496 + /// uint findID = 95683496; + /// Primitive findPrim = sim.ObjectsPrimitives.Find( + /// delegate(Primitive prim) { return prim.ID == findID; }); + /// + /// + public TValue Find(Predicate match) + { + lock (Dictionary) + { + foreach (TValue value in Dictionary.Values) + { + if (match(value)) + return value; + } + } + return default(TValue); + } + + /// Find All items in an + /// return matching items. + /// a containing found items. + /// + /// Find All prims within 20 meters and store them in a List + /// + /// int radius = 20; + /// List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( + /// delegate(Primitive prim) { + /// Vector3 pos = prim.Position; + /// return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius)); + /// } + /// ); + /// + /// + public List FindAll(Predicate match) + { + List found = new List(); + lock (Dictionary) + { + foreach (KeyValuePair kvp in Dictionary) + { + if (match(kvp.Value)) + found.Add(kvp.Value); + } + } + return found; + } + + /// Find All items in an + /// return matching keys. + /// a containing found keys. + /// + /// Find All keys which also exist in another dictionary + /// + /// List<UUID> matches = myDict.FindAll( + /// delegate(UUID id) { + /// return myOtherDict.ContainsKey(id); + /// } + /// ); + /// + /// + public List FindAll(Predicate match) + { + List found = new List(); + lock (Dictionary) + { + foreach (KeyValuePair kvp in Dictionary) + { + if (match(kvp.Key)) + found.Add(kvp.Key); + } + } + return found; + } + + /// Perform an on each entry in an + /// to perform + /// + /// + /// // Iterates over the ObjectsPrimitives InternalDictionary and prints out some information. + /// Client.Network.CurrentSim.ObjectsPrimitives.ForEach( + /// delegate(Primitive prim) + /// { + /// if (prim.Text != null) + /// { + /// Console.WriteLine("NAME={0} ID = {1} TEXT = '{2}'", + /// prim.PropertiesFamily.Name, prim.ID, prim.Text); + /// } + /// }); + /// + /// + public void ForEach(Action action) + { + lock (Dictionary) + { + foreach (TValue value in Dictionary.Values) + { + action(value); + } + } + } + + /// Perform an on each key of an + /// to perform + public void ForEach(Action action) + { + lock (Dictionary) + { + foreach (TKey key in Dictionary.Keys) + { + action(key); + } + } + } + + /// + /// Perform an on each KeyValuePair of an + /// + /// to perform + public void ForEach(Action> action) + { + lock (Dictionary) + { + foreach (KeyValuePair entry in Dictionary) + { + action(entry); + } + } + } + + /// Check if Key exists in Dictionary + /// Key to check for + /// if found, otherwise + public bool ContainsKey(TKey key) + { + return Dictionary.ContainsKey(key); + } + + /// Check if Value exists in Dictionary + /// Value to check for + /// if found, otherwise + public bool ContainsValue(TValue value) + { + return Dictionary.ContainsValue(value); + } + + /// + /// Adds the specified key to the dictionary, dictionary locking is not performed, + /// + /// + /// The key + /// The value + internal void Add(TKey key, TValue value) + { + lock (Dictionary) + Dictionary.Add(key, value); + } + + /// + /// Removes the specified key, dictionary locking is not performed + /// + /// The key. + /// if successful, otherwise + internal bool Remove(TKey key) + { + lock (Dictionary) + return Dictionary.Remove(key); + } + + /// + /// Indexer for the dictionary + /// + /// The key + /// The value + public TValue this[TKey key] + { + get + { + lock (Dictionary) + return Dictionary[key]; + } + internal set + { + lock (Dictionary) + Dictionary[key] = value; + } + } + } +} diff --git a/OpenMetaverse/Inventory.cs b/OpenMetaverse/Inventory.cs new file mode 100644 index 0000000..4494c92 --- /dev/null +++ b/OpenMetaverse/Inventory.cs @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization; + +namespace OpenMetaverse +{ + /// + /// Exception class to identify inventory exceptions + /// + public class InventoryException : Exception + { + public InventoryException(string message) + : base(message) { } + } + + /// + /// Responsible for maintaining inventory structure. Inventory constructs nodes + /// and manages node children as is necessary to maintain a coherant hirarchy. + /// Other classes should not manipulate or create InventoryNodes explicitly. When + /// A node's parent changes (when a folder is moved, for example) simply pass + /// Inventory the updated InventoryFolder and it will make the appropriate changes + /// to its internal representation. + /// + public class Inventory + { + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectUpdated; + + ///Raises the InventoryObjectUpdated Event + /// A InventoryObjectUpdatedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectUpdated(InventoryObjectUpdatedEventArgs e) + { + EventHandler handler = m_InventoryObjectUpdated; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InventoryObjectUpdatedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler InventoryObjectUpdated + { + add { lock (m_InventoryObjectUpdatedLock) { m_InventoryObjectUpdated += value; } } + remove { lock (m_InventoryObjectUpdatedLock) { m_InventoryObjectUpdated -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectRemoved; + + ///Raises the InventoryObjectRemoved Event + /// A InventoryObjectRemovedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectRemoved(InventoryObjectRemovedEventArgs e) + { + EventHandler handler = m_InventoryObjectRemoved; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InventoryObjectRemovedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler InventoryObjectRemoved + { + add { lock (m_InventoryObjectRemovedLock) { m_InventoryObjectRemoved += value; } } + remove { lock (m_InventoryObjectRemovedLock) { m_InventoryObjectRemoved -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectAdded; + + ///Raises the InventoryObjectAdded Event + /// A InventoryObjectAddedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectAdded(InventoryObjectAddedEventArgs e) + { + EventHandler handler = m_InventoryObjectAdded; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InventoryObjectAddedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler InventoryObjectAdded + { + add { lock (m_InventoryObjectAddedLock) { m_InventoryObjectAdded += value; } } + remove { lock (m_InventoryObjectAddedLock) { m_InventoryObjectAdded -= value; } } + } + + /// + /// The root folder of this avatars inventory + /// + public InventoryFolder RootFolder + { + get { return RootNode.Data as InventoryFolder; } + set + { + UpdateNodeFor(value); + _RootNode = Items[value.UUID]; + } + } + + /// + /// The default shared library folder + /// + public InventoryFolder LibraryFolder + { + get { return LibraryRootNode.Data as InventoryFolder; } + set + { + UpdateNodeFor(value); + _LibraryRootNode = Items[value.UUID]; + } + } + + private InventoryNode _LibraryRootNode; + private InventoryNode _RootNode; + + /// + /// The root node of the avatars inventory + /// + public InventoryNode RootNode + { + get { return _RootNode; } + } + + /// + /// The root node of the default shared library + /// + public InventoryNode LibraryRootNode + { + get { return _LibraryRootNode; } + } + + public UUID Owner { + get { return _Owner; } + } + + private UUID _Owner; + + private GridClient Client; + //private InventoryManager Manager; + public Dictionary Items = new Dictionary(); + + public Inventory(GridClient client, InventoryManager manager) + : this(client, manager, client.Self.AgentID) { } + + public Inventory(GridClient client, InventoryManager manager, UUID owner) + { + Client = client; + //Manager = manager; + _Owner = owner; + if (owner == UUID.Zero) + Logger.Log("Inventory owned by nobody!", Helpers.LogLevel.Warning, Client); + Items = new Dictionary(); + } + + public List GetContents(InventoryFolder folder) + { + return GetContents(folder.UUID); + } + + /// + /// Returns the contents of the specified folder + /// + /// A folder's UUID + /// The contents of the folder corresponding to folder + /// When folder does not exist in the inventory + public List GetContents(UUID folder) + { + InventoryNode folderNode; + if (!Items.TryGetValue(folder, out folderNode)) + throw new InventoryException("Unknown folder: " + folder); + lock (folderNode.Nodes.SyncRoot) + { + List contents = new List(folderNode.Nodes.Count); + foreach (InventoryNode node in folderNode.Nodes.Values) + { + contents.Add(node.Data); + } + return contents; + } + } + + /// + /// Updates the state of the InventoryNode and inventory data structure that + /// is responsible for the InventoryObject. If the item was previously not added to inventory, + /// it adds the item, and updates structure accordingly. If it was, it updates the + /// InventoryNode, changing the parent node if item.parentUUID does + /// not match node.Parent.Data.UUID. + /// + /// You can not set the inventory root folder using this method + /// + /// The InventoryObject to store + public void UpdateNodeFor(InventoryBase item) + { + lock (Items) + { + InventoryNode itemParent = null; + if (item.ParentUUID != UUID.Zero && !Items.TryGetValue(item.ParentUUID, out itemParent)) + { + // OK, we have no data on the parent, let's create a fake one. + InventoryFolder fakeParent = new InventoryFolder(item.ParentUUID); + fakeParent.DescendentCount = 1; // Dear god, please forgive me. + itemParent = new InventoryNode(fakeParent); + Items[item.ParentUUID] = itemParent; + // Unfortunately, this breaks the nice unified tree + // while we're waiting for the parent's data to come in. + // As soon as we get the parent, the tree repairs itself. + //Logger.DebugLog("Attempting to update inventory child of " + + // item.ParentUUID.ToString() + " when we have no local reference to that folder", Client); + + if (Client.Settings.FETCH_MISSING_INVENTORY) + { + // Fetch the parent + List fetchreq = new List(1); + fetchreq.Add(item.ParentUUID); + } + } + + InventoryNode itemNode; + if (Items.TryGetValue(item.UUID, out itemNode)) // We're updating. + { + InventoryNode oldParent = itemNode.Parent; + // Handle parent change + if (oldParent == null || itemParent == null || itemParent.Data.UUID != oldParent.Data.UUID) + { + if (oldParent != null) + { + lock (oldParent.Nodes.SyncRoot) + oldParent.Nodes.Remove(item.UUID); + } + if (itemParent != null) + { + lock (itemParent.Nodes.SyncRoot) + itemParent.Nodes[item.UUID] = itemNode; + } + } + + itemNode.Parent = itemParent; + + if (m_InventoryObjectUpdated != null) + { + OnInventoryObjectUpdated(new InventoryObjectUpdatedEventArgs(itemNode.Data, item)); + } + + itemNode.Data = item; + } + else // We're adding. + { + itemNode = new InventoryNode(item, itemParent); + Items.Add(item.UUID, itemNode); + if (m_InventoryObjectAdded != null) + { + OnInventoryObjectAdded(new InventoryObjectAddedEventArgs(item)); + } + } + } + } + + public InventoryNode GetNodeFor(UUID uuid) + { + return Items[uuid]; + } + + /// + /// Removes the InventoryObject and all related node data from Inventory. + /// + /// The InventoryObject to remove. + public void RemoveNodeFor(InventoryBase item) + { + lock (Items) + { + InventoryNode node; + if (Items.TryGetValue(item.UUID, out node)) + { + if (node.Parent != null) + lock (node.Parent.Nodes.SyncRoot) + node.Parent.Nodes.Remove(item.UUID); + Items.Remove(item.UUID); + if (m_InventoryObjectRemoved != null) + { + OnInventoryObjectRemoved(new InventoryObjectRemovedEventArgs(item)); + } + } + + // In case there's a new parent: + InventoryNode newParent; + if (Items.TryGetValue(item.ParentUUID, out newParent)) + { + lock (newParent.Nodes.SyncRoot) + newParent.Nodes.Remove(item.UUID); + } + } + } + + /// + /// Used to find out if Inventory contains the InventoryObject + /// specified by uuid. + /// + /// The UUID to check. + /// true if inventory contains uuid, false otherwise + public bool Contains(UUID uuid) + { + return Items.ContainsKey(uuid); + } + + public bool Contains(InventoryBase obj) + { + return Contains(obj.UUID); + } + + /// + /// Saves the current inventory structure to a cache file + /// + /// Name of the cache file to save to + public void SaveToDisk(string filename) + { + try + { + using (Stream stream = File.Open(filename, FileMode.Create)) + { + BinaryFormatter bformatter = new BinaryFormatter(); + lock (Items) + { + Logger.Log("Caching " + Items.Count.ToString() + " inventory items to " + filename, Helpers.LogLevel.Info); + foreach (KeyValuePair kvp in Items) + { + bformatter.Serialize(stream, kvp.Value); + } + } + } + } + catch (Exception e) + { + Logger.Log("Error saving inventory cache to disk :"+e.Message,Helpers.LogLevel.Error); + } + } + + /// + /// Loads in inventory cache file into the inventory structure. Note only valid to call after login has been successful. + /// + /// Name of the cache file to load + /// The number of inventory items sucessfully reconstructed into the inventory node tree + public int RestoreFromDisk(string filename) + { + List nodes = new List(); + int item_count = 0; + + try + { + if (!File.Exists(filename)) + return -1; + + using (Stream stream = File.Open(filename, FileMode.Open)) + { + BinaryFormatter bformatter = new BinaryFormatter(); + + while (stream.Position < stream.Length) + { + OpenMetaverse.InventoryNode node = (InventoryNode)bformatter.Deserialize(stream); + nodes.Add(node); + item_count++; + } + } + } + catch (Exception e) + { + Logger.Log("Error accessing inventory cache file :" + e.Message, Helpers.LogLevel.Error); + return -1; + } + + Logger.Log("Read " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); + + item_count = 0; + List del_nodes = new List(); //nodes that we have processed and will delete + List dirty_folders = new List(); // Tainted folders that we will not restore items into + + // Because we could get child nodes before parents we must itterate around and only add nodes who have + // a parent already in the list because we must update both child and parent to link together + // But sometimes we have seen orphin nodes due to bad/incomplete data when caching so we have an emergency abort route + int stuck = 0; + + while (nodes.Count != 0 && stuck<5) + { + foreach (InventoryNode node in nodes) + { + InventoryNode pnode; + if (node.ParentID == UUID.Zero) + { + //We don't need the root nodes "My Inventory" etc as they will already exist for the correct + // user of this cache. + del_nodes.Add(node); + item_count--; + } + else if(Items.TryGetValue(node.Data.UUID,out pnode)) + { + //We already have this it must be a folder + if (node.Data is InventoryFolder) + { + InventoryFolder cache_folder = (InventoryFolder)node.Data; + InventoryFolder server_folder = (InventoryFolder)pnode.Data; + + if (cache_folder.Version != server_folder.Version) + { + Logger.DebugLog("Inventory Cache/Server version mismatch on " + node.Data.Name + " " + cache_folder.Version.ToString() + " vs " + server_folder.Version.ToString()); + pnode.NeedsUpdate = true; + dirty_folders.Add(node.Data.UUID); + } + else + { + pnode.NeedsUpdate = false; + } + + del_nodes.Add(node); + } + } + else if (Items.TryGetValue(node.ParentID, out pnode)) + { + if (node.Data != null) + { + // If node is folder, and it does not exist in skeleton, mark it as + // dirty and don't process nodes that belong to it + if (node.Data is InventoryFolder && !(Items.ContainsKey(node.Data.UUID))) + { + dirty_folders.Add(node.Data.UUID); + } + + //Only add new items, this is most likely to be run at login time before any inventory + //nodes other than the root are populated. Don't add non existing folders. + if (!Items.ContainsKey(node.Data.UUID) && !dirty_folders.Contains(pnode.Data.UUID) && !(node.Data is InventoryFolder)) + { + Items.Add(node.Data.UUID, node); + node.Parent = pnode; //Update this node with its parent + pnode.Nodes.Add(node.Data.UUID, node); // Add to the parents child list + item_count++; + } + } + + del_nodes.Add(node); + } + } + + if (del_nodes.Count == 0) + stuck++; + else + stuck = 0; + + //Clean up processed nodes this loop around. + foreach (InventoryNode node in del_nodes) + nodes.Remove(node); + + del_nodes.Clear(); + } + + Logger.Log("Reassembled " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); + return item_count; + } + + #region Operators + + /// + /// By using the bracket operator on this class, the program can get the + /// InventoryObject designated by the specified uuid. If the value for the corresponding + /// UUID is null, the call is equivelant to a call to RemoveNodeFor(this[uuid]). + /// If the value is non-null, it is equivelant to a call to UpdateNodeFor(value), + /// the uuid parameter is ignored. + /// + /// The UUID of the InventoryObject to get or set, ignored if set to non-null value. + /// The InventoryObject corresponding to uuid. + public InventoryBase this[UUID uuid] + { + get + { + InventoryNode node = Items[uuid]; + return node.Data; + } + set + { + if (value != null) + { + // Log a warning if there is a UUID mismatch, this will cause problems + if (value.UUID != uuid) + Logger.Log("Inventory[uuid]: uuid " + uuid.ToString() + " is not equal to value.UUID " + + value.UUID.ToString(), Helpers.LogLevel.Warning, Client); + + UpdateNodeFor(value); + } + else + { + InventoryNode node; + if (Items.TryGetValue(uuid, out node)) + { + RemoveNodeFor(node.Data); + } + } + } + } + + #endregion Operators + + } + #region EventArgs classes + + public class InventoryObjectUpdatedEventArgs : EventArgs + { + private readonly InventoryBase m_OldObject; + private readonly InventoryBase m_NewObject; + + public InventoryBase OldObject { get { return m_OldObject; } } + public InventoryBase NewObject { get { return m_NewObject; } } + + public InventoryObjectUpdatedEventArgs(InventoryBase oldObject, InventoryBase newObject) + { + this.m_OldObject = oldObject; + this.m_NewObject = newObject; + } + } + + public class InventoryObjectRemovedEventArgs : EventArgs + { + private readonly InventoryBase m_Obj; + + public InventoryBase Obj { get { return m_Obj; } } + public InventoryObjectRemovedEventArgs(InventoryBase obj) + { + this.m_Obj = obj; + } + } + + public class InventoryObjectAddedEventArgs : EventArgs + { + private readonly InventoryBase m_Obj; + + public InventoryBase Obj { get { return m_Obj; } } + + public InventoryObjectAddedEventArgs(InventoryBase obj) + { + this.m_Obj = obj; + } + } + #endregion EventArgs +} diff --git a/OpenMetaverse/InventoryManager.cs b/OpenMetaverse/InventoryManager.cs new file mode 100644 index 0000000..91690cc --- /dev/null +++ b/OpenMetaverse/InventoryManager.cs @@ -0,0 +1,5005 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Text.RegularExpressions; +using System.Threading; +using System.Text; +using System.Runtime.Serialization; +using OpenMetaverse.Http; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + #region Enums + + [Flags] + public enum InventorySortOrder : int + { + /// Sort by name + ByName = 0, + /// Sort by date + ByDate = 1, + /// Sort folders by name, regardless of whether items are + /// sorted by name or date + FoldersByName = 2, + /// Place system folders at the top + SystemFoldersToTop = 4 + } + + /// + /// Possible destinations for DeRezObject request + /// + public enum DeRezDestination : byte + { + /// + AgentInventorySave = 0, + /// Copy from in-world to agent inventory + AgentInventoryCopy = 1, + /// Derez to TaskInventory + TaskInventory = 2, + /// + Attachment = 3, + /// Take Object + AgentInventoryTake = 4, + /// + ForceToGodInventory = 5, + /// Delete Object + TrashFolder = 6, + /// Put an avatar attachment into agent inventory + AttachmentToInventory = 7, + /// + AttachmentExists = 8, + /// Return an object back to the owner's inventory + ReturnToOwner = 9, + /// Return a deeded object back to the last owner's inventory + ReturnToLastOwner = 10 + } + + /// + /// Upper half of the Flags field for inventory items + /// + [Flags] + public enum InventoryItemFlags : uint + { + None = 0, + /// Indicates that the NextOwner permission will be set to the + /// most restrictive set of permissions found in the object set + /// (including linkset items and object inventory items) on next rez + ObjectSlamPerm = 0x100, + /// Indicates that the object sale information has been + /// changed + ObjectSlamSale = 0x1000, + /// If set, and a slam bit is set, indicates BaseMask will be overwritten on Rez + ObjectOverwriteBase = 0x010000, + /// If set, and a slam bit is set, indicates OwnerMask will be overwritten on Rez + ObjectOverwriteOwner = 0x020000, + /// If set, and a slam bit is set, indicates GroupMask will be overwritten on Rez + ObjectOverwriteGroup = 0x040000, + /// If set, and a slam bit is set, indicates EveryoneMask will be overwritten on Rez + ObjectOverwriteEveryone = 0x080000, + /// If set, and a slam bit is set, indicates NextOwnerMask will be overwritten on Rez + ObjectOverwriteNextOwner = 0x100000, + /// Indicates whether this object is composed of multiple + /// items or not + ObjectHasMultipleItems = 0x200000, + /// Indicates that the asset is only referenced by this + /// inventory item. If this item is deleted or updated to reference a + /// new assetID, the asset can be deleted + SharedSingleReference = 0x40000000, + } + + #endregion Enums + + #region Inventory Object Classes + + /// + /// Base Class for Inventory Items + /// + [Serializable()] + public abstract class InventoryBase : ISerializable + { + /// of item/folder + public UUID UUID; + /// of parent folder + public UUID ParentUUID; + /// Name of item/folder + public string Name; + /// Item/Folder Owners + public UUID OwnerID; + + /// + /// Constructor, takes an itemID as a parameter + /// + /// The of the item + public InventoryBase(UUID itemID) + { + if (itemID == UUID.Zero) + Logger.Log("Initializing an InventoryBase with UUID.Zero", Helpers.LogLevel.Warning); + UUID = itemID; + } + + /// + /// + /// + /// + public virtual void GetObjectData(SerializationInfo info, StreamingContext ctxt) + { + info.AddValue("UUID", UUID); + info.AddValue("ParentUUID", ParentUUID); + info.AddValue("Name", Name); + info.AddValue("OwnerID", OwnerID); + } + + /// + /// + /// + /// + public InventoryBase(SerializationInfo info, StreamingContext ctxt) + { + UUID = (UUID)info.GetValue("UUID", typeof(UUID)); + ParentUUID = (UUID)info.GetValue("ParentUUID", typeof(UUID)); + Name = (string)info.GetValue("Name", typeof(string)); + OwnerID = (UUID)info.GetValue("OwnerID", typeof(UUID)); + } + + /// + /// Generates a number corresponding to the value of the object to support the use of a hash table, + /// suitable for use in hashing algorithms and data structures such as a hash table + /// + /// A Hashcode of all the combined InventoryBase fields + public override int GetHashCode() + { + return UUID.GetHashCode() ^ ParentUUID.GetHashCode() ^ Name.GetHashCode() ^ OwnerID.GetHashCode(); + } + + /// + /// Determine whether the specified object is equal to the current object + /// + /// InventoryBase object to compare against + /// true if objects are the same + public override bool Equals(object o) + { + InventoryBase inv = o as InventoryBase; + return inv != null && Equals(inv); + } + + /// + /// Determine whether the specified object is equal to the current object + /// + /// InventoryBase object to compare against + /// true if objects are the same + public virtual bool Equals(InventoryBase o) + { + return o.UUID == UUID + && o.ParentUUID == ParentUUID + && o.Name == Name + && o.OwnerID == OwnerID; + } + + /// + /// Convert inventory to OSD + /// + /// OSD representation + public abstract OSD GetOSD(); + } + + /// + /// An Item in Inventory + /// + [Serializable()] + public class InventoryItem : InventoryBase + { + public override string ToString() + { + return AssetType + " " + AssetUUID + " (" + InventoryType + " " + UUID + ") '" + Name + "'/'" + + Description + "' " + Permissions; + } + /// The of this item + public UUID AssetUUID; + /// The combined of this item + public Permissions Permissions; + /// The type of item from + public AssetType AssetType; + /// The type of item from the enum + public InventoryType InventoryType; + /// The of the creator of this item + public UUID CreatorID; + /// A Description of this item + public string Description; + /// The s this item is set to or owned by + public UUID GroupID; + /// If true, item is owned by a group + public bool GroupOwned; + /// The price this item can be purchased for + public int SalePrice; + /// The type of sale from the enum + public SaleType SaleType; + /// Combined flags from + public uint Flags; + /// Time and date this inventory item was created, stored as + /// UTC (Coordinated Universal Time) + public DateTime CreationDate; + /// Used to update the AssetID in requests sent to the server + public UUID TransactionID; + /// The of the previous owner of the item + public UUID LastOwnerID; + + /// + /// Construct a new InventoryItem object + /// + /// The of the item + public InventoryItem(UUID itemID) + : base(itemID) { } + + /// + /// Construct a new InventoryItem object of a specific Type + /// + /// The type of item from + /// of the item + public InventoryItem(InventoryType type, UUID itemID) : base(itemID) { InventoryType = type; } + + /// + /// Indicates inventory item is a link + /// + /// True if inventory item is a link to another inventory item + public bool IsLink() + { + return AssetType == AssetType.Link || AssetType == AssetType.LinkFolder; + } + + /// + /// + /// + /// + override public void GetObjectData(SerializationInfo info, StreamingContext ctxt) + { + base.GetObjectData(info, ctxt); + info.AddValue("AssetUUID", AssetUUID, typeof(UUID)); + info.AddValue("Permissions", Permissions, typeof(Permissions)); + info.AddValue("AssetType", AssetType); + info.AddValue("InventoryType", InventoryType); + info.AddValue("CreatorID", CreatorID); + info.AddValue("Description", Description); + info.AddValue("GroupID", GroupID); + info.AddValue("GroupOwned", GroupOwned); + info.AddValue("SalePrice", SalePrice); + info.AddValue("SaleType", SaleType); + info.AddValue("Flags", Flags); + info.AddValue("CreationDate", CreationDate); + info.AddValue("LastOwnerID", LastOwnerID); + } + + /// + /// + /// + /// + public InventoryItem(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + AssetUUID = (UUID)info.GetValue("AssetUUID", typeof(UUID)); + Permissions = (Permissions)info.GetValue("Permissions", typeof(Permissions)); + AssetType = (AssetType)info.GetValue("AssetType", typeof(AssetType)); + InventoryType = (InventoryType)info.GetValue("InventoryType", typeof(InventoryType)); + CreatorID = (UUID)info.GetValue("CreatorID", typeof(UUID)); + Description = (string)info.GetValue("Description", typeof(string)); + GroupID = (UUID)info.GetValue("GroupID", typeof(UUID)); + GroupOwned = (bool)info.GetValue("GroupOwned", typeof(bool)); + SalePrice = (int)info.GetValue("SalePrice", typeof(int)); + SaleType = (SaleType)info.GetValue("SaleType", typeof(SaleType)); + Flags = (uint)info.GetValue("Flags", typeof(uint)); + CreationDate = (DateTime)info.GetValue("CreationDate", typeof(DateTime)); + LastOwnerID = (UUID)info.GetValue("LastOwnerID", typeof(UUID)); + } + + /// + /// Generates a number corresponding to the value of the object to support the use of a hash table. + /// Suitable for use in hashing algorithms and data structures such as a hash table + /// + /// A Hashcode of all the combined InventoryItem fields + public override int GetHashCode() + { + return AssetUUID.GetHashCode() ^ Permissions.GetHashCode() ^ AssetType.GetHashCode() ^ + InventoryType.GetHashCode() ^ Description.GetHashCode() ^ GroupID.GetHashCode() ^ + GroupOwned.GetHashCode() ^ SalePrice.GetHashCode() ^ SaleType.GetHashCode() ^ + Flags.GetHashCode() ^ CreationDate.GetHashCode() ^ LastOwnerID.GetHashCode(); + } + + /// + /// Compares an object + /// + /// The object to compare + /// true if comparison object matches + public override bool Equals(object o) + { + InventoryItem item = o as InventoryItem; + return item != null && Equals(item); + } + + /// + /// Determine whether the specified object is equal to the current object + /// + /// The object to compare against + /// true if objects are the same + public override bool Equals(InventoryBase o) + { + InventoryItem item = o as InventoryItem; + return item != null && Equals(item); + } + + /// + /// Determine whether the specified object is equal to the current object + /// + /// The object to compare against + /// true if objects are the same + public bool Equals(InventoryItem o) + { + return base.Equals(o as InventoryBase) + && o.AssetType == AssetType + && o.AssetUUID == AssetUUID + && o.CreationDate == CreationDate + && o.Description == Description + && o.Flags == Flags + && o.GroupID == GroupID + && o.GroupOwned == GroupOwned + && o.InventoryType == InventoryType + && o.Permissions.Equals(Permissions) + && o.SalePrice == SalePrice + && o.SaleType == SaleType + && o.LastOwnerID == LastOwnerID; + } + + /// + /// Create InventoryItem from OSD + /// + /// OSD Data that makes up InventoryItem + /// Inventory item created + public static InventoryItem FromOSD(OSD data) + { + OSDMap descItem = (OSDMap)data; + + InventoryType type = (InventoryType)descItem["inv_type"].AsInteger(); + if (type == InventoryType.Texture && (AssetType)descItem["type"].AsInteger() == AssetType.Object) + { + type = InventoryType.Attachment; + } + InventoryItem item = InventoryManager.CreateInventoryItem(type, descItem["item_id"]); + + item.ParentUUID = descItem["parent_id"]; + item.Name = descItem["name"]; + item.Description = descItem["desc"]; + item.OwnerID = descItem["agent_id"]; + item.ParentUUID = descItem["parent_id"]; + item.AssetUUID = descItem["asset_id"]; + item.AssetType = (AssetType)descItem["type"].AsInteger(); + item.CreationDate = Utils.UnixTimeToDateTime(descItem["created_at"]); + item.Flags = descItem["flags"]; + + OSDMap perms = (OSDMap)descItem["permissions"]; + item.CreatorID = perms["creator_id"]; + item.LastOwnerID = perms["last_owner_id"]; + item.Permissions = new Permissions(perms["base_mask"], perms["everyone_mask"], perms["group_mask"], perms["next_owner_mask"], perms["owner_mask"]); + item.GroupOwned = perms["is_owner_group"]; + item.GroupID = perms["group_id"]; + + OSDMap sale = (OSDMap)descItem["sale_info"]; + item.SalePrice = sale["sale_price"]; + item.SaleType = (SaleType)sale["sale_type"].AsInteger(); + + return item; + } + + /// + /// Convert InventoryItem to OSD + /// + /// OSD representation of InventoryItem + public override OSD GetOSD() + { + OSDMap map = new OSDMap(); + map["inv_type"] = (int)InventoryType; + map["parent_id"] = ParentUUID; + map["name"] = Name; + map["desc"] = Description; + map["agent_id"] = OwnerID; + map["parent_id"] = ParentUUID; + map["asset_id"] = AssetUUID; + map["type"] = (int)AssetType; + map["created_at"] = CreationDate; + map["flags"] = Flags; + + OSDMap perms = (OSDMap)Permissions.GetOSD(); + perms["creator_id"] = CreatorID; + perms["last_owner_id"] = LastOwnerID; + perms["is_owner_group"] = GroupOwned; + perms["group_id"] = GroupID; + map["permissions"] = perms; + + OSDMap sale = new OSDMap(); + sale["sale_price"] = SalePrice; + sale["sale_type"] = (int)SaleType; + map["sale_info"] = sale; + + return map; + } + } + + /// + /// InventoryTexture Class representing a graphical image + /// + /// + [Serializable()] + public class InventoryTexture : InventoryItem + { + /// + /// Construct an InventoryTexture object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryTexture(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Texture; + } + + /// + /// Construct an InventoryTexture object from a serialization stream + /// + public InventoryTexture(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Texture; + } + } + + /// + /// InventorySound Class representing a playable sound + /// + [Serializable()] + public class InventorySound : InventoryItem + { + /// + /// Construct an InventorySound object + /// + /// A which becomes the + /// objects AssetUUID + public InventorySound(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Sound; + } + + /// + /// Construct an InventorySound object from a serialization stream + /// + public InventorySound(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Sound; + } + } + + /// + /// InventoryCallingCard Class, contains information on another avatar + /// + [Serializable()] + public class InventoryCallingCard : InventoryItem + { + /// + /// Construct an InventoryCallingCard object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryCallingCard(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.CallingCard; + } + + /// + /// Construct an InventoryCallingCard object from a serialization stream + /// + public InventoryCallingCard(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.CallingCard; + } + } + + /// + /// InventoryLandmark Class, contains details on a specific location + /// + [Serializable()] + public class InventoryLandmark : InventoryItem + { + /// + /// Construct an InventoryLandmark object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryLandmark(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Landmark; + } + + /// + /// Construct an InventoryLandmark object from a serialization stream + /// + public InventoryLandmark(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Landmark; + + } + + /// + /// Landmarks use the InventoryItemFlags struct and will have a flag of 1 set if they have been visited + /// + public bool LandmarkVisited + { + get { return (Flags & 1) != 0; } + set + { + if (value) Flags |= 1; + else Flags &= ~1u; + } + } + } + + /// + /// InventoryObject Class contains details on a primitive or coalesced set of primitives + /// + [Serializable()] + public class InventoryObject : InventoryItem + { + /// + /// Construct an InventoryObject object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryObject(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Object; + } + + /// + /// Construct an InventoryObject object from a serialization stream + /// + public InventoryObject(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Object; + } + + /// + /// Gets or sets the upper byte of the Flags value + /// + public InventoryItemFlags ItemFlags + { + get { return (InventoryItemFlags)(Flags & ~0xFF); } + set { Flags = (uint)value | (Flags & 0xFF); } + } + + /// + /// Gets or sets the object attachment point, the lower byte of the Flags value + /// + public AttachmentPoint AttachPoint + { + get { return (AttachmentPoint)(Flags & 0xFF); } + set { Flags = (uint)value | (Flags & 0xFFFFFF00); } + } + } + + /// + /// InventoryNotecard Class, contains details on an encoded text document + /// + [Serializable()] + public class InventoryNotecard : InventoryItem + { + /// + /// Construct an InventoryNotecard object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryNotecard(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Notecard; + } + + /// + /// Construct an InventoryNotecard object from a serialization stream + /// + public InventoryNotecard(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Notecard; + } + } + + /// + /// InventoryCategory Class + /// + /// TODO: Is this even used for anything? + [Serializable()] + public class InventoryCategory : InventoryItem + { + /// + /// Construct an InventoryCategory object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryCategory(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Category; + } + + /// + /// Construct an InventoryCategory object from a serialization stream + /// + public InventoryCategory(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Category; + } + } + + /// + /// InventoryLSL Class, represents a Linden Scripting Language object + /// + [Serializable()] + public class InventoryLSL : InventoryItem + { + /// + /// Construct an InventoryLSL object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryLSL(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.LSL; + } + + /// + /// Construct an InventoryLSL object from a serialization stream + /// + public InventoryLSL(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.LSL; + } + } + + /// + /// InventorySnapshot Class, an image taken with the viewer + /// + [Serializable()] + public class InventorySnapshot : InventoryItem + { + /// + /// Construct an InventorySnapshot object + /// + /// A which becomes the + /// objects AssetUUID + public InventorySnapshot(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Snapshot; + } + + /// + /// Construct an InventorySnapshot object from a serialization stream + /// + public InventorySnapshot(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Snapshot; + } + } + + /// + /// InventoryAttachment Class, contains details on an attachable object + /// + [Serializable()] + public class InventoryAttachment : InventoryItem + { + /// + /// Construct an InventoryAttachment object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryAttachment(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Attachment; + } + + /// + /// Construct an InventoryAttachment object from a serialization stream + /// + public InventoryAttachment(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Attachment; + } + + /// + /// Get the last AttachmentPoint this object was attached to + /// + public AttachmentPoint AttachmentPoint + { + get { return (AttachmentPoint)Flags; } + set { Flags = (uint)value; } + } + } + + /// + /// InventoryWearable Class, details on a clothing item or body part + /// + [Serializable()] + public class InventoryWearable : InventoryItem + { + /// + /// Construct an InventoryWearable object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryWearable(UUID itemID) : base(itemID) { InventoryType = InventoryType.Wearable; } + + /// + /// Construct an InventoryWearable object from a serialization stream + /// + public InventoryWearable(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Wearable; + } + + /// + /// The , Skin, Shape, Skirt, Etc + /// + public WearableType WearableType + { + get { return (WearableType)Flags; } + set { Flags = (uint)value; } + } + } + + /// + /// InventoryAnimation Class, A bvh encoded object which animates an avatar + /// + [Serializable()] + public class InventoryAnimation : InventoryItem + { + /// + /// Construct an InventoryAnimation object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryAnimation(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Animation; + } + + /// + /// Construct an InventoryAnimation object from a serialization stream + /// + public InventoryAnimation(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Animation; + } + + + } + + /// + /// InventoryGesture Class, details on a series of animations, sounds, and actions + /// + [Serializable()] + public class InventoryGesture : InventoryItem + { + /// + /// Construct an InventoryGesture object + /// + /// A which becomes the + /// objects AssetUUID + public InventoryGesture(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Gesture; + } + + /// + /// Construct an InventoryGesture object from a serialization stream + /// + public InventoryGesture(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + InventoryType = InventoryType.Gesture; + } + } + + /// + /// A folder contains s and has certain attributes specific + /// to itself + /// + [Serializable()] + public class InventoryFolder : InventoryBase + { + /// The Preferred for a folder. + public AssetType PreferredType; + /// The Version of this folder + public int Version; + /// Number of child items this folder contains. + public int DescendentCount; + + /// + /// Constructor + /// + /// UUID of the folder + public InventoryFolder(UUID itemID) + : base(itemID) + { + PreferredType = AssetType.Unknown; + Version = 1; + DescendentCount = 0; + } + + /// + /// + /// + /// + public override string ToString() + { + return Name; + } + + /// + /// Get Serilization data for this InventoryFolder object + /// + override public void GetObjectData(SerializationInfo info, StreamingContext ctxt) + { + base.GetObjectData(info, ctxt); + info.AddValue("PreferredType", PreferredType, typeof(AssetType)); + info.AddValue("Version", Version); + info.AddValue("DescendentCount", DescendentCount); + } + + /// + /// Construct an InventoryFolder object from a serialization stream + /// + public InventoryFolder(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) + { + PreferredType = (AssetType)info.GetValue("PreferredType", typeof(AssetType)); + Version = (int)info.GetValue("Version", typeof(int)); + DescendentCount = (int)info.GetValue("DescendentCount", typeof(int)); + } + + /// + /// + /// + /// + public override int GetHashCode() + { + return PreferredType.GetHashCode() ^ Version.GetHashCode() ^ DescendentCount.GetHashCode(); + } + + /// + /// + /// + /// + /// + public override bool Equals(object o) + { + InventoryFolder folder = o as InventoryFolder; + return folder != null && Equals(folder); + } + + /// + /// + /// + /// + /// + public override bool Equals(InventoryBase o) + { + InventoryFolder folder = o as InventoryFolder; + return folder != null && Equals(folder); + } + + /// + /// + /// + /// + /// + public bool Equals(InventoryFolder o) + { + return base.Equals(o as InventoryBase) + && o.DescendentCount == DescendentCount + && o.PreferredType == PreferredType + && o.Version == Version; + } + + /// + /// Create InventoryFolder from OSD + /// + /// OSD Data that makes up InventoryFolder + /// Inventory folder created + public static InventoryFolder FromOSD(OSD data) + { + OSDMap res = (OSDMap)data; + UUID folderID = res.ContainsKey("category_id") ? res["category_id"] : res["folder_id"]; + InventoryFolder folder = new InventoryFolder(folderID); + folder.Name = res["name"]; + folder.DescendentCount = res["descendents"]; + folder.Version = res["version"]; + folder.OwnerID = res.ContainsKey("agent_id") ? res["agent_id"] : res["owner_id"]; + folder.ParentUUID = res["parent_id"]; + folder.PreferredType = (AssetType)(int)res["type_default"]; + return folder; + } + + /// + /// Convert InventoryItem to OSD + /// + /// OSD representation of InventoryItem + public override OSD GetOSD() + { + OSDMap res = new OSDMap(4); + res["name"] = Name; + res["type_default"] = (int)PreferredType; + res["folder_id"] = UUID; + res["descendents"] = DescendentCount; + res["version"] = Version; + res["owner_id"] = OwnerID; + res["parent_id"] = ParentUUID; + return res; + } + + } + + #endregion Inventory Object Classes + + /// + /// Tools for dealing with agents inventory + /// + [Serializable()] + public class InventoryManager + { + /// Used for converting shadow_id to asset_id + public static readonly UUID MAGIC_ID = new UUID("3c115e51-04f4-523c-9fa6-98aff1034730"); + + protected struct InventorySearch + { + public UUID Folder; + public UUID Owner; + public string[] Path; + public int Level; + } + + #region Delegates + + /// + /// Callback for inventory item creation finishing + /// + /// Whether the request to create an inventory + /// item succeeded or not + /// Inventory item being created. If success is + /// false this will be null + public delegate void ItemCreatedCallback(bool success, InventoryItem item); + + /// + /// Callback for an inventory item being create from an uploaded asset + /// + /// true if inventory item creation was successful + /// + /// + /// + public delegate void ItemCreatedFromAssetCallback(bool success, string status, UUID itemID, UUID assetID); + + /// + /// + /// + /// + public delegate void ItemCopiedCallback(InventoryBase item); + + /// The event subscribers, null of no subscribers + private EventHandler m_ItemReceived; + + ///Raises the ItemReceived Event + /// A ItemReceivedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnItemReceived(ItemReceivedEventArgs e) + { + EventHandler handler = m_ItemReceived; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ItemReceivedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler ItemReceived + { + add { lock (m_ItemReceivedLock) { m_ItemReceived += value; } } + remove { lock (m_ItemReceivedLock) { m_ItemReceived -= value; } } + } + + + /// The event subscribers, null of no subscribers + private EventHandler m_FolderUpdated; + + ///Raises the FolderUpdated Event + /// A FolderUpdatedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnFolderUpdated(FolderUpdatedEventArgs e) + { + EventHandler handler = m_FolderUpdated; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FolderUpdatedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler FolderUpdated + { + add { lock (m_FolderUpdatedLock) { m_FolderUpdated += value; } } + remove { lock (m_FolderUpdatedLock) { m_FolderUpdated -= value; } } + } + + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectOffered; + + ///Raises the InventoryObjectOffered Event + /// A InventoryObjectOfferedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectOffered(InventoryObjectOfferedEventArgs e) + { + EventHandler handler = m_InventoryObjectOffered; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InventoryObjectOfferedLock = new object(); + + /// Raised when the simulator sends us data containing + /// an inventory object sent by another avatar or primitive + public event EventHandler InventoryObjectOffered + { + add { lock (m_InventoryObjectOfferedLock) { m_InventoryObjectOffered += value; } } + remove { lock (m_InventoryObjectOfferedLock) { m_InventoryObjectOffered -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_TaskItemReceived; + + ///Raises the TaskItemReceived Event + /// A TaskItemReceivedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnTaskItemReceived(TaskItemReceivedEventArgs e) + { + EventHandler handler = m_TaskItemReceived; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TaskItemReceivedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler TaskItemReceived + { + add { lock (m_TaskItemReceivedLock) { m_TaskItemReceived += value; } } + remove { lock (m_TaskItemReceivedLock) { m_TaskItemReceived -= value; } } + } + + + /// The event subscribers, null of no subscribers + private EventHandler m_FindObjectByPathReply; + + ///Raises the FindObjectByPath Event + /// A FindObjectByPathEventArgs object containing + /// the data sent from the simulator + protected virtual void OnFindObjectByPathReply(FindObjectByPathReplyEventArgs e) + { + EventHandler handler = m_FindObjectByPathReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FindObjectByPathReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler FindObjectByPathReply + { + add { lock (m_FindObjectByPathReplyLock) { m_FindObjectByPathReply += value; } } + remove { lock (m_FindObjectByPathReplyLock) { m_FindObjectByPathReply -= value; } } + } + + + /// The event subscribers, null of no subscribers + private EventHandler m_TaskInventoryReply; + + ///Raises the TaskInventoryReply Event + /// A TaskInventoryReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnTaskInventoryReply(TaskInventoryReplyEventArgs e) + { + EventHandler handler = m_TaskInventoryReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TaskInventoryReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler TaskInventoryReply + { + add { lock (m_TaskInventoryReplyLock) { m_TaskInventoryReply += value; } } + remove { lock (m_TaskInventoryReplyLock) { m_TaskInventoryReply -= value; } } + } + + /// + /// Reply received when uploading an inventory asset + /// + /// Has upload been successful + /// Error message if upload failed + /// Inventory asset UUID + /// New asset UUID + public delegate void InventoryUploadedAssetCallback(bool success, string status, UUID itemID, UUID assetID); + + + /// The event subscribers, null of no subscribers + private EventHandler m_SaveAssetToInventory; + + ///Raises the SaveAssetToInventory Event + /// A SaveAssetToInventoryEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSaveAssetToInventory(SaveAssetToInventoryEventArgs e) + { + EventHandler handler = m_SaveAssetToInventory; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SaveAssetToInventoryLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler SaveAssetToInventory + { + add { lock (m_SaveAssetToInventoryLock) { m_SaveAssetToInventory += value; } } + remove { lock (m_SaveAssetToInventoryLock) { m_SaveAssetToInventory -= value; } } + } + + /// + /// Delegate that is invoked when script upload is completed + /// + /// Has upload succeded (note, there still might be compile errors) + /// Upload status message + /// Is compilation successful + /// If compilation failed, list of error messages, null on compilation success + /// Script inventory UUID + /// Script's new asset UUID + public delegate void ScriptUpdatedCallback(bool uploadSuccess, string uploadStatus, bool compileSuccess, List compileMessages, UUID itemID, UUID assetID); + + /// The event subscribers, null of no subscribers + private EventHandler m_ScriptRunningReply; + + ///Raises the ScriptRunningReply Event + /// A ScriptRunningReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnScriptRunningReply(ScriptRunningReplyEventArgs e) + { + EventHandler handler = m_ScriptRunningReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ScriptRunningReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler ScriptRunningReply + { + add { lock (m_ScriptRunningReplyLock) { m_ScriptRunningReply += value; } } + remove { lock (m_ScriptRunningReplyLock) { m_ScriptRunningReply -= value; } } + } + #endregion Delegates + + #region String Arrays + + /// Partial mapping of AssetTypes to folder names + private static readonly string[] _NewFolderNames = new string[] + { + "Textures", + "Sounds", + "Calling Cards", + "Landmarks", + "Scripts", + "Clothing", + "Objects", + "Notecards", + "New Folder", + "Inventory", + "Scripts", + "Scripts", + "Uncompressed Images", + "Body Parts", + "Trash", + "Photo Album", + "Lost And Found", + "Uncompressed Sounds", + "Uncompressed Images", + "Uncompressed Images", + "Animations", + "Gestures" + }; + + #endregion String Arrays + + private GridClient Client; + private Inventory _Store; + //private Random _RandNumbers = new Random(); + private object _CallbacksLock = new object(); + private uint _CallbackPos; + private Dictionary _ItemCreatedCallbacks = new Dictionary(); + private Dictionary _ItemCopiedCallbacks = new Dictionary(); + private Dictionary _ItemInventoryTypeRequest = new Dictionary(); + private List _Searches = new List(); + + #region Properties + + /// + /// Get this agents Inventory data + /// + public Inventory Store { get { return _Store; } } + + #endregion Properties + + /// + /// Default constructor + /// + /// Reference to the GridClient object + public InventoryManager(GridClient client) + { + Client = client; + + Client.Network.RegisterCallback(PacketType.UpdateCreateInventoryItem, UpdateCreateInventoryItemHandler); + Client.Network.RegisterCallback(PacketType.SaveAssetIntoInventory, SaveAssetIntoInventoryHandler); + Client.Network.RegisterCallback(PacketType.BulkUpdateInventory, BulkUpdateInventoryHandler); + Client.Network.RegisterEventCallback("BulkUpdateInventory", new Caps.EventQueueCallback(BulkUpdateInventoryCapHandler)); + Client.Network.RegisterCallback(PacketType.MoveInventoryItem, MoveInventoryItemHandler); + Client.Network.RegisterCallback(PacketType.InventoryDescendents, InventoryDescendentsHandler); + Client.Network.RegisterCallback(PacketType.FetchInventoryReply, FetchInventoryReplyHandler); + Client.Network.RegisterCallback(PacketType.ReplyTaskInventory, ReplyTaskInventoryHandler); + Client.Network.RegisterEventCallback("ScriptRunningReply", new Caps.EventQueueCallback(ScriptRunningReplyMessageHandler)); + + // Watch for inventory given to us through instant message + Client.Self.IM += Self_IM; + + // Register extra parameters with login and parse the inventory data that comes back + Client.Network.RegisterLoginResponseCallback( + new NetworkManager.LoginResponseCallback(Network_OnLoginResponse), + new string[] { + "inventory-root", "inventory-skeleton", "inventory-lib-root", + "inventory-lib-owner", "inventory-skel-lib"}); + } + + + #region Fetch + + /// + /// Fetch an inventory item from the dataserver + /// + /// The items + /// The item Owners + /// a integer representing the number of milliseconds to wait for results + /// An object on success, or null if no item was found + /// Items will also be sent to the event + public InventoryItem FetchItem(UUID itemID, UUID ownerID, int timeoutMS) + { + AutoResetEvent fetchEvent = new AutoResetEvent(false); + InventoryItem fetchedItem = null; + + EventHandler callback = + delegate(object sender, ItemReceivedEventArgs e) + { + if (e.Item.UUID == itemID) + { + fetchedItem = e.Item; + fetchEvent.Set(); + } + }; + + ItemReceived += callback; + RequestFetchInventory(itemID, ownerID); + + fetchEvent.WaitOne(timeoutMS, false); + ItemReceived -= callback; + + return fetchedItem; + } + + /// + /// Request A single inventory item + /// + /// The items + /// The item Owners + /// + public void RequestFetchInventory(UUID itemID, UUID ownerID) + { + RequestFetchInventory(new List(1) { itemID }, new List(1) { ownerID }); + } + + /// + /// Request inventory items + /// + /// Inventory items to request + /// Owners of the inventory items + /// + public void RequestFetchInventory(List itemIDs, List ownerIDs) + { + if (itemIDs.Count != ownerIDs.Count) + throw new ArgumentException("itemIDs and ownerIDs must contain the same number of entries"); + + if (Client.Settings.HTTP_INVENTORY && + Client.Network.CurrentSim.Caps != null && + Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventory2") != null) + { + RequestFetchInventoryCap(itemIDs, ownerIDs); + return; + } + + + FetchInventoryPacket fetch = new FetchInventoryPacket(); + fetch.AgentData = new FetchInventoryPacket.AgentDataBlock(); + fetch.AgentData.AgentID = Client.Self.AgentID; + fetch.AgentData.SessionID = Client.Self.SessionID; + + fetch.InventoryData = new FetchInventoryPacket.InventoryDataBlock[itemIDs.Count]; + for (int i = 0; i < itemIDs.Count; i++) + { + fetch.InventoryData[i] = new FetchInventoryPacket.InventoryDataBlock(); + fetch.InventoryData[i].ItemID = itemIDs[i]; + fetch.InventoryData[i].OwnerID = ownerIDs[i]; + } + + Client.Network.SendPacket(fetch); + } + + /// + /// Request inventory items via Capabilities + /// + /// Inventory items to request + /// Owners of the inventory items + /// + private void RequestFetchInventoryCap(List itemIDs, List ownerIDs) + { + if (itemIDs.Count != ownerIDs.Count) + throw new ArgumentException("itemIDs and ownerIDs must contain the same number of entries"); + + if (Client.Settings.HTTP_INVENTORY && + Client.Network.CurrentSim.Caps != null && + Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventory2") != null) + { + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventory2"); + CapsClient request = new CapsClient(url); + + request.OnComplete += (client, result, error) => + { + if (error == null) + { + try + { + OSDMap res = (OSDMap)result; + OSDArray itemsOSD = (OSDArray)res["items"]; + + for (int i = 0; i < itemsOSD.Count; i++) + { + InventoryItem item = InventoryItem.FromOSD(itemsOSD[i]); + _Store[item.UUID] = item; + OnItemReceived(new ItemReceivedEventArgs(item)); + } + } + catch (Exception ex) + { + Logger.Log("Failed getting data from FetchInventory2 capability.", Helpers.LogLevel.Error, Client, ex); + } + } + }; + + OSDMap OSDRequest = new OSDMap(); + OSDRequest["agent_id"] = Client.Self.AgentID; + + OSDArray items = new OSDArray(itemIDs.Count); + for (int i = 0; i < itemIDs.Count; i++) + { + OSDMap item = new OSDMap(2); + item["item_id"] = itemIDs[i]; + item["owner_id"] = ownerIDs[i]; + items.Add(item); + } + + OSDRequest["items"] = items; + + request.BeginGetResponse(OSDRequest, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + } + + /// + /// Get contents of a folder + /// + /// The of the folder to search + /// The of the folders owner + /// true to retrieve folders + /// true to retrieve items + /// sort order to return results in + /// a integer representing the number of milliseconds to wait for results + /// A list of inventory items matching search criteria within folder + /// + /// InventoryFolder.DescendentCount will only be accurate if both folders and items are + /// requested + public List FolderContents(UUID folder, UUID owner, bool folders, bool items, + InventorySortOrder order, int timeoutMS) + { + List objects = null; + AutoResetEvent fetchEvent = new AutoResetEvent(false); + + EventHandler callback = + delegate(object sender, FolderUpdatedEventArgs e) + { + if (e.FolderID == folder + && _Store[folder] is InventoryFolder) + { + // InventoryDescendentsHandler only stores DescendendCount if both folders and items are fetched. + if (_Store.GetContents(folder).Count >= ((InventoryFolder)_Store[folder]).DescendentCount) + { + + fetchEvent.Set(); + } + } + else + { + fetchEvent.Set(); + } + }; + + FolderUpdated += callback; + + RequestFolderContents(folder, owner, folders, items, order); + if (fetchEvent.WaitOne(timeoutMS, false)) + objects = _Store.GetContents(folder); + + FolderUpdated -= callback; + + return objects; + } + + /// + /// Request the contents of an inventory folder + /// + /// The folder to search + /// The folder owners + /// true to return s contained in folder + /// true to return s containd in folder + /// the sort order to return items in + /// + public void RequestFolderContents(UUID folder, UUID owner, bool folders, bool items, + InventorySortOrder order) + { + string cap = owner == Client.Self.AgentID ? "FetchInventoryDescendents2" : "FetchLibDescendents2"; + + if (Client.Settings.HTTP_INVENTORY && + Client.Network.CurrentSim.Caps != null && + Client.Network.CurrentSim.Caps.CapabilityURI(cap) != null) + { + RequestFolderContentsCap(folder, owner, folders, items, order); + return; + } + + FetchInventoryDescendentsPacket fetch = new FetchInventoryDescendentsPacket(); + fetch.AgentData.AgentID = Client.Self.AgentID; + fetch.AgentData.SessionID = Client.Self.SessionID; + + fetch.InventoryData.FetchFolders = folders; + fetch.InventoryData.FetchItems = items; + fetch.InventoryData.FolderID = folder; + fetch.InventoryData.OwnerID = owner; + fetch.InventoryData.SortOrder = (int)order; + + Client.Network.SendPacket(fetch); + } + + /// + /// Request the contents of an inventory folder using HTTP capabilities + /// + /// The folder to search + /// The folder owners + /// true to return s contained in folder + /// true to return s containd in folder + /// the sort order to return items in + /// + public void RequestFolderContentsCap(UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, + InventorySortOrder order) + { + Uri url = null; + string cap = ownerID == Client.Self.AgentID ? "FetchInventoryDescendents2" : "FetchLibDescendents2"; + if (Client.Network.CurrentSim.Caps == null || + null == (url = Client.Network.CurrentSim.Caps.CapabilityURI(cap))) + { + Logger.Log(cap + " capability not available in the current sim", Helpers.LogLevel.Warning, Client); + OnFolderUpdated(new FolderUpdatedEventArgs(folderID, false)); + return; + } + + InventoryFolder folder = new InventoryFolder(folderID); + folder.OwnerID = ownerID; + folder.UUID = folderID; + RequestFolderContentsCap(new List() { folder }, url, fetchFolders, fetchItems, order); + } + + public void RequestFolderContentsCap(List batch, Uri url, bool fetchFolders, bool fetchItems, InventorySortOrder order) + { + + try + { + CapsClient request = new CapsClient(url); + request.OnComplete += (client, result, error) => + { + try + { + if (error != null) + { + throw error; + } + + OSDMap resultMap = ((OSDMap)result); + if (resultMap.ContainsKey("folders")) + { + OSDArray fetchedFolders = (OSDArray)resultMap["folders"]; + for (int fetchedFolderNr = 0; fetchedFolderNr < fetchedFolders.Count; fetchedFolderNr++) + { + OSDMap res = (OSDMap)fetchedFolders[fetchedFolderNr]; + InventoryFolder fetchedFolder = null; + + if (_Store.Contains(res["folder_id"]) + && _Store[res["folder_id"]] is InventoryFolder) + { + fetchedFolder = (InventoryFolder)_Store[res["folder_id"]]; + } + else + { + fetchedFolder = new InventoryFolder(res["folder_id"]); + _Store[res["folder_id"]] = fetchedFolder; + } + fetchedFolder.DescendentCount = res["descendents"]; + fetchedFolder.Version = res["version"]; + fetchedFolder.OwnerID = res["owner_id"]; + _Store.GetNodeFor(fetchedFolder.UUID).NeedsUpdate = false; + + // Do we have any descendants + if (fetchedFolder.DescendentCount > 0) + { + // Fetch descendent folders + if (res["categories"] is OSDArray) + { + OSDArray folders = (OSDArray)res["categories"]; + for (int i = 0; i < folders.Count; i++) + { + OSDMap descFolder = (OSDMap)folders[i]; + InventoryFolder folder; + UUID folderID = descFolder.ContainsKey("category_id") ? descFolder["category_id"] : descFolder["folder_id"]; + if (!_Store.Contains(folderID)) + { + folder = new InventoryFolder(folderID); + folder.ParentUUID = descFolder["parent_id"]; + _Store[folderID] = folder; + } + else + { + folder = (InventoryFolder)_Store[folderID]; + } + + folder.OwnerID = descFolder["agent_id"]; + folder.ParentUUID = descFolder["parent_id"]; + folder.Name = descFolder["name"]; + folder.Version = descFolder["version"]; + folder.PreferredType = (AssetType)(int)descFolder["type_default"]; + } + + // Fetch descendent items + OSDArray items = (OSDArray)res["items"]; + for (int i = 0; i < items.Count; i++) + { + InventoryItem item = InventoryItem.FromOSD(items[i]); + _Store[item.UUID] = item; + } + } + } + + OnFolderUpdated(new FolderUpdatedEventArgs(res["folder_id"], true)); + } + } + } + catch (Exception exc) + { + Logger.Log(string.Format("Failed to fetch inventory descendants: {0}\n{1}", exc.Message, exc.StackTrace.ToString()), Helpers.LogLevel.Warning, Client); + foreach (var f in batch) + { + OnFolderUpdated(new FolderUpdatedEventArgs(f.UUID, false)); + } + return; + } + + }; + + // Construct request + OSDArray requestedFolders = new OSDArray(1); + foreach (var f in batch) + { + OSDMap requestedFolder = new OSDMap(1); + requestedFolder["folder_id"] = f.UUID; + requestedFolder["owner_id"] = f.OwnerID; + requestedFolder["fetch_folders"] = fetchFolders; + requestedFolder["fetch_items"] = fetchItems; + requestedFolder["sort_order"] = (int)order; + + requestedFolders.Add(requestedFolder); + } + OSDMap req = new OSDMap(1); + req["folders"] = requestedFolders; + + request.BeginGetResponse(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + catch (Exception ex) + { + Logger.Log(string.Format("Failed to fetch inventory descendants: {0}\n{1}", ex.Message, ex.StackTrace.ToString()), Helpers.LogLevel.Warning, Client); + foreach (var f in batch) + { + OnFolderUpdated(new FolderUpdatedEventArgs(f.UUID, false)); + } + return; + } + } + + #endregion Fetch + + #region Find + + /// + /// Returns the UUID of the folder (category) that defaults to + /// containing 'type'. The folder is not necessarily only for that + /// type + /// + /// This will return the root folder if one does not exist + /// + /// The UUID of the desired folder if found, the UUID of the RootFolder + /// if not found, or UUID.Zero on failure + public UUID FindFolderForType(AssetType type) + { + if (_Store == null) + { + Logger.Log("Inventory is null, FindFolderForType() lookup cannot continue", + Helpers.LogLevel.Error, Client); + return UUID.Zero; + } + + // Folders go in the root + if (type == AssetType.Folder) + return _Store.RootFolder.UUID; + + // Loop through each top-level directory and check if PreferredType + // matches the requested type + List contents = _Store.GetContents(_Store.RootFolder.UUID); + foreach (InventoryBase inv in contents) + { + if (inv is InventoryFolder) + { + InventoryFolder folder = inv as InventoryFolder; + + if (folder.PreferredType == type) + return folder.UUID; + } + } + + // No match found, return Root Folder ID + return _Store.RootFolder.UUID; + } + + /// + /// Find an object in inventory using a specific path to search + /// + /// The folder to begin the search in + /// The object owners + /// A string path to search + /// milliseconds to wait for a reply + /// Found items or if + /// timeout occurs or item is not found + public UUID FindObjectByPath(UUID baseFolder, UUID inventoryOwner, string path, int timeoutMS) + { + AutoResetEvent findEvent = new AutoResetEvent(false); + UUID foundItem = UUID.Zero; + + EventHandler callback = + delegate(object sender, FindObjectByPathReplyEventArgs e) + { + if (e.Path == path) + { + foundItem = e.InventoryObjectID; + findEvent.Set(); + } + }; + + FindObjectByPathReply += callback; + + RequestFindObjectByPath(baseFolder, inventoryOwner, path); + findEvent.WaitOne(timeoutMS, false); + + FindObjectByPathReply -= callback; + + return foundItem; + } + + /// + /// Find inventory items by path + /// + /// The folder to begin the search in + /// The object owners + /// A string path to search, folders/objects separated by a '/' + /// Results are sent to the event + public void RequestFindObjectByPath(UUID baseFolder, UUID inventoryOwner, string path) + { + if (path == null || path.Length == 0) + throw new ArgumentException("Empty path is not supported"); + + // Store this search + InventorySearch search; + search.Folder = baseFolder; + search.Owner = inventoryOwner; + search.Path = path.Split('/'); + search.Level = 0; + lock (_Searches) _Searches.Add(search); + + // Start the search + RequestFolderContents(baseFolder, inventoryOwner, true, true, InventorySortOrder.ByName); + } + + /// + /// Search inventory Store object for an item or folder + /// + /// The folder to begin the search in + /// An array which creates a path to search + /// Number of levels below baseFolder to conduct searches + /// if True, will stop searching after first match is found + /// A list of inventory items found + public List LocalFind(UUID baseFolder, string[] path, int level, bool firstOnly) + { + List objects = new List(); + //List folders = new List(); + List contents = _Store.GetContents(baseFolder); + + foreach (InventoryBase inv in contents) + { + if (inv.Name.CompareTo(path[level]) == 0) + { + if (level == path.Length - 1) + { + objects.Add(inv); + if (firstOnly) return objects; + } + else if (inv is InventoryFolder) + objects.AddRange(LocalFind(inv.UUID, path, level + 1, firstOnly)); + } + } + + return objects; + } + + #endregion Find + + #region Move/Rename + + /// + /// Move an inventory item or folder to a new location + /// + /// The item or folder to move + /// The to move item or folder to + public void Move(InventoryBase item, InventoryFolder newParent) + { + if (item is InventoryFolder) + MoveFolder(item.UUID, newParent.UUID); + else + MoveItem(item.UUID, newParent.UUID); + } + + /// + /// Move an inventory item or folder to a new location and change its name + /// + /// The item or folder to move + /// The to move item or folder to + /// The name to change the item or folder to + public void Move(InventoryBase item, InventoryFolder newParent, string newName) + { + if (item is InventoryFolder) + MoveFolder(item.UUID, newParent.UUID, newName); + else + MoveItem(item.UUID, newParent.UUID, newName); + } + + /// + /// Move and rename a folder + /// + /// The source folders + /// The destination folders + /// The name to change the folder to + public void MoveFolder(UUID folderID, UUID newparentID, string newName) + { + UpdateFolderProperties(folderID, newparentID, newName, AssetType.Unknown); + } + + /// + /// Update folder properties + /// + /// of the folder to update + /// Sets folder's parent to + /// Folder name + /// Folder type + public void UpdateFolderProperties(UUID folderID, UUID parentID, string name, AssetType type) + { + lock (Store) + { + if (_Store.Contains(folderID)) + { + InventoryFolder inv = (InventoryFolder)Store[folderID]; + inv.Name = name; + inv.ParentUUID = parentID; + inv.PreferredType = type; + _Store.UpdateNodeFor(inv); + } + } + + UpdateInventoryFolderPacket invFolder = new UpdateInventoryFolderPacket(); + invFolder.AgentData.AgentID = Client.Self.AgentID; + invFolder.AgentData.SessionID = Client.Self.SessionID; + invFolder.FolderData = new UpdateInventoryFolderPacket.FolderDataBlock[1]; + invFolder.FolderData[0] = new UpdateInventoryFolderPacket.FolderDataBlock(); + invFolder.FolderData[0].FolderID = folderID; + invFolder.FolderData[0].ParentID = parentID; + invFolder.FolderData[0].Name = Utils.StringToBytes(name); + invFolder.FolderData[0].Type = (sbyte)type; + + Client.Network.SendPacket(invFolder); + } + + /// + /// Move a folder + /// + /// The source folders + /// The destination folders + public void MoveFolder(UUID folderID, UUID newParentID) + { + lock (Store) + { + if (_Store.Contains(folderID)) + { + InventoryBase inv = Store[folderID]; + inv.ParentUUID = newParentID; + _Store.UpdateNodeFor(inv); + } + } + + MoveInventoryFolderPacket move = new MoveInventoryFolderPacket(); + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; + move.AgentData.Stamp = false; //FIXME: ?? + + move.InventoryData = new MoveInventoryFolderPacket.InventoryDataBlock[1]; + move.InventoryData[0] = new MoveInventoryFolderPacket.InventoryDataBlock(); + move.InventoryData[0].FolderID = folderID; + move.InventoryData[0].ParentID = newParentID; + + Client.Network.SendPacket(move); + } + + /// + /// Move multiple folders, the keys in the Dictionary parameter, + /// to a new parents, the value of that folder's key. + /// + /// A Dictionary containing the + /// of the source as the key, and the + /// of the destination as the value + public void MoveFolders(Dictionary foldersNewParents) + { + // FIXME: Use two List to stay consistent + + lock (Store) + { + foreach (KeyValuePair entry in foldersNewParents) + { + if (_Store.Contains(entry.Key)) + { + InventoryBase inv = _Store[entry.Key]; + inv.ParentUUID = entry.Value; + _Store.UpdateNodeFor(inv); + } + } + } + + //TODO: Test if this truly supports multiple-folder move + MoveInventoryFolderPacket move = new MoveInventoryFolderPacket(); + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; + move.AgentData.Stamp = false; //FIXME: ?? + + move.InventoryData = new MoveInventoryFolderPacket.InventoryDataBlock[foldersNewParents.Count]; + + int index = 0; + foreach (KeyValuePair folder in foldersNewParents) + { + MoveInventoryFolderPacket.InventoryDataBlock block = new MoveInventoryFolderPacket.InventoryDataBlock(); + block.FolderID = folder.Key; + block.ParentID = folder.Value; + move.InventoryData[index++] = block; + } + + Client.Network.SendPacket(move); + } + + + /// + /// Move an inventory item to a new folder + /// + /// The of the source item to move + /// The of the destination folder + public void MoveItem(UUID itemID, UUID folderID) + { + MoveItem(itemID, folderID, String.Empty); + } + + /// + /// Move and rename an inventory item + /// + /// The of the source item to move + /// The of the destination folder + /// The name to change the folder to + public void MoveItem(UUID itemID, UUID folderID, string newName) + { + lock (_Store) + { + if (_Store.Contains(itemID)) + { + InventoryBase inv = _Store[itemID]; + if (!string.IsNullOrEmpty(newName)) + { + inv.Name = newName; + } + inv.ParentUUID = folderID; + _Store.UpdateNodeFor(inv); + } + } + + MoveInventoryItemPacket move = new MoveInventoryItemPacket(); + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; + move.AgentData.Stamp = false; //FIXME: ?? + + move.InventoryData = new MoveInventoryItemPacket.InventoryDataBlock[1]; + move.InventoryData[0] = new MoveInventoryItemPacket.InventoryDataBlock(); + move.InventoryData[0].ItemID = itemID; + move.InventoryData[0].FolderID = folderID; + move.InventoryData[0].NewName = Utils.StringToBytes(newName); + + Client.Network.SendPacket(move); + } + + /// + /// Move multiple inventory items to new locations + /// + /// A Dictionary containing the + /// of the source item as the key, and the + /// of the destination folder as the value + public void MoveItems(Dictionary itemsNewParents) + { + lock (_Store) + { + foreach (KeyValuePair entry in itemsNewParents) + { + if (_Store.Contains(entry.Key)) + { + InventoryBase inv = _Store[entry.Key]; + inv.ParentUUID = entry.Value; + _Store.UpdateNodeFor(inv); + } + } + } + + MoveInventoryItemPacket move = new MoveInventoryItemPacket(); + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; + move.AgentData.Stamp = false; //FIXME: ?? + + move.InventoryData = new MoveInventoryItemPacket.InventoryDataBlock[itemsNewParents.Count]; + + int index = 0; + foreach (KeyValuePair entry in itemsNewParents) + { + MoveInventoryItemPacket.InventoryDataBlock block = new MoveInventoryItemPacket.InventoryDataBlock(); + block.ItemID = entry.Key; + block.FolderID = entry.Value; + block.NewName = Utils.EmptyBytes; + move.InventoryData[index++] = block; + } + + Client.Network.SendPacket(move); + } + + #endregion Move + + #region Remove + + /// + /// Remove descendants of a folder + /// + /// The of the folder + public void RemoveDescendants(UUID folder) + { + PurgeInventoryDescendentsPacket purge = new PurgeInventoryDescendentsPacket(); + purge.AgentData.AgentID = Client.Self.AgentID; + purge.AgentData.SessionID = Client.Self.SessionID; + purge.InventoryData.FolderID = folder; + Client.Network.SendPacket(purge); + + // Update our local copy + lock (_Store) + { + if (_Store.Contains(folder)) + { + List contents = _Store.GetContents(folder); + foreach (InventoryBase obj in contents) + { + _Store.RemoveNodeFor(obj); + } + } + } + } + + /// + /// Remove a single item from inventory + /// + /// The of the inventory item to remove + public void RemoveItem(UUID item) + { + List items = new List(1); + items.Add(item); + + Remove(items, null); + } + + /// + /// Remove a folder from inventory + /// + /// The of the folder to remove + public void RemoveFolder(UUID folder) + { + List folders = new List(1); + folders.Add(folder); + + Remove(null, folders); + } + + /// + /// Remove multiple items or folders from inventory + /// + /// A List containing the s of items to remove + /// A List containing the s of the folders to remove + public void Remove(List items, List folders) + { + if ((items == null || items.Count == 0) && (folders == null || folders.Count == 0)) + return; + + RemoveInventoryObjectsPacket rem = new RemoveInventoryObjectsPacket(); + rem.AgentData.AgentID = Client.Self.AgentID; + rem.AgentData.SessionID = Client.Self.SessionID; + + if (items == null || items.Count == 0) + { + // To indicate that we want no items removed: + rem.ItemData = new RemoveInventoryObjectsPacket.ItemDataBlock[1]; + rem.ItemData[0] = new RemoveInventoryObjectsPacket.ItemDataBlock(); + rem.ItemData[0].ItemID = UUID.Zero; + } + else + { + lock (_Store) + { + rem.ItemData = new RemoveInventoryObjectsPacket.ItemDataBlock[items.Count]; + for (int i = 0; i < items.Count; i++) + { + rem.ItemData[i] = new RemoveInventoryObjectsPacket.ItemDataBlock(); + rem.ItemData[i].ItemID = items[i]; + + // Update local copy + if (_Store.Contains(items[i])) + _Store.RemoveNodeFor(Store[items[i]]); + } + } + } + + if (folders == null || folders.Count == 0) + { + // To indicate we want no folders removed: + rem.FolderData = new RemoveInventoryObjectsPacket.FolderDataBlock[1]; + rem.FolderData[0] = new RemoveInventoryObjectsPacket.FolderDataBlock(); + rem.FolderData[0].FolderID = UUID.Zero; + } + else + { + lock (_Store) + { + rem.FolderData = new RemoveInventoryObjectsPacket.FolderDataBlock[folders.Count]; + for (int i = 0; i < folders.Count; i++) + { + rem.FolderData[i] = new RemoveInventoryObjectsPacket.FolderDataBlock(); + rem.FolderData[i].FolderID = folders[i]; + + // Update local copy + if (_Store.Contains(folders[i])) + _Store.RemoveNodeFor(Store[folders[i]]); + } + } + } + Client.Network.SendPacket(rem); + } + + /// + /// Empty the Lost and Found folder + /// + public void EmptyLostAndFound() + { + EmptySystemFolder(AssetType.LostAndFoundFolder); + } + + /// + /// Empty the Trash folder + /// + public void EmptyTrash() + { + EmptySystemFolder(AssetType.TrashFolder); + } + + private void EmptySystemFolder(AssetType folderType) + { + List items = _Store.GetContents(_Store.RootFolder); + + UUID folderKey = UUID.Zero; + foreach (InventoryBase item in items) + { + if ((item as InventoryFolder) != null) + { + InventoryFolder folder = item as InventoryFolder; + if (folder.PreferredType == folderType) + { + folderKey = folder.UUID; + break; + } + } + } + items = _Store.GetContents(folderKey); + List remItems = new List(); + List remFolders = new List(); + foreach (InventoryBase item in items) + { + if ((item as InventoryFolder) != null) + { + remFolders.Add(item.UUID); + } + else + { + remItems.Add(item.UUID); + } + } + Remove(remItems, remFolders); + } + #endregion Remove + + #region Create + + /// + /// + /// + /// + /// + /// + /// + /// Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. + /// + /// + /// + public void RequestCreateItem(UUID parentFolder, string name, string description, AssetType type, UUID assetTransactionID, + InventoryType invType, PermissionMask nextOwnerMask, ItemCreatedCallback callback) + { + // Even though WearableType 0 is Shape, in this context it is treated as NOT_WEARABLE + RequestCreateItem(parentFolder, name, description, type, assetTransactionID, invType, (WearableType)0, nextOwnerMask, + callback); + } + + /// + /// + /// + /// + /// + /// + /// + /// Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. + /// + /// + /// + /// + public void RequestCreateItem(UUID parentFolder, string name, string description, AssetType type, UUID assetTransactionID, + InventoryType invType, WearableType wearableType, PermissionMask nextOwnerMask, ItemCreatedCallback callback) + { + CreateInventoryItemPacket create = new CreateInventoryItemPacket(); + create.AgentData.AgentID = Client.Self.AgentID; + create.AgentData.SessionID = Client.Self.SessionID; + + create.InventoryBlock.CallbackID = RegisterItemCreatedCallback(callback); + create.InventoryBlock.FolderID = parentFolder; + create.InventoryBlock.TransactionID = assetTransactionID; + create.InventoryBlock.NextOwnerMask = (uint)nextOwnerMask; + create.InventoryBlock.Type = (sbyte)type; + create.InventoryBlock.InvType = (sbyte)invType; + create.InventoryBlock.WearableType = (byte)wearableType; + create.InventoryBlock.Name = Utils.StringToBytes(name); + create.InventoryBlock.Description = Utils.StringToBytes(description); + + Client.Network.SendPacket(create); + } + + /// + /// Creates a new inventory folder + /// + /// ID of the folder to put this folder in + /// Name of the folder to create + /// The UUID of the newly created folder + public UUID CreateFolder(UUID parentID, string name) + { + return CreateFolder(parentID, name, AssetType.Unknown); + } + + /// + /// Creates a new inventory folder + /// + /// ID of the folder to put this folder in + /// Name of the folder to create + /// Sets this folder as the default folder + /// for new assets of the specified type. Use AssetType.Unknown + /// to create a normal folder, otherwise it will likely create a + /// duplicate of an existing folder type + /// The UUID of the newly created folder + /// If you specify a preferred type of AsseType.Folder + /// it will create a new root folder which may likely cause all sorts + /// of strange problems + public UUID CreateFolder(UUID parentID, string name, AssetType preferredType) + { + UUID id = UUID.Random(); + + // Assign a folder name if one is not already set + if (String.IsNullOrEmpty(name)) + { + if (preferredType >= AssetType.Texture && preferredType <= AssetType.Gesture) + { + name = _NewFolderNames[(int)preferredType]; + } + else + { + name = "New Folder"; + } + } + + // Create the new folder locally + InventoryFolder newFolder = new InventoryFolder(id); + newFolder.Version = 1; + newFolder.DescendentCount = 0; + newFolder.ParentUUID = parentID; + newFolder.PreferredType = preferredType; + newFolder.Name = name; + newFolder.OwnerID = Client.Self.AgentID; + + // Update the local store + try { _Store[newFolder.UUID] = newFolder; } + catch (InventoryException ie) { Logger.Log(ie.Message, Helpers.LogLevel.Warning, Client, ie); } + + // Create the create folder packet and send it + CreateInventoryFolderPacket create = new CreateInventoryFolderPacket(); + create.AgentData.AgentID = Client.Self.AgentID; + create.AgentData.SessionID = Client.Self.SessionID; + + create.FolderData.FolderID = id; + create.FolderData.ParentID = parentID; + create.FolderData.Type = (sbyte)preferredType; + create.FolderData.Name = Utils.StringToBytes(name); + + Client.Network.SendPacket(create); + + return id; + } + + /// + /// Create an inventory item and upload asset data + /// + /// Asset data + /// Inventory item name + /// Inventory item description + /// Asset type + /// Inventory type + /// Put newly created inventory in this folder + /// Delegate that will receive feedback on success or failure + public void RequestCreateItemFromAsset(byte[] data, string name, string description, AssetType assetType, + InventoryType invType, UUID folderID, ItemCreatedFromAssetCallback callback) + { + Permissions permissions = new Permissions(); + permissions.EveryoneMask = PermissionMask.None; + permissions.GroupMask = PermissionMask.None; + permissions.NextOwnerMask = PermissionMask.All; + + RequestCreateItemFromAsset(data, name, description, assetType, invType, folderID, permissions, callback); + } + + /// + /// Create an inventory item and upload asset data + /// + /// Asset data + /// Inventory item name + /// Inventory item description + /// Asset type + /// Inventory type + /// Put newly created inventory in this folder + /// Permission of the newly created item + /// (EveryoneMask, GroupMask, and NextOwnerMask of Permissions struct are supported) + /// Delegate that will receive feedback on success or failure + public void RequestCreateItemFromAsset(byte[] data, string name, string description, AssetType assetType, + InventoryType invType, UUID folderID, Permissions permissions, ItemCreatedFromAssetCallback callback) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + throw new Exception("NewFileAgentInventory capability is not currently available"); + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("NewFileAgentInventory"); + + if (url != null) + { + OSDMap query = new OSDMap(); + query.Add("folder_id", OSD.FromUUID(folderID)); + query.Add("asset_type", OSD.FromString(Utils.AssetTypeToString(assetType))); + query.Add("inventory_type", OSD.FromString(Utils.InventoryTypeToString(invType))); + query.Add("name", OSD.FromString(name)); + query.Add("description", OSD.FromString(description)); + query.Add("everyone_mask", OSD.FromInteger((int)permissions.EveryoneMask)); + query.Add("group_mask", OSD.FromInteger((int)permissions.GroupMask)); + query.Add("next_owner_mask", OSD.FromInteger((int)permissions.NextOwnerMask)); + query.Add("expected_upload_cost", OSD.FromInteger(Client.Settings.UPLOAD_COST)); + + // Make the request + CapsClient request = new CapsClient(url); + request.OnComplete += CreateItemFromAssetResponse; + request.UserData = new object[] { callback, data, Client.Settings.CAPS_TIMEOUT, query }; + + request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("NewFileAgentInventory capability is not currently available"); + } + } + + /// + /// Creates inventory link to another inventory item or folder + /// + /// Put newly created link in folder with this UUID + /// Inventory item or folder + /// Method to call upon creation of the link + public void CreateLink(UUID folderID, InventoryBase bse, ItemCreatedCallback callback) + { + if (bse is InventoryFolder) + { + InventoryFolder folder = (InventoryFolder)bse; + CreateLink(folderID, folder, callback); + } + else if (bse is InventoryItem) + { + InventoryItem item = (InventoryItem)bse; + CreateLink(folderID, item.UUID, item.Name, item.Description, AssetType.Link, item.InventoryType, UUID.Random(), callback); + } + } + + /// + /// Creates inventory link to another inventory item + /// + /// Put newly created link in folder with this UUID + /// Original inventory item + /// Method to call upon creation of the link + public void CreateLink(UUID folderID, InventoryItem item, ItemCreatedCallback callback) + { + CreateLink(folderID, item.UUID, item.Name, item.Description, AssetType.Link, item.InventoryType, UUID.Random(), callback); + } + + /// + /// Creates inventory link to another inventory folder + /// + /// Put newly created link in folder with this UUID + /// Original inventory folder + /// Method to call upon creation of the link + public void CreateLink(UUID folderID, InventoryFolder folder, ItemCreatedCallback callback) + { + CreateLink(folderID, folder.UUID, folder.Name, "", AssetType.LinkFolder, InventoryType.Folder, UUID.Random(), callback); + } + + /// + /// Creates inventory link to another inventory item or folder + /// + /// Put newly created link in folder with this UUID + /// Original item's UUID + /// Name + /// Description + /// Asset Type + /// Inventory Type + /// Transaction UUID + /// Method to call upon creation of the link + public void CreateLink(UUID folderID, UUID itemID, string name, string description, AssetType assetType, InventoryType invType, UUID transactionID, ItemCreatedCallback callback) + { + LinkInventoryItemPacket create = new LinkInventoryItemPacket(); + create.AgentData.AgentID = Client.Self.AgentID; + create.AgentData.SessionID = Client.Self.SessionID; + + create.InventoryBlock.CallbackID = RegisterItemCreatedCallback(callback); + lock (_ItemInventoryTypeRequest) + { + _ItemInventoryTypeRequest[create.InventoryBlock.CallbackID] = invType; + } + create.InventoryBlock.FolderID = folderID; + create.InventoryBlock.TransactionID = transactionID; + create.InventoryBlock.OldItemID = itemID; + create.InventoryBlock.Type = (sbyte)assetType; + create.InventoryBlock.InvType = (sbyte)invType; + create.InventoryBlock.Name = Utils.StringToBytes(name); + create.InventoryBlock.Description = Utils.StringToBytes(description); + + Client.Network.SendPacket(create); + } + + #endregion Create + + #region Copy + + /// + /// + /// + /// + /// + /// + /// + public void RequestCopyItem(UUID item, UUID newParent, string newName, ItemCopiedCallback callback) + { + RequestCopyItem(item, newParent, newName, Client.Self.AgentID, callback); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public void RequestCopyItem(UUID item, UUID newParent, string newName, UUID oldOwnerID, + ItemCopiedCallback callback) + { + List items = new List(1); + items.Add(item); + + List folders = new List(1); + folders.Add(newParent); + + List names = new List(1); + names.Add(newName); + + RequestCopyItems(items, folders, names, oldOwnerID, callback); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public void RequestCopyItems(List items, List targetFolders, List newNames, + UUID oldOwnerID, ItemCopiedCallback callback) + { + if (items.Count != targetFolders.Count || (newNames != null && items.Count != newNames.Count)) + throw new ArgumentException("All list arguments must have an equal number of entries"); + + uint callbackID = RegisterItemsCopiedCallback(callback); + + CopyInventoryItemPacket copy = new CopyInventoryItemPacket(); + copy.AgentData.AgentID = Client.Self.AgentID; + copy.AgentData.SessionID = Client.Self.SessionID; + + copy.InventoryData = new CopyInventoryItemPacket.InventoryDataBlock[items.Count]; + for (int i = 0; i < items.Count; ++i) + { + copy.InventoryData[i] = new CopyInventoryItemPacket.InventoryDataBlock(); + copy.InventoryData[i].CallbackID = callbackID; + copy.InventoryData[i].NewFolderID = targetFolders[i]; + copy.InventoryData[i].OldAgentID = oldOwnerID; + copy.InventoryData[i].OldItemID = items[i]; + + if (newNames != null && !String.IsNullOrEmpty(newNames[i])) + copy.InventoryData[i].NewName = Utils.StringToBytes(newNames[i]); + else + copy.InventoryData[i].NewName = Utils.EmptyBytes; + } + + Client.Network.SendPacket(copy); + } + + /// + /// Request a copy of an asset embedded within a notecard + /// + /// Usually UUID.Zero for copying an asset from a notecard + /// UUID of the notecard to request an asset from + /// Target folder for asset to go to in your inventory + /// UUID of the embedded asset + /// callback to run when item is copied to inventory + public void RequestCopyItemFromNotecard(UUID objectID, UUID notecardID, UUID folderID, UUID itemID, ItemCopiedCallback callback) + { + _ItemCopiedCallbacks[0] = callback; //Notecards always use callback ID 0 + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("CopyInventoryFromNotecard"); + + if (url != null) + { + CopyInventoryFromNotecardMessage message = new CopyInventoryFromNotecardMessage(); + message.CallbackID = 0; + message.FolderID = folderID; + message.ItemID = itemID; + message.NotecardID = notecardID; + message.ObjectID = objectID; + + CapsClient request = new CapsClient(url); + request.BeginGetResponse(message.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + CopyInventoryFromNotecardPacket copy = new CopyInventoryFromNotecardPacket(); + copy.AgentData.AgentID = Client.Self.AgentID; + copy.AgentData.SessionID = Client.Self.SessionID; + + copy.NotecardData.ObjectID = objectID; + copy.NotecardData.NotecardItemID = notecardID; + + copy.InventoryData = new CopyInventoryFromNotecardPacket.InventoryDataBlock[1]; + copy.InventoryData[0] = new CopyInventoryFromNotecardPacket.InventoryDataBlock(); + copy.InventoryData[0].FolderID = folderID; + copy.InventoryData[0].ItemID = itemID; + + Client.Network.SendPacket(copy); + } + } + + #endregion Copy + + #region Update + + /// + /// + /// + /// + public void RequestUpdateItem(InventoryItem item) + { + List items = new List(1); + items.Add(item); + + RequestUpdateItems(items, UUID.Random()); + } + + /// + /// + /// + /// + public void RequestUpdateItems(List items) + { + RequestUpdateItems(items, UUID.Random()); + } + + /// + /// + /// + /// + /// + public void RequestUpdateItems(List items, UUID transactionID) + { + UpdateInventoryItemPacket update = new UpdateInventoryItemPacket(); + update.AgentData.AgentID = Client.Self.AgentID; + update.AgentData.SessionID = Client.Self.SessionID; + update.AgentData.TransactionID = transactionID; + + update.InventoryData = new UpdateInventoryItemPacket.InventoryDataBlock[items.Count]; + for (int i = 0; i < items.Count; i++) + { + InventoryItem item = items[i]; + + UpdateInventoryItemPacket.InventoryDataBlock block = new UpdateInventoryItemPacket.InventoryDataBlock(); + block.BaseMask = (uint)item.Permissions.BaseMask; + block.CRC = ItemCRC(item); + block.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); + block.CreatorID = item.CreatorID; + block.Description = Utils.StringToBytes(item.Description); + block.EveryoneMask = (uint)item.Permissions.EveryoneMask; + block.Flags = (uint)item.Flags; + block.FolderID = item.ParentUUID; + block.GroupID = item.GroupID; + block.GroupMask = (uint)item.Permissions.GroupMask; + block.GroupOwned = item.GroupOwned; + block.InvType = (sbyte)item.InventoryType; + block.ItemID = item.UUID; + block.Name = Utils.StringToBytes(item.Name); + block.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; + block.OwnerID = item.OwnerID; + block.OwnerMask = (uint)item.Permissions.OwnerMask; + block.SalePrice = item.SalePrice; + block.SaleType = (byte)item.SaleType; + block.TransactionID = item.TransactionID; + block.Type = (sbyte)item.AssetType; + + update.InventoryData[i] = block; + } + + Client.Network.SendPacket(update); + } + + /// + /// + /// + /// + /// + /// + public void RequestUploadNotecardAsset(byte[] data, UUID notecardID, InventoryUploadedAssetCallback callback) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + throw new Exception("UpdateNotecardAgentInventory capability is not currently available"); + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateNotecardAgentInventory"); + + if (url != null) + { + OSDMap query = new OSDMap(); + query.Add("item_id", OSD.FromUUID(notecardID)); + + // Make the request + CapsClient request = new CapsClient(url); + request.OnComplete += UploadInventoryAssetResponse; + request.UserData = new object[] { new KeyValuePair(callback, data), notecardID }; + request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("UpdateNotecardAgentInventory capability is not currently available"); + } + } + + /// + /// Save changes to notecard embedded in object contents + /// + /// Encoded notecard asset data + /// Notecard UUID + /// Object's UUID + /// Called upon finish of the upload with status information + public void RequestUpdateNotecardTask(byte[] data, UUID notecardID, UUID taskID, InventoryUploadedAssetCallback callback) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + throw new Exception("UpdateNotecardTaskInventory capability is not currently available"); + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateNotecardTaskInventory"); + + if (url != null) + { + OSDMap query = new OSDMap(); + query.Add("item_id", OSD.FromUUID(notecardID)); + query.Add("task_id", OSD.FromUUID(taskID)); + + // Make the request + CapsClient request = new CapsClient(url); + request.OnComplete += UploadInventoryAssetResponse; + request.UserData = new object[] { new KeyValuePair(callback, data), notecardID }; + request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("UpdateNotecardTaskInventory capability is not currently available"); + } + } + + /// + /// Upload new gesture asset for an inventory gesture item + /// + /// Encoded gesture asset + /// Gesture inventory UUID + /// Callback whick will be called when upload is complete + public void RequestUploadGestureAsset(byte[] data, UUID gestureID, InventoryUploadedAssetCallback callback) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + throw new Exception("UpdateGestureAgentInventory capability is not currently available"); + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateGestureAgentInventory"); + + if (url != null) + { + OSDMap query = new OSDMap(); + query.Add("item_id", OSD.FromUUID(gestureID)); + + // Make the request + CapsClient request = new CapsClient(url); + request.OnComplete += UploadInventoryAssetResponse; + request.UserData = new object[] { new KeyValuePair(callback, data), gestureID }; + request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("UpdateGestureAgentInventory capability is not currently available"); + } + } + + /// + /// Update an existing script in an agents Inventory + /// + /// A byte[] array containing the encoded scripts contents + /// the itemID of the script + /// if true, sets the script content to run on the mono interpreter + /// + public void RequestUpdateScriptAgentInventory(byte[] data, UUID itemID, bool mono, ScriptUpdatedCallback callback) + { + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateScriptAgent"); + + if (url != null) + { + UpdateScriptAgentRequestMessage msg = new UpdateScriptAgentRequestMessage(); + msg.ItemID = itemID; + msg.Target = mono ? "mono" : "lsl2"; + + CapsClient request = new CapsClient(url); + request.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse); + request.UserData = new object[2] { new KeyValuePair(callback, data), itemID }; + request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("UpdateScriptAgent capability is not currently available"); + } + } + + /// + /// Update an existing script in an task Inventory + /// + /// A byte[] array containing the encoded scripts contents + /// the itemID of the script + /// UUID of the prim containting the script + /// if true, sets the script content to run on the mono interpreter + /// if true, sets the script to running + /// + public void RequestUpdateScriptTask(byte[] data, UUID itemID, UUID taskID, bool mono, bool running, ScriptUpdatedCallback callback) + { + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateScriptTask"); + + if (url != null) + { + UpdateScriptTaskUpdateMessage msg = new UpdateScriptTaskUpdateMessage(); + msg.ItemID = itemID; + msg.TaskID = taskID; + msg.ScriptRunning = running; + msg.Target = mono ? "mono" : "lsl2"; + + CapsClient request = new CapsClient(url); + request.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse); + request.UserData = new object[2] { new KeyValuePair(callback, data), itemID }; + request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + throw new Exception("UpdateScriptTask capability is not currently available"); + } + } + #endregion Update + + #region Rez/Give + + /// + /// Rez an object from inventory + /// + /// Simulator to place object in + /// Rotation of the object when rezzed + /// Vector of where to place object + /// InventoryItem object containing item details + public UUID RequestRezFromInventory(Simulator simulator, Quaternion rotation, Vector3 position, + InventoryItem item) + { + return RequestRezFromInventory(simulator, rotation, position, item, Client.Self.ActiveGroup, + UUID.Random(), true); + } + + /// + /// Rez an object from inventory + /// + /// Simulator to place object in + /// Rotation of the object when rezzed + /// Vector of where to place object + /// InventoryItem object containing item details + /// UUID of group to own the object + public UUID RequestRezFromInventory(Simulator simulator, Quaternion rotation, Vector3 position, + InventoryItem item, UUID groupOwner) + { + return RequestRezFromInventory(simulator, rotation, position, item, groupOwner, UUID.Random(), true); + } + + /// + /// Rez an object from inventory + /// + /// Simulator to place object in + /// Rotation of the object when rezzed + /// Vector of where to place object + /// InventoryItem object containing item details + /// UUID of group to own the object + /// User defined queryID to correlate replies + /// If set to true, the CreateSelected flag + /// will be set on the rezzed object + public UUID RequestRezFromInventory(Simulator simulator, Quaternion rotation, Vector3 position, + InventoryItem item, UUID groupOwner, UUID queryID, bool rezSelected) + { + return RequestRezFromInventory(simulator, UUID.Zero, rotation, position, item, groupOwner, queryID, + rezSelected); + } + + /// + /// Rez an object from inventory + /// + /// Simulator to place object in + /// TaskID object when rezzed + /// Rotation of the object when rezzed + /// Vector of where to place object + /// InventoryItem object containing item details + /// UUID of group to own the object + /// User defined queryID to correlate replies + /// If set to true, the CreateSelected flag + /// will be set on the rezzed object + public UUID RequestRezFromInventory(Simulator simulator, UUID taskID, Quaternion rotation, Vector3 position, + InventoryItem item, UUID groupOwner, UUID queryID, bool rezSelected) + { + RezObjectPacket add = new RezObjectPacket(); + + add.AgentData.AgentID = Client.Self.AgentID; + add.AgentData.SessionID = Client.Self.SessionID; + add.AgentData.GroupID = groupOwner; + + add.RezData.FromTaskID = taskID; + add.RezData.BypassRaycast = 1; + add.RezData.RayStart = position; + add.RezData.RayEnd = position; + add.RezData.RayTargetID = UUID.Zero; + add.RezData.RayEndIsIntersection = false; + add.RezData.RezSelected = rezSelected; + add.RezData.RemoveItem = false; + add.RezData.ItemFlags = (uint)item.Flags; + add.RezData.GroupMask = (uint)item.Permissions.GroupMask; + add.RezData.EveryoneMask = (uint)item.Permissions.EveryoneMask; + add.RezData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; + + add.InventoryData.ItemID = item.UUID; + add.InventoryData.FolderID = item.ParentUUID; + add.InventoryData.CreatorID = item.CreatorID; + add.InventoryData.OwnerID = item.OwnerID; + add.InventoryData.GroupID = item.GroupID; + add.InventoryData.BaseMask = (uint)item.Permissions.BaseMask; + add.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask; + add.InventoryData.GroupMask = (uint)item.Permissions.GroupMask; + add.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask; + add.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; + add.InventoryData.GroupOwned = item.GroupOwned; + add.InventoryData.TransactionID = queryID; + add.InventoryData.Type = (sbyte)item.InventoryType; + add.InventoryData.InvType = (sbyte)item.InventoryType; + add.InventoryData.Flags = (uint)item.Flags; + add.InventoryData.SaleType = (byte)item.SaleType; + add.InventoryData.SalePrice = item.SalePrice; + add.InventoryData.Name = Utils.StringToBytes(item.Name); + add.InventoryData.Description = Utils.StringToBytes(item.Description); + add.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); + + Client.Network.SendPacket(add, simulator); + + // Remove from store if the item is no copy + if (Store.Items.ContainsKey(item.UUID) && Store[item.UUID] is InventoryItem) + { + InventoryItem invItem = (InventoryItem)Store[item.UUID]; + if ((invItem.Permissions.OwnerMask & PermissionMask.Copy) == PermissionMask.None) + { + Store.RemoveNodeFor(invItem); + } + } + + return queryID; + } + + /// + /// DeRez an object from the simulator to the agents Objects folder in the agents Inventory + /// + /// The simulator Local ID of the object + /// If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed + public void RequestDeRezToInventory(uint objectLocalID) + { + RequestDeRezToInventory(objectLocalID, DeRezDestination.AgentInventoryTake, + Client.Inventory.FindFolderForType(AssetType.Object), UUID.Random()); + } + + /// + /// DeRez an object from the simulator and return to inventory + /// + /// The simulator Local ID of the object + /// The type of destination from the enum + /// The destination inventory folders -or- + /// if DeRezzing object to a tasks Inventory, the Tasks + /// The transaction ID for this request which + /// can be used to correlate this request with other packets + /// If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed + public void RequestDeRezToInventory(uint objectLocalID, DeRezDestination destType, UUID destFolder, UUID transactionID) + { + DeRezObjectPacket take = new DeRezObjectPacket(); + + take.AgentData.AgentID = Client.Self.AgentID; + take.AgentData.SessionID = Client.Self.SessionID; + take.AgentBlock = new DeRezObjectPacket.AgentBlockBlock(); + take.AgentBlock.GroupID = UUID.Zero; + take.AgentBlock.Destination = (byte)destType; + take.AgentBlock.DestinationID = destFolder; + take.AgentBlock.PacketCount = 1; + take.AgentBlock.PacketNumber = 1; + take.AgentBlock.TransactionID = transactionID; + + take.ObjectData = new DeRezObjectPacket.ObjectDataBlock[1]; + take.ObjectData[0] = new DeRezObjectPacket.ObjectDataBlock(); + take.ObjectData[0].ObjectLocalID = objectLocalID; + + Client.Network.SendPacket(take); + } + + /// + /// Rez an item from inventory to its previous simulator location + /// + /// + /// + /// + /// + public UUID RequestRestoreRezFromInventory(Simulator simulator, InventoryItem item, UUID queryID) + { + RezRestoreToWorldPacket add = new RezRestoreToWorldPacket(); + + add.AgentData.AgentID = Client.Self.AgentID; + add.AgentData.SessionID = Client.Self.SessionID; + + add.InventoryData.ItemID = item.UUID; + add.InventoryData.FolderID = item.ParentUUID; + add.InventoryData.CreatorID = item.CreatorID; + add.InventoryData.OwnerID = item.OwnerID; + add.InventoryData.GroupID = item.GroupID; + add.InventoryData.BaseMask = (uint)item.Permissions.BaseMask; + add.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask; + add.InventoryData.GroupMask = (uint)item.Permissions.GroupMask; + add.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask; + add.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; + add.InventoryData.GroupOwned = item.GroupOwned; + add.InventoryData.TransactionID = queryID; + add.InventoryData.Type = (sbyte)item.InventoryType; + add.InventoryData.InvType = (sbyte)item.InventoryType; + add.InventoryData.Flags = (uint)item.Flags; + add.InventoryData.SaleType = (byte)item.SaleType; + add.InventoryData.SalePrice = item.SalePrice; + add.InventoryData.Name = Utils.StringToBytes(item.Name); + add.InventoryData.Description = Utils.StringToBytes(item.Description); + add.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); + + Client.Network.SendPacket(add, simulator); + + return queryID; + } + + /// + /// Give an inventory item to another avatar + /// + /// The of the item to give + /// The name of the item + /// The type of the item from the enum + /// The of the recipient + /// true to generate a beameffect during transfer + public void GiveItem(UUID itemID, string itemName, AssetType assetType, UUID recipient, + bool doEffect) + { + byte[] bucket; + + + bucket = new byte[17]; + bucket[0] = (byte)assetType; + Buffer.BlockCopy(itemID.GetBytes(), 0, bucket, 1, 16); + + Client.Self.InstantMessage( + Client.Self.Name, + recipient, + itemName, + UUID.Random(), + InstantMessageDialog.InventoryOffered, + InstantMessageOnline.Online, + Client.Self.SimPosition, + Client.Network.CurrentSim.ID, + bucket); + + if (doEffect) + { + Client.Self.BeamEffect(Client.Self.AgentID, recipient, Vector3d.Zero, + Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random()); + } + + // Remove from store if the item is no copy + if (Store.Items.ContainsKey(itemID) && Store[itemID] is InventoryItem) + { + InventoryItem invItem = (InventoryItem)Store[itemID]; + if ((invItem.Permissions.OwnerMask & PermissionMask.Copy) == PermissionMask.None) + { + Store.RemoveNodeFor(invItem); + } + } + } + + /// + /// Give an inventory Folder with contents to another avatar + /// + /// The of the Folder to give + /// The name of the folder + /// The type of the item from the enum + /// The of the recipient + /// true to generate a beameffect during transfer + public void GiveFolder(UUID folderID, string folderName, AssetType assetType, UUID recipient, + bool doEffect) + { + byte[] bucket; + + List folderContents = new List(); + + Client.Inventory.FolderContents(folderID, Client.Self.AgentID, false, true, InventorySortOrder.ByDate, 1000 * 15).ForEach( + delegate(InventoryBase ib) + { + folderContents.Add(Client.Inventory.FetchItem(ib.UUID, Client.Self.AgentID, 1000 * 10)); + }); + bucket = new byte[17 * (folderContents.Count + 1)]; + + //Add parent folder (first item in bucket) + bucket[0] = (byte)assetType; + Buffer.BlockCopy(folderID.GetBytes(), 0, bucket, 1, 16); + + //Add contents to bucket after folder + for (int i = 1; i <= folderContents.Count; ++i) + { + bucket[i * 17] = (byte)folderContents[i - 1].AssetType; + Buffer.BlockCopy(folderContents[i - 1].UUID.GetBytes(), 0, bucket, i * 17 + 1, 16); + } + + Client.Self.InstantMessage( + Client.Self.Name, + recipient, + folderName, + UUID.Random(), + InstantMessageDialog.InventoryOffered, + InstantMessageOnline.Online, + Client.Self.SimPosition, + Client.Network.CurrentSim.ID, + bucket); + + if (doEffect) + { + Client.Self.BeamEffect(Client.Self.AgentID, recipient, Vector3d.Zero, + Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random()); + } + + // Remove from store if items were no copy + for (int i = 0; i < folderContents.Count; i++) + { + + if (Store.Items.ContainsKey(folderContents[i].UUID) && Store[folderContents[i].UUID] is InventoryItem) + { + InventoryItem invItem = (InventoryItem)Store[folderContents[i].UUID]; + if ((invItem.Permissions.OwnerMask & PermissionMask.Copy) == PermissionMask.None) + { + Store.RemoveNodeFor(invItem); + } + } + + } + } + + #endregion Rez/Give + + #region Task + + /// + /// Copy or move an from agent inventory to a task (primitive) inventory + /// + /// The target object + /// The item to copy or move from inventory + /// + /// For items with copy permissions a copy of the item is placed in the tasks inventory, + /// for no-copy items the object is moved to the tasks inventory + // DocTODO: what does the return UUID correlate to if anything? + public UUID UpdateTaskInventory(uint objectLocalID, InventoryItem item) + { + UUID transactionID = UUID.Random(); + + UpdateTaskInventoryPacket update = new UpdateTaskInventoryPacket(); + update.AgentData.AgentID = Client.Self.AgentID; + update.AgentData.SessionID = Client.Self.SessionID; + update.UpdateData.Key = 0; + update.UpdateData.LocalID = objectLocalID; + + update.InventoryData.ItemID = item.UUID; + update.InventoryData.FolderID = item.ParentUUID; + update.InventoryData.CreatorID = item.CreatorID; + update.InventoryData.OwnerID = item.OwnerID; + update.InventoryData.GroupID = item.GroupID; + update.InventoryData.BaseMask = (uint)item.Permissions.BaseMask; + update.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask; + update.InventoryData.GroupMask = (uint)item.Permissions.GroupMask; + update.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask; + update.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; + update.InventoryData.GroupOwned = item.GroupOwned; + update.InventoryData.TransactionID = transactionID; + update.InventoryData.Type = (sbyte)item.AssetType; + update.InventoryData.InvType = (sbyte)item.InventoryType; + update.InventoryData.Flags = (uint)item.Flags; + update.InventoryData.SaleType = (byte)item.SaleType; + update.InventoryData.SalePrice = item.SalePrice; + update.InventoryData.Name = Utils.StringToBytes(item.Name); + update.InventoryData.Description = Utils.StringToBytes(item.Description); + update.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); + update.InventoryData.CRC = ItemCRC(item); + + Client.Network.SendPacket(update); + + return transactionID; + } + + /// + /// Retrieve a listing of the items contained in a task (Primitive) + /// + /// The tasks + /// The tasks simulator local ID + /// milliseconds to wait for reply from simulator + /// A list containing the inventory items inside the task or null + /// if a timeout occurs + /// This request blocks until the response from the simulator arrives + /// or timeoutMS is exceeded + public List GetTaskInventory(UUID objectID, UInt32 objectLocalID, Int32 timeoutMS) + { + String filename = null; + AutoResetEvent taskReplyEvent = new AutoResetEvent(false); + + EventHandler callback = + delegate(object sender, TaskInventoryReplyEventArgs e) + { + if (e.ItemID == objectID) + { + filename = e.AssetFilename; + taskReplyEvent.Set(); + } + }; + + TaskInventoryReply += callback; + + RequestTaskInventory(objectLocalID); + + if (taskReplyEvent.WaitOne(timeoutMS, false)) + { + TaskInventoryReply -= callback; + + if (!String.IsNullOrEmpty(filename)) + { + byte[] assetData = null; + ulong xferID = 0; + AutoResetEvent taskDownloadEvent = new AutoResetEvent(false); + + EventHandler xferCallback = + delegate(object sender, XferReceivedEventArgs e) + { + if (e.Xfer.XferID == xferID) + { + assetData = e.Xfer.AssetData; + taskDownloadEvent.Set(); + } + }; + + Client.Assets.XferReceived += xferCallback; + + // Start the actual asset xfer + xferID = Client.Assets.RequestAssetXfer(filename, true, false, UUID.Zero, AssetType.Unknown, true); + + if (taskDownloadEvent.WaitOne(timeoutMS, false)) + { + Client.Assets.XferReceived -= xferCallback; + + String taskList = Utils.BytesToString(assetData); + return ParseTaskInventory(taskList); + } + else + { + Logger.Log("Timed out waiting for task inventory download for " + filename, Helpers.LogLevel.Warning, Client); + Client.Assets.XferReceived -= xferCallback; + return null; + } + } + else + { + Logger.DebugLog("Task is empty for " + objectLocalID, Client); + return new List(0); + } + } + else + { + Logger.Log("Timed out waiting for task inventory reply for " + objectLocalID, Helpers.LogLevel.Warning, Client); + TaskInventoryReply -= callback; + return null; + } + } + + /// + /// Request the contents of a tasks (primitives) inventory from the + /// current simulator + /// + /// The LocalID of the object + /// + public void RequestTaskInventory(uint objectLocalID) + { + RequestTaskInventory(objectLocalID, Client.Network.CurrentSim); + } + + /// + /// Request the contents of a tasks (primitives) inventory + /// + /// The simulator Local ID of the object + /// A reference to the simulator object that contains the object + /// + public void RequestTaskInventory(uint objectLocalID, Simulator simulator) + { + RequestTaskInventoryPacket request = new RequestTaskInventoryPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.InventoryData.LocalID = objectLocalID; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Move an item from a tasks (Primitive) inventory to the specified folder in the avatars inventory + /// + /// LocalID of the object in the simulator + /// UUID of the task item to move + /// The ID of the destination folder in this agents inventory + /// Simulator Object + /// Raises the event + public void MoveTaskInventory(uint objectLocalID, UUID taskItemID, UUID inventoryFolderID, Simulator simulator) + { + MoveTaskInventoryPacket request = new MoveTaskInventoryPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + request.AgentData.FolderID = inventoryFolderID; + + request.InventoryData.ItemID = taskItemID; + request.InventoryData.LocalID = objectLocalID; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Remove an item from an objects (Prim) Inventory + /// + /// LocalID of the object in the simulator + /// UUID of the task item to remove + /// Simulator Object + /// You can confirm the removal by comparing the tasks inventory serial before and after the + /// request with the request combined with + /// the event + public void RemoveTaskInventory(uint objectLocalID, UUID taskItemID, Simulator simulator) + { + RemoveTaskInventoryPacket remove = new RemoveTaskInventoryPacket(); + remove.AgentData.AgentID = Client.Self.AgentID; + remove.AgentData.SessionID = Client.Self.SessionID; + + remove.InventoryData.ItemID = taskItemID; + remove.InventoryData.LocalID = objectLocalID; + + Client.Network.SendPacket(remove, simulator); + } + + /// + /// Copy an InventoryScript item from the Agents Inventory into a primitives task inventory + /// + /// An unsigned integer representing a primitive being simulated + /// An which represents a script object from the agents inventory + /// true to set the scripts running state to enabled + /// A Unique Transaction ID + /// + /// The following example shows the basic steps necessary to copy a script from the agents inventory into a tasks inventory + /// and assumes the script exists in the agents inventory. + /// + /// uint primID = 95899503; // Fake prim ID + /// UUID scriptID = UUID.Parse("92a7fe8a-e949-dd39-a8d8-1681d8673232"); // Fake Script UUID in Inventory + /// + /// Client.Inventory.FolderContents(Client.Inventory.FindFolderForType(AssetType.LSLText), Client.Self.AgentID, + /// false, true, InventorySortOrder.ByName, 10000); + /// + /// Client.Inventory.RezScript(primID, (InventoryItem)Client.Inventory.Store[scriptID]); + /// + /// + // DocTODO: what does the return UUID correlate to if anything? + public UUID CopyScriptToTask(uint objectLocalID, InventoryItem item, bool enableScript) + { + UUID transactionID = UUID.Random(); + + RezScriptPacket ScriptPacket = new RezScriptPacket(); + ScriptPacket.AgentData.AgentID = Client.Self.AgentID; + ScriptPacket.AgentData.SessionID = Client.Self.SessionID; + + ScriptPacket.UpdateBlock.ObjectLocalID = objectLocalID; + ScriptPacket.UpdateBlock.Enabled = enableScript; + + ScriptPacket.InventoryBlock.ItemID = item.UUID; + ScriptPacket.InventoryBlock.FolderID = item.ParentUUID; + ScriptPacket.InventoryBlock.CreatorID = item.CreatorID; + ScriptPacket.InventoryBlock.OwnerID = item.OwnerID; + ScriptPacket.InventoryBlock.GroupID = item.GroupID; + ScriptPacket.InventoryBlock.BaseMask = (uint)item.Permissions.BaseMask; + ScriptPacket.InventoryBlock.OwnerMask = (uint)item.Permissions.OwnerMask; + ScriptPacket.InventoryBlock.GroupMask = (uint)item.Permissions.GroupMask; + ScriptPacket.InventoryBlock.EveryoneMask = (uint)item.Permissions.EveryoneMask; + ScriptPacket.InventoryBlock.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; + ScriptPacket.InventoryBlock.GroupOwned = item.GroupOwned; + ScriptPacket.InventoryBlock.TransactionID = transactionID; + ScriptPacket.InventoryBlock.Type = (sbyte)item.AssetType; + ScriptPacket.InventoryBlock.InvType = (sbyte)item.InventoryType; + ScriptPacket.InventoryBlock.Flags = (uint)item.Flags; + ScriptPacket.InventoryBlock.SaleType = (byte)item.SaleType; + ScriptPacket.InventoryBlock.SalePrice = item.SalePrice; + ScriptPacket.InventoryBlock.Name = Utils.StringToBytes(item.Name); + ScriptPacket.InventoryBlock.Description = Utils.StringToBytes(item.Description); + ScriptPacket.InventoryBlock.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); + ScriptPacket.InventoryBlock.CRC = ItemCRC(item); + + Client.Network.SendPacket(ScriptPacket); + + return transactionID; + } + + + /// + /// Request the running status of a script contained in a task (primitive) inventory + /// + /// The ID of the primitive containing the script + /// The ID of the script + /// The event can be used to obtain the results of the + /// request + /// + public void RequestGetScriptRunning(UUID objectID, UUID scriptID) + { + GetScriptRunningPacket request = new GetScriptRunningPacket(); + request.Script.ObjectID = objectID; + request.Script.ItemID = scriptID; + + Client.Network.SendPacket(request); + } + + /// + /// Send a request to set the running state of a script contained in a task (primitive) inventory + /// + /// The ID of the primitive containing the script + /// The ID of the script + /// true to set the script running, false to stop a running script + /// To verify the change you can use the method combined + /// with the event + public void RequestSetScriptRunning(UUID objectID, UUID scriptID, bool running) + { + SetScriptRunningPacket request = new SetScriptRunningPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.Script.Running = running; + request.Script.ItemID = scriptID; + request.Script.ObjectID = objectID; + + Client.Network.SendPacket(request); + } + + #endregion Task + + #region Helper Functions + + private uint RegisterItemCreatedCallback(ItemCreatedCallback callback) + { + lock (_CallbacksLock) + { + if (_CallbackPos == UInt32.MaxValue) + _CallbackPos = 0; + + _CallbackPos++; + + if (_ItemCreatedCallbacks.ContainsKey(_CallbackPos)) + Logger.Log("Overwriting an existing ItemCreatedCallback", Helpers.LogLevel.Warning, Client); + + _ItemCreatedCallbacks[_CallbackPos] = callback; + + return _CallbackPos; + } + } + + private uint RegisterItemsCopiedCallback(ItemCopiedCallback callback) + { + lock (_CallbacksLock) + { + if (_CallbackPos == UInt32.MaxValue) + _CallbackPos = 0; + + _CallbackPos++; + + if (_ItemCopiedCallbacks.ContainsKey(_CallbackPos)) + Logger.Log("Overwriting an existing ItemsCopiedCallback", Helpers.LogLevel.Warning, Client); + + _ItemCopiedCallbacks[_CallbackPos] = callback; + + return _CallbackPos; + } + } + + /// + /// Create a CRC from an InventoryItem + /// + /// The source InventoryItem + /// A uint representing the source InventoryItem as a CRC + public static uint ItemCRC(InventoryItem iitem) + { + uint CRC = 0; + + // IDs + CRC += iitem.AssetUUID.CRC(); // AssetID + CRC += iitem.ParentUUID.CRC(); // FolderID + CRC += iitem.UUID.CRC(); // ItemID + + // Permission stuff + CRC += iitem.CreatorID.CRC(); // CreatorID + CRC += iitem.OwnerID.CRC(); // OwnerID + CRC += iitem.GroupID.CRC(); // GroupID + + // CRC += another 4 words which always seem to be zero -- unclear if this is a UUID or what + CRC += (uint)iitem.Permissions.OwnerMask; //owner_mask; // Either owner_mask or next_owner_mask may need to be + CRC += (uint)iitem.Permissions.NextOwnerMask; //next_owner_mask; // switched with base_mask -- 2 values go here and in my + CRC += (uint)iitem.Permissions.EveryoneMask; //everyone_mask; // study item, the three were identical. + CRC += (uint)iitem.Permissions.GroupMask; //group_mask; + + // The rest of the CRC fields + CRC += (uint)iitem.Flags; // Flags + CRC += (uint)iitem.InventoryType; // InvType + CRC += (uint)iitem.AssetType; // Type + CRC += (uint)Utils.DateTimeToUnixTime(iitem.CreationDate); // CreationDate + CRC += (uint)iitem.SalePrice; // SalePrice + CRC += (uint)((uint)iitem.SaleType * 0x07073096); // SaleType + + return CRC; + } + + /// + /// Reverses a cheesy XORing with a fixed UUID to convert a shadow_id to an asset_id + /// + /// Obfuscated shadow_id value + /// Deobfuscated asset_id value + public static UUID DecryptShadowID(UUID shadowID) + { + return shadowID ^ MAGIC_ID; + } + + /// + /// Does a cheesy XORing with a fixed UUID to convert an asset_id to a shadow_id + /// + /// asset_id value to obfuscate + /// Obfuscated shadow_id value + public static UUID EncryptAssetID(UUID assetID) + { + return assetID ^ MAGIC_ID; + } + + /// + /// Wrapper for creating a new object + /// + /// The type of item from the enum + /// The of the newly created object + /// An object with the type and id passed + public static InventoryItem CreateInventoryItem(InventoryType type, UUID id) + { + switch (type) + { + case InventoryType.Texture: return new InventoryTexture(id); + case InventoryType.Sound: return new InventorySound(id); + case InventoryType.CallingCard: return new InventoryCallingCard(id); + case InventoryType.Landmark: return new InventoryLandmark(id); + case InventoryType.Object: return new InventoryObject(id); + case InventoryType.Notecard: return new InventoryNotecard(id); + case InventoryType.Category: return new InventoryCategory(id); + case InventoryType.LSL: return new InventoryLSL(id); + case InventoryType.Snapshot: return new InventorySnapshot(id); + case InventoryType.Attachment: return new InventoryAttachment(id); + case InventoryType.Wearable: return new InventoryWearable(id); + case InventoryType.Animation: return new InventoryAnimation(id); + case InventoryType.Gesture: return new InventoryGesture(id); + default: return new InventoryItem(type, id); + } + } + + private InventoryItem SafeCreateInventoryItem(InventoryType InvType, UUID ItemID) + { + InventoryItem ret = null; + + if (_Store.Contains(ItemID)) + ret = _Store[ItemID] as InventoryItem; + + if (ret == null) + ret = CreateInventoryItem(InvType, ItemID); + + return ret; + } + + private static bool ParseLine(string line, out string key, out string value) + { + // Clean up and convert tabs to spaces + line = line.Trim(); + line = line.Replace('\t', ' '); + + // Shrink all whitespace down to single spaces + while (line.IndexOf(" ") > 0) + line = line.Replace(" ", " "); + + if (line.Length > 2) + { + int sep = line.IndexOf(' '); + if (sep > 0) + { + key = line.Substring(0, sep); + value = line.Substring(sep + 1); + + return true; + } + } + else if (line.Length == 1) + { + key = line; + value = String.Empty; + return true; + } + + key = null; + value = null; + return false; + } + + /// + /// Parse the results of a RequestTaskInventory() response + /// + /// A string which contains the data from the task reply + /// A List containing the items contained within the tasks inventory + public static List ParseTaskInventory(string taskData) + { + List items = new List(); + int lineNum = 0; + string[] lines = taskData.Replace("\r\n", "\n").Split('\n'); + + while (lineNum < lines.Length) + { + string key, value; + if (ParseLine(lines[lineNum++], out key, out value)) + { + if (key == "inv_object") + { + #region inv_object + + // In practice this appears to only be used for folders + UUID itemID = UUID.Zero; + UUID parentID = UUID.Zero; + string name = String.Empty; + AssetType assetType = AssetType.Unknown; + + while (lineNum < lines.Length) + { + if (ParseLine(lines[lineNum++], out key, out value)) + { + if (key == "{") + { + continue; + } + else if (key == "}") + { + break; + } + else if (key == "obj_id") + { + UUID.TryParse(value, out itemID); + } + else if (key == "parent_id") + { + UUID.TryParse(value, out parentID); + } + else if (key == "type") + { + assetType = Utils.StringToAssetType(value); + } + else if (key == "name") + { + name = value.Substring(0, value.IndexOf('|')); + } + } + } + + if (assetType == AssetType.Folder) + { + InventoryFolder folder = new InventoryFolder(itemID); + folder.Name = name; + folder.ParentUUID = parentID; + + items.Add(folder); + } + else + { + InventoryItem item = new InventoryItem(itemID); + item.Name = name; + item.ParentUUID = parentID; + item.AssetType = assetType; + + items.Add(item); + } + + #endregion inv_object + } + else if (key == "inv_item") + { + #region inv_item + + // Any inventory item that links to an assetID, has permissions, etc + UUID itemID = UUID.Zero; + UUID assetID = UUID.Zero; + UUID parentID = UUID.Zero; + UUID creatorID = UUID.Zero; + UUID ownerID = UUID.Zero; + UUID lastOwnerID = UUID.Zero; + UUID groupID = UUID.Zero; + bool groupOwned = false; + string name = String.Empty; + string desc = String.Empty; + AssetType assetType = AssetType.Unknown; + InventoryType inventoryType = InventoryType.Unknown; + DateTime creationDate = Utils.Epoch; + uint flags = 0; + Permissions perms = Permissions.NoPermissions; + SaleType saleType = SaleType.Not; + int salePrice = 0; + + while (lineNum < lines.Length) + { + if (ParseLine(lines[lineNum++], out key, out value)) + { + if (key == "{") + { + continue; + } + else if (key == "}") + { + break; + } + else if (key == "item_id") + { + UUID.TryParse(value, out itemID); + } + else if (key == "parent_id") + { + UUID.TryParse(value, out parentID); + } + else if (key == "permissions") + { + #region permissions + + while (lineNum < lines.Length) + { + if (ParseLine(lines[lineNum++], out key, out value)) + { + if (key == "{") + { + continue; + } + else if (key == "}") + { + break; + } + else if (key == "creator_mask") + { + // Deprecated + uint val; + if (Utils.TryParseHex(value, out val)) + perms.BaseMask = (PermissionMask)val; + } + else if (key == "base_mask") + { + uint val; + if (Utils.TryParseHex(value, out val)) + perms.BaseMask = (PermissionMask)val; + } + else if (key == "owner_mask") + { + uint val; + if (Utils.TryParseHex(value, out val)) + perms.OwnerMask = (PermissionMask)val; + } + else if (key == "group_mask") + { + uint val; + if (Utils.TryParseHex(value, out val)) + perms.GroupMask = (PermissionMask)val; + } + else if (key == "everyone_mask") + { + uint val; + if (Utils.TryParseHex(value, out val)) + perms.EveryoneMask = (PermissionMask)val; + } + else if (key == "next_owner_mask") + { + uint val; + if (Utils.TryParseHex(value, out val)) + perms.NextOwnerMask = (PermissionMask)val; + } + else if (key == "creator_id") + { + + UUID.TryParse(value, out creatorID); + } + else if (key == "owner_id") + { + UUID.TryParse(value, out ownerID); + } + else if (key == "last_owner_id") + { + UUID.TryParse(value, out lastOwnerID); + } + else if (key == "group_id") + { + UUID.TryParse(value, out groupID); + } + else if (key == "group_owned") + { + uint val; + if (UInt32.TryParse(value, out val)) + groupOwned = (val != 0); + } + } + } + + #endregion permissions + } + else if (key == "sale_info") + { + #region sale_info + + while (lineNum < lines.Length) + { + if (ParseLine(lines[lineNum++], out key, out value)) + { + if (key == "{") + { + continue; + } + else if (key == "}") + { + break; + } + else if (key == "sale_type") + { + saleType = Utils.StringToSaleType(value); + } + else if (key == "sale_price") + { + Int32.TryParse(value, out salePrice); + } + } + } + + #endregion sale_info + } + else if (key == "shadow_id") + { + UUID shadowID; + if (UUID.TryParse(value, out shadowID)) + assetID = DecryptShadowID(shadowID); + } + else if (key == "asset_id") + { + UUID.TryParse(value, out assetID); + } + else if (key == "type") + { + assetType = Utils.StringToAssetType(value); + } + else if (key == "inv_type") + { + inventoryType = Utils.StringToInventoryType(value); + } + else if (key == "flags") + { + UInt32.TryParse(value, out flags); + } + else if (key == "name") + { + name = value.Substring(0, value.IndexOf('|')); + } + else if (key == "desc") + { + desc = value.Substring(0, value.IndexOf('|')); + } + else if (key == "creation_date") + { + uint timestamp; + if (UInt32.TryParse(value, out timestamp)) + creationDate = Utils.UnixTimeToDateTime(timestamp); + else + Logger.Log("Failed to parse creation_date " + value, Helpers.LogLevel.Warning); + } + } + } + + InventoryItem item = CreateInventoryItem(inventoryType, itemID); + item.AssetUUID = assetID; + item.AssetType = assetType; + item.CreationDate = creationDate; + item.CreatorID = creatorID; + item.Description = desc; + item.Flags = flags; + item.GroupID = groupID; + item.GroupOwned = groupOwned; + item.Name = name; + item.OwnerID = ownerID; + item.LastOwnerID = lastOwnerID; + item.ParentUUID = parentID; + item.Permissions = perms; + item.SalePrice = salePrice; + item.SaleType = saleType; + + items.Add(item); + + #endregion inv_item + } + else + { + Logger.Log("Unrecognized token " + key + " in: " + Environment.NewLine + taskData, + Helpers.LogLevel.Error); + } + } + } + + return items; + } + + #endregion Helper Functions + + #region Internal Callbacks + + void Self_IM(object sender, InstantMessageEventArgs e) + { + // TODO: MainAvatar.InstantMessageDialog.GroupNotice can also be an inventory offer, should we + // handle it here? + + if (m_InventoryObjectOffered != null && + (e.IM.Dialog == InstantMessageDialog.InventoryOffered + || e.IM.Dialog == InstantMessageDialog.TaskInventoryOffered)) + { + AssetType type = AssetType.Unknown; + UUID objectID = UUID.Zero; + bool fromTask = false; + + if (e.IM.Dialog == InstantMessageDialog.InventoryOffered) + { + if (e.IM.BinaryBucket.Length == 17) + { + type = (AssetType)e.IM.BinaryBucket[0]; + objectID = new UUID(e.IM.BinaryBucket, 1); + fromTask = false; + } + else + { + Logger.Log("Malformed inventory offer from agent", Helpers.LogLevel.Warning, Client); + return; + } + } + else if (e.IM.Dialog == InstantMessageDialog.TaskInventoryOffered) + { + if (e.IM.BinaryBucket.Length == 1) + { + type = (AssetType)e.IM.BinaryBucket[0]; + fromTask = true; + } + else + { + Logger.Log("Malformed inventory offer from object", Helpers.LogLevel.Warning, Client); + return; + } + } + + // Find the folder where this is going to go + UUID destinationFolderID = FindFolderForType(type); + + // Fire the callback + try + { + ImprovedInstantMessagePacket imp = new ImprovedInstantMessagePacket(); + imp.AgentData.AgentID = Client.Self.AgentID; + imp.AgentData.SessionID = Client.Self.SessionID; + imp.MessageBlock.FromGroup = false; + imp.MessageBlock.ToAgentID = e.IM.FromAgentID; + imp.MessageBlock.Offline = 0; + imp.MessageBlock.ID = e.IM.IMSessionID; + imp.MessageBlock.Timestamp = 0; + imp.MessageBlock.FromAgentName = Utils.StringToBytes(Client.Self.Name); + imp.MessageBlock.Message = Utils.EmptyBytes; + imp.MessageBlock.ParentEstateID = 0; + imp.MessageBlock.RegionID = UUID.Zero; + imp.MessageBlock.Position = Client.Self.SimPosition; + + InventoryObjectOfferedEventArgs args = new InventoryObjectOfferedEventArgs(e.IM, type, objectID, fromTask, destinationFolderID); + + OnInventoryObjectOffered(args); + + if (args.Accept) + { + // Accept the inventory offer + switch (e.IM.Dialog) + { + case InstantMessageDialog.InventoryOffered: + imp.MessageBlock.Dialog = (byte)InstantMessageDialog.InventoryAccepted; + break; + case InstantMessageDialog.TaskInventoryOffered: + imp.MessageBlock.Dialog = (byte)InstantMessageDialog.TaskInventoryAccepted; + break; + case InstantMessageDialog.GroupNotice: + imp.MessageBlock.Dialog = (byte)InstantMessageDialog.GroupNoticeInventoryAccepted; + break; + } + imp.MessageBlock.BinaryBucket = args.FolderID.GetBytes(); + } + else + { + // Decline the inventory offer + switch (e.IM.Dialog) + { + case InstantMessageDialog.InventoryOffered: + imp.MessageBlock.Dialog = (byte)InstantMessageDialog.InventoryDeclined; + break; + case InstantMessageDialog.TaskInventoryOffered: + imp.MessageBlock.Dialog = (byte)InstantMessageDialog.TaskInventoryDeclined; + break; + case InstantMessageDialog.GroupNotice: + imp.MessageBlock.Dialog = (byte)InstantMessageDialog.GroupNoticeInventoryDeclined; + break; + } + + imp.MessageBlock.BinaryBucket = Utils.EmptyBytes; + } + + Client.Network.SendPacket(imp, e.Simulator); + } + catch (Exception ex) + { + Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); + } + } + } + + private void CreateItemFromAssetResponse(CapsClient client, OSD result, Exception error) + { + object[] args = (object[])client.UserData; + ItemCreatedFromAssetCallback callback = (ItemCreatedFromAssetCallback)args[0]; + byte[] itemData = (byte[])args[1]; + int millisecondsTimeout = (int)args[2]; + OSDMap request = (OSDMap)args[3]; + + if (result == null) + { + try { callback(false, error.Message, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + return; + } + + if (result.Type == OSDType.Unknown) + { + try + { + callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); + } + catch (Exception e) + { + Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); + } + } + + OSDMap contents = (OSDMap)result; + + string status = contents["state"].AsString().ToLower(); + + if (status == "upload") + { + string uploadURL = contents["uploader"].AsString(); + + Logger.DebugLog("CreateItemFromAsset: uploading to " + uploadURL); + + // This makes the assumption that all uploads go to CurrentSim, to avoid + // the problem of HttpRequestState not knowing anything about simulators + CapsClient upload = new CapsClient(new Uri(uploadURL)); + upload.OnComplete += CreateItemFromAssetResponse; + upload.UserData = new object[] { callback, itemData, millisecondsTimeout, request }; + upload.BeginGetResponse(itemData, "application/octet-stream", millisecondsTimeout); + } + else if (status == "complete") + { + Logger.DebugLog("CreateItemFromAsset: completed"); + + if (contents.ContainsKey("new_inventory_item") && contents.ContainsKey("new_asset")) + { + // Request full update on the item in order to update the local store + RequestFetchInventory(contents["new_inventory_item"].AsUUID(), Client.Self.AgentID); + + try { callback(true, String.Empty, contents["new_inventory_item"].AsUUID(), contents["new_asset"].AsUUID()); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + else + { + try { callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else + { + // Failure + try { callback(false, status, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + + + private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason, LoginResponseData replyData) + { + if (loginSuccess) + { + // Initialize the store here so we know who owns it: + _Store = new Inventory(Client, this, Client.Self.AgentID); + Logger.DebugLog("Setting InventoryRoot to " + replyData.InventoryRoot.ToString(), Client); + InventoryFolder rootFolder = new InventoryFolder(replyData.InventoryRoot); + rootFolder.Name = String.Empty; + rootFolder.ParentUUID = UUID.Zero; + _Store.RootFolder = rootFolder; + + for (int i = 0; i < replyData.InventorySkeleton.Length; i++) + _Store.UpdateNodeFor(replyData.InventorySkeleton[i]); + + InventoryFolder libraryRootFolder = new InventoryFolder(replyData.LibraryRoot); + libraryRootFolder.Name = String.Empty; + libraryRootFolder.ParentUUID = UUID.Zero; + _Store.LibraryFolder = libraryRootFolder; + + for (int i = 0; i < replyData.LibrarySkeleton.Length; i++) + _Store.UpdateNodeFor(replyData.LibrarySkeleton[i]); + } + } + + private void UploadInventoryAssetResponse(CapsClient client, OSD result, Exception error) + { + OSDMap contents = result as OSDMap; + KeyValuePair kvp = (KeyValuePair)(((object[])client.UserData)[0]); + InventoryUploadedAssetCallback callback = kvp.Key; + byte[] itemData = (byte[])kvp.Value; + + if (error == null && contents != null) + { + string status = contents["state"].AsString(); + + if (status == "upload") + { + Uri uploadURL = contents["uploader"].AsUri(); + + if (uploadURL != null) + { + // This makes the assumption that all uploads go to CurrentSim, to avoid + // the problem of HttpRequestState not knowing anything about simulators + CapsClient upload = new CapsClient(uploadURL); + upload.OnComplete += UploadInventoryAssetResponse; + upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; + upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); + } + else + { + try { callback(false, "Missing uploader URL", UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else if (status == "complete") + { + if (contents.ContainsKey("new_asset")) + { + // Request full item update so we keep store in sync + RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); + + try { callback(true, String.Empty, (UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + else + { + try { callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else + { + try { callback(false, status, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else + { + string message = "Unrecognized or empty response"; + + if (error != null) + { + if (error is WebException) + message = ((HttpWebResponse)((WebException)error).Response).StatusDescription; + + if (message == null || message == "None") + message = error.Message; + } + + try { callback(false, message, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + + private void UpdateScriptAgentInventoryResponse(CapsClient client, OSD result, Exception error) + { + KeyValuePair kvp = (KeyValuePair)(((object[])client.UserData)[0]); + ScriptUpdatedCallback callback = kvp.Key; + byte[] itemData = (byte[])kvp.Value; + + if (result == null) + { + try { callback(false, error.Message, false, null, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + return; + } + + OSDMap contents = (OSDMap)result; + + string status = contents["state"].AsString(); + if (status == "upload") + { + string uploadURL = contents["uploader"].AsString(); + + CapsClient upload = new CapsClient(new Uri(uploadURL)); + upload.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse); + upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; + upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); + } + else if (status == "complete" && callback != null) + { + if (contents.ContainsKey("new_asset")) + { + // Request full item update so we keep store in sync + RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); + + + try + { + List compileErrors = null; + + if (contents.ContainsKey("errors")) + { + OSDArray errors = (OSDArray)contents["errors"]; + compileErrors = new List(errors.Count); + + for (int i = 0; i < errors.Count; i++) + { + compileErrors.Add(errors[i].AsString()); + } + } + + callback(true, + status, + contents["compiled"].AsBoolean(), + compileErrors, + (UUID)(((object[])client.UserData)[1]), + contents["new_asset"].AsUUID()); + } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + else + { + try { callback(false, "Failed to parse asset UUID", false, null, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else if (callback != null) + { + try { callback(false, status, false, null, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + #endregion Internal Handlers + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void SaveAssetIntoInventoryHandler(object sender, PacketReceivedEventArgs e) + { + if (m_SaveAssetToInventory != null) + { + Packet packet = e.Packet; + + SaveAssetIntoInventoryPacket save = (SaveAssetIntoInventoryPacket)packet; + OnSaveAssetToInventory(new SaveAssetToInventoryEventArgs(save.InventoryData.ItemID, save.InventoryData.NewAssetID)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void InventoryDescendentsHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + InventoryDescendentsPacket reply = (InventoryDescendentsPacket)packet; + + if (reply.AgentData.Descendents > 0) + { + // InventoryDescendantsReply sends a null folder if the parent doesnt contain any folders + if (reply.FolderData[0].FolderID != UUID.Zero) + { + // Iterate folders in this packet + for (int i = 0; i < reply.FolderData.Length; i++) + { + // If folder already exists then ignore, we assume the version cache + // logic is working and if the folder is stale then it should not be present. + + if (!_Store.Contains(reply.FolderData[i].FolderID)) + { + InventoryFolder folder = new InventoryFolder(reply.FolderData[i].FolderID); + folder.ParentUUID = reply.FolderData[i].ParentID; + folder.Name = Utils.BytesToString(reply.FolderData[i].Name); + folder.PreferredType = (AssetType)reply.FolderData[i].Type; + folder.OwnerID = reply.AgentData.OwnerID; + + _Store[folder.UUID] = folder; + } + } + } + + // InventoryDescendantsReply sends a null item if the parent doesnt contain any items. + if (reply.ItemData[0].ItemID != UUID.Zero) + { + // Iterate items in this packet + for (int i = 0; i < reply.ItemData.Length; i++) + { + if (reply.ItemData[i].ItemID != UUID.Zero) + { + InventoryItem item; + /* + * Objects that have been attached in-world prior to being stored on the + * asset server are stored with the InventoryType of 0 (Texture) + * instead of 17 (Attachment) + * + * This corrects that behavior by forcing Object Asset types that have an + * invalid InventoryType with the proper InventoryType of Attachment. + */ + if ((AssetType)reply.ItemData[i].Type == AssetType.Object + && (InventoryType)reply.ItemData[i].InvType == InventoryType.Texture) + { + item = CreateInventoryItem(InventoryType.Attachment, reply.ItemData[i].ItemID); + item.InventoryType = InventoryType.Attachment; + } + else + { + item = CreateInventoryItem((InventoryType)reply.ItemData[i].InvType, reply.ItemData[i].ItemID); + item.InventoryType = (InventoryType)reply.ItemData[i].InvType; + } + + item.ParentUUID = reply.ItemData[i].FolderID; + item.CreatorID = reply.ItemData[i].CreatorID; + item.AssetType = (AssetType)reply.ItemData[i].Type; + item.AssetUUID = reply.ItemData[i].AssetID; + item.CreationDate = Utils.UnixTimeToDateTime((uint)reply.ItemData[i].CreationDate); + item.Description = Utils.BytesToString(reply.ItemData[i].Description); + item.Flags = reply.ItemData[i].Flags; + item.Name = Utils.BytesToString(reply.ItemData[i].Name); + item.GroupID = reply.ItemData[i].GroupID; + item.GroupOwned = reply.ItemData[i].GroupOwned; + item.Permissions = new Permissions( + reply.ItemData[i].BaseMask, + reply.ItemData[i].EveryoneMask, + reply.ItemData[i].GroupMask, + reply.ItemData[i].NextOwnerMask, + reply.ItemData[i].OwnerMask); + item.SalePrice = reply.ItemData[i].SalePrice; + item.SaleType = (SaleType)reply.ItemData[i].SaleType; + item.OwnerID = reply.AgentData.OwnerID; + + _Store[item.UUID] = item; + } + } + } + } + + InventoryFolder parentFolder = null; + + if (_Store.Contains(reply.AgentData.FolderID) && + _Store[reply.AgentData.FolderID] is InventoryFolder) + { + parentFolder = _Store[reply.AgentData.FolderID] as InventoryFolder; + } + else + { + Logger.Log("Don't have a reference to FolderID " + reply.AgentData.FolderID.ToString() + + " or it is not a folder", Helpers.LogLevel.Error, Client); + return; + } + + if (reply.AgentData.Version < parentFolder.Version) + { + Logger.Log("Got an outdated InventoryDescendents packet for folder " + parentFolder.Name + + ", this version = " + reply.AgentData.Version + ", latest version = " + parentFolder.Version, + Helpers.LogLevel.Warning, Client); + return; + } + + parentFolder.Version = reply.AgentData.Version; + // FIXME: reply.AgentData.Descendants is not parentFolder.DescendentCount if we didn't + // request items and folders + parentFolder.DescendentCount = reply.AgentData.Descendents; + _Store.GetNodeFor(reply.AgentData.FolderID).NeedsUpdate = false; + + #region FindObjectsByPath Handling + + if (_Searches.Count > 0) + { + lock (_Searches) + { + StartSearch: + + // Iterate over all of the outstanding searches + for (int i = 0; i < _Searches.Count; i++) + { + InventorySearch search = _Searches[i]; + List folderContents = _Store.GetContents(search.Folder); + + // Iterate over all of the inventory objects in the base search folder + for (int j = 0; j < folderContents.Count; j++) + { + // Check if this inventory object matches the current path node + if (folderContents[j].Name == search.Path[search.Level]) + { + if (search.Level == search.Path.Length - 1) + { + Logger.DebugLog("Finished path search of " + String.Join("/", search.Path), Client); + + // This is the last node in the path, fire the callback and clean up + if (m_FindObjectByPathReply != null) + { + OnFindObjectByPathReply(new FindObjectByPathReplyEventArgs(String.Join("/", search.Path), + folderContents[j].UUID)); + } + + // Remove this entry and restart the loop since we are changing the collection size + _Searches.RemoveAt(i); + goto StartSearch; + } + else + { + // We found a match but it is not the end of the path, request the next level + Logger.DebugLog(String.Format("Matched level {0}/{1} in a path search of {2}", + search.Level, search.Path.Length - 1, String.Join("/", search.Path)), Client); + + search.Folder = folderContents[j].UUID; + search.Level++; + _Searches[i] = search; + + RequestFolderContents(search.Folder, search.Owner, true, true, + InventorySortOrder.ByName); + } + } + } + } + } + } + + #endregion FindObjectsByPath Handling + + // Callback for inventory folder contents being updated + OnFolderUpdated(new FolderUpdatedEventArgs(parentFolder.UUID, true)); + } + + /// + /// UpdateCreateInventoryItem packets are received when a new inventory item + /// is created. This may occur when an object that's rezzed in world is + /// taken into inventory, when an item is created using the CreateInventoryItem + /// packet, or when an object is purchased + /// + /// The sender + /// The EventArgs object containing the packet data + protected void UpdateCreateInventoryItemHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + UpdateCreateInventoryItemPacket reply = packet as UpdateCreateInventoryItemPacket; + + foreach (UpdateCreateInventoryItemPacket.InventoryDataBlock dataBlock in reply.InventoryData) + { + if (dataBlock.InvType == (sbyte)InventoryType.Folder) + { + Logger.Log("Received InventoryFolder in an UpdateCreateInventoryItem packet, this should not happen!", + Helpers.LogLevel.Error, Client); + continue; + } + + InventoryItem item = CreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID); + item.AssetType = (AssetType)dataBlock.Type; + item.AssetUUID = dataBlock.AssetID; + item.CreationDate = Utils.UnixTimeToDateTime(dataBlock.CreationDate); + item.CreatorID = dataBlock.CreatorID; + item.Description = Utils.BytesToString(dataBlock.Description); + item.Flags = dataBlock.Flags; + item.GroupID = dataBlock.GroupID; + item.GroupOwned = dataBlock.GroupOwned; + item.Name = Utils.BytesToString(dataBlock.Name); + item.OwnerID = dataBlock.OwnerID; + item.ParentUUID = dataBlock.FolderID; + item.Permissions = new Permissions( + dataBlock.BaseMask, + dataBlock.EveryoneMask, + dataBlock.GroupMask, + dataBlock.NextOwnerMask, + dataBlock.OwnerMask); + item.SalePrice = dataBlock.SalePrice; + item.SaleType = (SaleType)dataBlock.SaleType; + + /* + * When attaching new objects, an UpdateCreateInventoryItem packet will be + * returned by the server that has a FolderID/ParentUUID of zero. It is up + * to the client to make sure that the item gets a good folder, otherwise + * it will end up inaccesible in inventory. + */ + if (item.ParentUUID == UUID.Zero) + { + // assign default folder for type + item.ParentUUID = FindFolderForType(item.AssetType); + + Logger.Log("Received an item through UpdateCreateInventoryItem with no parent folder, assigning to folder " + + item.ParentUUID, Helpers.LogLevel.Info); + + // send update to the sim + RequestUpdateItem(item); + } + + // Update the local copy + _Store[item.UUID] = item; + + // Look for an "item created" callback + ItemCreatedCallback createdCallback; + if (_ItemCreatedCallbacks.TryGetValue(dataBlock.CallbackID, out createdCallback)) + { + _ItemCreatedCallbacks.Remove(dataBlock.CallbackID); + + try { createdCallback(true, item); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + // TODO: Is this callback even triggered when items are copied? + // Look for an "item copied" callback + ItemCopiedCallback copyCallback; + if (_ItemCopiedCallbacks.TryGetValue(dataBlock.CallbackID, out copyCallback)) + { + _ItemCopiedCallbacks.Remove(dataBlock.CallbackID); + + try { copyCallback(item); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + //This is triggered when an item is received from a task + if (m_TaskItemReceived != null) + { + OnTaskItemReceived(new TaskItemReceivedEventArgs(item.UUID, dataBlock.FolderID, + item.CreatorID, item.AssetUUID, item.InventoryType)); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void MoveInventoryItemHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + MoveInventoryItemPacket move = (MoveInventoryItemPacket)packet; + + for (int i = 0; i < move.InventoryData.Length; i++) + { + // FIXME: Do something here + string newName = Utils.BytesToString(move.InventoryData[i].NewName); + + Logger.Log(String.Format( + "MoveInventoryItemHandler: Item {0} is moving to Folder {1} with new name \"{2}\". Someone write this function!", + move.InventoryData[i].ItemID.ToString(), move.InventoryData[i].FolderID.ToString(), + newName), Helpers.LogLevel.Warning, Client); + } + } + + protected void BulkUpdateInventoryCapHandler(string capsKey, Interfaces.IMessage message, Simulator simulator) + { + BulkUpdateInventoryMessage msg = (BulkUpdateInventoryMessage)message; + + foreach (BulkUpdateInventoryMessage.FolderDataInfo newFolder in msg.FolderData) + { + if (newFolder.FolderID == UUID.Zero) continue; + + InventoryFolder folder; + if (!_Store.Contains(newFolder.FolderID)) + { + folder = new InventoryFolder(newFolder.FolderID); + } + else + { + folder = (InventoryFolder)_Store[newFolder.FolderID]; + } + + folder.Name = newFolder.Name; + folder.ParentUUID = newFolder.ParentID; + folder.PreferredType = newFolder.Type; + _Store[folder.UUID] = folder; + } + + foreach (BulkUpdateInventoryMessage.ItemDataInfo newItem in msg.ItemData) + { + if (newItem.ItemID == UUID.Zero) continue; + InventoryType invType = newItem.InvType; + + lock (_ItemInventoryTypeRequest) + { + InventoryType storedType = 0; + if (_ItemInventoryTypeRequest.TryGetValue(newItem.CallbackID, out storedType)) + { + _ItemInventoryTypeRequest.Remove(newItem.CallbackID); + invType = storedType; + } + } + InventoryItem item = SafeCreateInventoryItem(invType, newItem.ItemID); + + item.AssetType = newItem.Type; + item.AssetUUID = newItem.AssetID; + item.CreationDate = newItem.CreationDate; + item.CreatorID = newItem.CreatorID; + item.Description = newItem.Description; + item.Flags = newItem.Flags; + item.GroupID = newItem.GroupID; + item.GroupOwned = newItem.GroupOwned; + item.Name = newItem.Name; + item.OwnerID = newItem.OwnerID; + item.ParentUUID = newItem.FolderID; + item.Permissions.BaseMask = newItem.BaseMask; + item.Permissions.EveryoneMask = newItem.EveryoneMask; + item.Permissions.GroupMask = newItem.GroupMask; + item.Permissions.NextOwnerMask = newItem.NextOwnerMask; + item.Permissions.OwnerMask = newItem.OwnerMask; + item.SalePrice = newItem.SalePrice; + item.SaleType = newItem.SaleType; + + _Store[item.UUID] = item; + + // Look for an "item created" callback + ItemCreatedCallback callback; + if (_ItemCreatedCallbacks.TryGetValue(newItem.CallbackID, out callback)) + { + _ItemCreatedCallbacks.Remove(newItem.CallbackID); + + try { callback(true, item); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + // Look for an "item copied" callback + ItemCopiedCallback copyCallback; + if (_ItemCopiedCallbacks.TryGetValue(newItem.CallbackID, out copyCallback)) + { + _ItemCopiedCallbacks.Remove(newItem.CallbackID); + + try { copyCallback(item); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + } + + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void BulkUpdateInventoryHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + BulkUpdateInventoryPacket update = packet as BulkUpdateInventoryPacket; + + if (update.FolderData.Length > 0 && update.FolderData[0].FolderID != UUID.Zero) + { + foreach (BulkUpdateInventoryPacket.FolderDataBlock dataBlock in update.FolderData) + { + InventoryFolder folder; + if (!_Store.Contains(dataBlock.FolderID)) + { + folder = new InventoryFolder(dataBlock.FolderID); + } + else + { + folder = (InventoryFolder)_Store[dataBlock.FolderID]; + } + + if (dataBlock.Name != null) + { + folder.Name = Utils.BytesToString(dataBlock.Name); + } + folder.OwnerID = update.AgentData.AgentID; + folder.ParentUUID = dataBlock.ParentID; + _Store[folder.UUID] = folder; + } + } + + if (update.ItemData.Length > 0 && update.ItemData[0].ItemID != UUID.Zero) + { + for (int i = 0; i < update.ItemData.Length; i++) + { + BulkUpdateInventoryPacket.ItemDataBlock dataBlock = update.ItemData[i]; + + InventoryItem item = SafeCreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID); + + item.AssetType = (AssetType)dataBlock.Type; + if (dataBlock.AssetID != UUID.Zero) item.AssetUUID = dataBlock.AssetID; + item.CreationDate = Utils.UnixTimeToDateTime(dataBlock.CreationDate); + item.CreatorID = dataBlock.CreatorID; + item.Description = Utils.BytesToString(dataBlock.Description); + item.Flags = dataBlock.Flags; + item.GroupID = dataBlock.GroupID; + item.GroupOwned = dataBlock.GroupOwned; + item.Name = Utils.BytesToString(dataBlock.Name); + item.OwnerID = dataBlock.OwnerID; + item.ParentUUID = dataBlock.FolderID; + item.Permissions = new Permissions( + dataBlock.BaseMask, + dataBlock.EveryoneMask, + dataBlock.GroupMask, + dataBlock.NextOwnerMask, + dataBlock.OwnerMask); + item.SalePrice = dataBlock.SalePrice; + item.SaleType = (SaleType)dataBlock.SaleType; + + _Store[item.UUID] = item; + + // Look for an "item created" callback + ItemCreatedCallback callback; + if (_ItemCreatedCallbacks.TryGetValue(dataBlock.CallbackID, out callback)) + { + _ItemCreatedCallbacks.Remove(dataBlock.CallbackID); + + try { callback(true, item); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + // Look for an "item copied" callback + ItemCopiedCallback copyCallback; + if (_ItemCopiedCallbacks.TryGetValue(dataBlock.CallbackID, out copyCallback)) + { + _ItemCopiedCallbacks.Remove(dataBlock.CallbackID); + + try { copyCallback(item); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void FetchInventoryReplyHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + FetchInventoryReplyPacket reply = packet as FetchInventoryReplyPacket; + + foreach (FetchInventoryReplyPacket.InventoryDataBlock dataBlock in reply.InventoryData) + { + if (dataBlock.InvType == (sbyte)InventoryType.Folder) + { + Logger.Log("Received FetchInventoryReply for an inventory folder, this should not happen!", + Helpers.LogLevel.Error, Client); + continue; + } + + InventoryItem item = CreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID); + item.AssetType = (AssetType)dataBlock.Type; + item.AssetUUID = dataBlock.AssetID; + item.CreationDate = Utils.UnixTimeToDateTime(dataBlock.CreationDate); + item.CreatorID = dataBlock.CreatorID; + item.Description = Utils.BytesToString(dataBlock.Description); + item.Flags = dataBlock.Flags; + item.GroupID = dataBlock.GroupID; + item.GroupOwned = dataBlock.GroupOwned; + item.InventoryType = (InventoryType)dataBlock.InvType; + item.Name = Utils.BytesToString(dataBlock.Name); + item.OwnerID = dataBlock.OwnerID; + item.ParentUUID = dataBlock.FolderID; + item.Permissions = new Permissions( + dataBlock.BaseMask, + dataBlock.EveryoneMask, + dataBlock.GroupMask, + dataBlock.NextOwnerMask, + dataBlock.OwnerMask); + item.SalePrice = dataBlock.SalePrice; + item.SaleType = (SaleType)dataBlock.SaleType; + item.UUID = dataBlock.ItemID; + + _Store[item.UUID] = item; + + // Fire the callback for an item being fetched + OnItemReceived(new ItemReceivedEventArgs(item)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ReplyTaskInventoryHandler(object sender, PacketReceivedEventArgs e) + { + if (m_TaskInventoryReply != null) + { + Packet packet = e.Packet; + + ReplyTaskInventoryPacket reply = (ReplyTaskInventoryPacket)packet; + + OnTaskInventoryReply(new TaskInventoryReplyEventArgs(reply.InventoryData.TaskID, reply.InventoryData.Serial, + Utils.BytesToString(reply.InventoryData.Filename))); + } + } + + protected void ScriptRunningReplyMessageHandler(string capsKey, Interfaces.IMessage message, Simulator simulator) + { + if (m_ScriptRunningReply != null) + { + ScriptRunningReplyMessage msg = (ScriptRunningReplyMessage)message; + OnScriptRunningReply(new ScriptRunningReplyEventArgs(msg.ObjectID, msg.ItemID, msg.Mono, msg.Running)); + } + } + + #endregion Packet Handlers + } + + #region EventArgs + + public class InventoryObjectOfferedEventArgs : EventArgs + { + private readonly InstantMessage m_Offer; + private readonly AssetType m_AssetType; + private readonly UUID m_ObjectID; + private readonly bool m_FromTask; + + /// Set to true to accept offer, false to decline it + public bool Accept { get; set; } + /// The folder to accept the inventory into, if null default folder for will be used + public UUID FolderID { get; set; } + + public InstantMessage Offer { get { return m_Offer; } } + public AssetType AssetType { get { return m_AssetType; } } + public UUID ObjectID { get { return m_ObjectID; } } + public bool FromTask { get { return m_FromTask; } } + + public InventoryObjectOfferedEventArgs(InstantMessage offerDetails, AssetType type, UUID objectID, bool fromTask, UUID folderID) + { + this.Accept = false; + this.FolderID = folderID; + this.m_Offer = offerDetails; + this.m_AssetType = type; + this.m_ObjectID = objectID; + this.m_FromTask = fromTask; + } + } + + public class FolderUpdatedEventArgs : EventArgs + { + private readonly UUID m_FolderID; + public UUID FolderID { get { return m_FolderID; } } + private readonly bool m_Success; + public bool Success { get { return m_Success; } } + + public FolderUpdatedEventArgs(UUID folderID, bool success) + { + this.m_FolderID = folderID; + this.m_Success = success; + } + } + + public class ItemReceivedEventArgs : EventArgs + { + private readonly InventoryItem m_Item; + + public InventoryItem Item { get { return m_Item; } } + + public ItemReceivedEventArgs(InventoryItem item) + { + this.m_Item = item; + } + } + + public class FindObjectByPathReplyEventArgs : EventArgs + { + private readonly String m_Path; + private readonly UUID m_InventoryObjectID; + + public String Path { get { return m_Path; } } + public UUID InventoryObjectID { get { return m_InventoryObjectID; } } + + public FindObjectByPathReplyEventArgs(string path, UUID inventoryObjectID) + { + this.m_Path = path; + this.m_InventoryObjectID = inventoryObjectID; + } + } + + /// + /// Callback when an inventory object is accepted and received from a + /// task inventory. This is the callback in which you actually get + /// the ItemID, as in ObjectOfferedCallback it is null when received + /// from a task. + /// + public class TaskItemReceivedEventArgs : EventArgs + { + private readonly UUID m_ItemID; + private readonly UUID m_FolderID; + private readonly UUID m_CreatorID; + private readonly UUID m_AssetID; + private readonly InventoryType m_Type; + + public UUID ItemID { get { return m_ItemID; } } + public UUID FolderID { get { return m_FolderID; } } + public UUID CreatorID { get { return m_CreatorID; } } + public UUID AssetID { get { return m_AssetID; } } + public InventoryType Type { get { return m_Type; } } + + public TaskItemReceivedEventArgs(UUID itemID, UUID folderID, UUID creatorID, UUID assetID, InventoryType type) + { + this.m_ItemID = itemID; + this.m_FolderID = folderID; + this.m_CreatorID = creatorID; + this.m_AssetID = assetID; + this.m_Type = type; + } + } + + public class TaskInventoryReplyEventArgs : EventArgs + { + private readonly UUID m_ItemID; + private readonly Int16 m_Serial; + private readonly String m_AssetFilename; + + public UUID ItemID { get { return m_ItemID; } } + public Int16 Serial { get { return m_Serial; } } + public String AssetFilename { get { return m_AssetFilename; } } + + public TaskInventoryReplyEventArgs(UUID itemID, short serial, string assetFilename) + { + this.m_ItemID = itemID; + this.m_Serial = serial; + this.m_AssetFilename = assetFilename; + } + } + + public class SaveAssetToInventoryEventArgs : EventArgs + { + private readonly UUID m_ItemID; + private readonly UUID m_NewAssetID; + + public UUID ItemID { get { return m_ItemID; } } + public UUID NewAssetID { get { return m_NewAssetID; } } + + public SaveAssetToInventoryEventArgs(UUID itemID, UUID newAssetID) + { + this.m_ItemID = itemID; + this.m_NewAssetID = newAssetID; + } + } + + public class ScriptRunningReplyEventArgs : EventArgs + { + private readonly UUID m_ObjectID; + private readonly UUID m_ScriptID; + private readonly bool m_IsMono; + private readonly bool m_IsRunning; + + public UUID ObjectID { get { return m_ObjectID; } } + public UUID ScriptID { get { return m_ScriptID; } } + public bool IsMono { get { return m_IsMono; } } + public bool IsRunning { get { return m_IsRunning; } } + + public ScriptRunningReplyEventArgs(UUID objectID, UUID sctriptID, bool isMono, bool isRunning) + { + this.m_ObjectID = objectID; + this.m_ScriptID = sctriptID; + this.m_IsMono = isMono; + this.m_IsRunning = isRunning; + } + } + #endregion +} diff --git a/OpenMetaverse/InventoryNode.cs b/OpenMetaverse/InventoryNode.cs new file mode 100644 index 0000000..01de09e --- /dev/null +++ b/OpenMetaverse/InventoryNode.cs @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.Serialization; + +namespace OpenMetaverse +{ + [Serializable()] + public class InventoryNode : ISerializable + { + private InventoryBase data; + private InventoryNode parent; + private UUID parentID; //used for de-seralization + private InventoryNodeDictionary nodes; + private bool needsUpdate = true; + [NonSerialized] + private object tag; + + /// + public InventoryBase Data + { + get { return data; } + set { data = value; } + } + + /// User data + public object Tag + { + get { return tag; } + set { tag = value; } + } + + /// + public InventoryNode Parent + { + get { return parent; } + set { parent = value; } + } + + /// + public UUID ParentID + { + get { return parentID; } + } + + /// + public InventoryNodeDictionary Nodes + { + get + { + if (nodes == null) + nodes = new InventoryNodeDictionary(this); + + return nodes; + } + set { nodes = value; } + } + + + public System.DateTime ModifyTime + { + get + { + if (Data is InventoryItem) + { + return ((InventoryItem)Data).CreationDate; + } + DateTime newest = default(DateTime);//.MinValue; + if (Data is InventoryFolder) + { + foreach (var node in Nodes.Values) + { + var t = node.ModifyTime; + if (t > newest) newest = t; + } + } + return newest; + } + } + public void Sort() + { + Nodes.Sort(); + } + + /// + /// For inventory folder nodes specifies weather the folder needs to be + /// refreshed from the server + /// + public bool NeedsUpdate + { + get { return needsUpdate; } + set { needsUpdate = value; } + } + + /// + /// + /// + public InventoryNode() + { + } + + /// + /// + /// + /// + public InventoryNode(InventoryBase data) + { + this.data = data; + } + + /// + /// De-serialization constructor for the InventoryNode Class + /// + public InventoryNode(InventoryBase data, InventoryNode parent) + { + this.data = data; + this.parent = parent; + + if (parent != null) + { + // Add this node to the collection of parent nodes + lock (parent.Nodes.SyncRoot) parent.Nodes.Add(data.UUID, this); + } + } + + /// + /// Serialization handler for the InventoryNode Class + /// + public void GetObjectData(SerializationInfo info, StreamingContext ctxt) + { + if(parent!=null) + info.AddValue("Parent", parent.Data.UUID, typeof(UUID)); //We need to track the parent UUID for de-serialization + else + info.AddValue("Parent", UUID.Zero, typeof(UUID)); + + info.AddValue("Type", data.GetType(), typeof(Type)); + + data.GetObjectData(info, ctxt); + } + + /// + /// De-serialization handler for the InventoryNode Class + /// + public InventoryNode(SerializationInfo info, StreamingContext ctxt) + { + parentID = (UUID)info.GetValue("Parent", typeof(UUID)); + Type type = (Type)info.GetValue("Type", typeof(Type)); + + // Construct a new inventory object based on the Type stored in Type + System.Reflection.ConstructorInfo ctr = type.GetConstructor(new Type[] {typeof(SerializationInfo),typeof(StreamingContext)}); + data = (InventoryBase) ctr.Invoke(new Object[] { info, ctxt }); + } + + /// + /// + /// + /// + public override string ToString() + { + if (this.Data == null) return "[Empty Node]"; + return this.Data.ToString(); + } + } +} diff --git a/OpenMetaverse/InventoryNodeDictionary.cs b/OpenMetaverse/InventoryNodeDictionary.cs new file mode 100644 index 0000000..5996120 --- /dev/null +++ b/OpenMetaverse/InventoryNodeDictionary.cs @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse +{ + public class InventoryNodeDictionary: IComparer + { + protected SortedDictionary SDictionary; + protected Dictionary Dictionary = new Dictionary(); + protected InventoryNode parent; + protected object syncRoot = new object(); + public int Compare(UUID id1, UUID id2) + { + InventoryNode n1 = Get(id1); + InventoryNode n2 = Get(id2); + int diff = NullCompare(n1, n2); + if (diff != 0) return diff; + if (n1 == null) return id1.CompareTo(id2); + DateTime t1 = n1.ModifyTime; + DateTime t2 = n2.ModifyTime; + diff = t1.CompareTo(t2); + if (diff != 0) return diff; + var d1 = n1.Data; + var d2 = n2.Data; + diff = NullCompare(d1, d2); + if (diff != 0) return diff; + if (d1 != null) + { + diff = NullCompare(d1.Name, d2.Name); + if (diff != 0) return diff; + if (d1.Name != null) + { + // both are not null.. due to NullCoimpare code + diff = d1.Name.CompareTo(d2.Name); + if (diff != 0) return diff; + } + } + return id1.CompareTo(id2); + } + + private InventoryNode Get(UUID uuid) + { + InventoryNode val; + if (Dictionary.TryGetValue(uuid, out val)) + { + return val; + } + return null; + } + + static int NullCompare(object o1, object o2) + { + return ReferenceEquals(o1, null).CompareTo(ReferenceEquals(o2, null)); + } + + public InventoryNode Parent + { + get { return parent; } + set { parent = value; } + } + + public object SyncRoot { get { return syncRoot; } } + + public int Count { get { return Dictionary.Count; } } + + public InventoryNodeDictionary(InventoryNode parentNode) + { + if (Settings.SORT_INVENTORY) SDictionary = new SortedDictionary(this); + parent = parentNode; + } + + public InventoryNode this[UUID key] + { + get { return (InventoryNode)this.Dictionary[key]; } + set + { + value.Parent = parent; + lock (syncRoot) + { + Dictionary[key] = value; + if (Settings.SORT_INVENTORY) this.SDictionary[key] = value; + } + } + } + + public ICollection Keys + { + get + { + if (Settings.SORT_INVENTORY) return this.SDictionary.Keys; + return Dictionary.Keys; + } + } + public ICollection Values + { + get + { + if (Settings.SORT_INVENTORY) return this.SDictionary.Values; + return this.Dictionary.Values; + } + } + + public void Add(UUID key, InventoryNode value) + { + value.Parent = parent; + lock (syncRoot) + { + Dictionary[key] = value; + if (Settings.SORT_INVENTORY) this.SDictionary.Add(key, value); + } + } + + public void Remove(UUID key) + { + lock (syncRoot) + { + this.Dictionary.Remove(key); + if (Settings.SORT_INVENTORY) this.SDictionary.Remove(key); + } + } + + public bool Contains(UUID key) + { + return this.Dictionary.ContainsKey(key); + } + + internal void Sort() + { + if (Settings.SORT_INVENTORY) + { + // TODO resort SDictionary now that more data has come? + } + } + } +} diff --git a/OpenMetaverse/Logger.cs b/OpenMetaverse/Logger.cs new file mode 100644 index 0000000..1e6b3f9 --- /dev/null +++ b/OpenMetaverse/Logger.cs @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using log4net; +using log4net.Config; + +[assembly: log4net.Config.XmlConfigurator(Watch = true)] + +namespace OpenMetaverse +{ + /// + /// Singleton logging class for the entire library + /// + public static class Logger + { + /// + /// Callback used for client apps to receive log messages from + /// the library + /// + /// Data being logged + /// The severity of the log entry from + public delegate void LogCallback(object message, Helpers.LogLevel level); + + /// Triggered whenever a message is logged. If this is left + /// null, log messages will go to the console + public static event LogCallback OnLogMessage; + + /// log4net logging engine + public static ILog LogInstance; + + /// + /// Default constructor + /// + static Logger() + { + LogInstance = LogManager.GetLogger("OpenMetaverse"); + + // If error level reporting isn't enabled we assume no logger is configured and initialize a default + // ConsoleAppender + if (!LogInstance.Logger.IsEnabledFor(log4net.Core.Level.Error)) + { + log4net.Appender.ConsoleAppender appender = new log4net.Appender.ConsoleAppender(); + appender.Layout = new log4net.Layout.PatternLayout("%timestamp [%thread] %-5level - %message%newline"); + BasicConfigurator.Configure(appender); + + if(Settings.LOG_LEVEL != Helpers.LogLevel.None) + LogInstance.Info("No log configuration found, defaulting to console logging"); + } + } + + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + public static void Log(object message, Helpers.LogLevel level) + { + Log(message, level, null, null); + } + + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + /// Instance of the client + public static void Log(object message, Helpers.LogLevel level, GridClient client) + { + Log(message, level, client, null); + } + + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + /// Exception that was raised + public static void Log(object message, Helpers.LogLevel level, Exception exception) + { + Log(message, level, null, exception); + } + + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + /// Instance of the client + /// Exception that was raised + public static void Log(object message, Helpers.LogLevel level, GridClient client, Exception exception) + { + if (client != null && client.Settings.LOG_NAMES) + message = String.Format("<{0}>: {1}", client.Self.Name, message); + + if (OnLogMessage != null) + OnLogMessage(message, level); + + switch (level) + { + case Helpers.LogLevel.Debug: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug) + LogInstance.Debug(message, exception); + break; + case Helpers.LogLevel.Info: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug + || Settings.LOG_LEVEL == Helpers.LogLevel.Info) + LogInstance.Info(message, exception); + break; + case Helpers.LogLevel.Warning: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug + || Settings.LOG_LEVEL == Helpers.LogLevel.Info + || Settings.LOG_LEVEL == Helpers.LogLevel.Warning) + LogInstance.Warn(message, exception); + break; + case Helpers.LogLevel.Error: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug + || Settings.LOG_LEVEL == Helpers.LogLevel.Info + || Settings.LOG_LEVEL == Helpers.LogLevel.Warning + || Settings.LOG_LEVEL == Helpers.LogLevel.Error) + LogInstance.Error(message, exception); + break; + default: + break; + } + } + + /// + /// If the library is compiled with DEBUG defined, an event will be + /// fired if an OnLogMessage handler is registered and the + /// message will be sent to the logging engine + /// + /// The message to log at the DEBUG level to the + /// current logging engine + public static void DebugLog(object message) + { + DebugLog(message, null); + } + + /// + /// If the library is compiled with DEBUG defined and + /// GridClient.Settings.DEBUG is true, an event will be + /// fired if an OnLogMessage handler is registered and the + /// message will be sent to the logging engine + /// + /// The message to log at the DEBUG level to the + /// current logging engine + /// Instance of the client + [System.Diagnostics.Conditional("DEBUG")] + public static void DebugLog(object message, GridClient client) + { + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug) + { + if (client != null && client.Settings.LOG_NAMES) + message = String.Format("<{0}>: {1}", client.Self.Name, message); + + if (OnLogMessage != null) + OnLogMessage(message, Helpers.LogLevel.Debug); + + LogInstance.Debug(message); + } + } + } +} diff --git a/OpenMetaverse/Login.cs b/OpenMetaverse/Login.cs new file mode 100644 index 0000000..235cec9 --- /dev/null +++ b/OpenMetaverse/Login.cs @@ -0,0 +1,1640 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.IO; +using System.Net; +using System.Xml; +using System.Security.Cryptography.X509Certificates; +using Nwc.XmlRpc; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// + /// + public enum LoginStatus + { + /// + Failed = -1, + /// + None = 0, + /// + ConnectingToLogin, + /// + ReadingResponse, + /// + ConnectingToSim, + /// + Redirecting, + /// + Success + } + + /// + /// Status of the last application run. + /// Used for error reporting to the grid login service for statistical purposes. + /// + public enum LastExecStatus + { + /// Application exited normally + Normal = 0, + /// Application froze + Froze, + /// Application detected error and exited abnormally + ForcedCrash, + /// Other crash + OtherCrash, + /// Application froze during logout + LogoutFroze, + /// Application crashed during logout + LogoutCrash + } + + #endregion Enums + + #region Structs + + /// + /// Login Request Parameters + /// + public class LoginParams + { + /// The URL of the Login Server + public string URI; + /// The number of milliseconds to wait before a login is considered + /// failed due to timeout + public int Timeout; + /// The request method + /// login_to_simulator is currently the only supported method + public string MethodName; + /// The Agents First name + public string FirstName; + /// The Agents Last name + public string LastName; + /// A md5 hashed password + /// plaintext password will be automatically hashed + public string Password; + /// The agents starting location once logged in + /// Either "last", "home", or a string encoded URI + /// containing the simulator name and x/y/z coordinates e.g: uri:hooper&128&152&17 + public string Start; + /// A string containing the client software channel information + /// Second Life Release + public string Channel; + /// The client software version information + /// The official viewer uses: Second Life Release n.n.n.n + /// where n is replaced with the current version of the viewer + public string Version; + /// A string containing the platform information the agent is running on + public string Platform; + /// A string hash of the network cards Mac Address + public string MAC; + /// Unknown or deprecated + public string ViewerDigest; + /// A string hash of the first disk drives ID used to identify this clients uniqueness + public string ID0; + /// A string containing the viewers Software, this is not directly sent to the login server but + /// instead is used to generate the Version string + public string UserAgent; + /// A string representing the software creator. This is not directly sent to the login server but + /// is used by the library to generate the Version information + public string Author; + /// If true, this agent agrees to the Terms of Service of the grid its connecting to + public bool AgreeToTos; + /// Unknown + public bool ReadCritical; + /// Status of the last application run sent to the grid login server for statistical purposes + public LastExecStatus LastExecEvent = LastExecStatus.Normal; + + /// An array of string sent to the login server to enable various options + public string[] Options; + + /// A randomly generated ID to distinguish between login attempts. This value is only used + /// internally in the library and is never sent over the wire + internal UUID LoginID; + + /// + /// Default constuctor, initializes sane default values + /// + public LoginParams() + { + List options = new List(16); + options.Add("inventory-root"); + options.Add("inventory-skeleton"); + options.Add("inventory-lib-root"); + options.Add("inventory-lib-owner"); + options.Add("inventory-skel-lib"); + options.Add("initial-outfit"); + options.Add("gestures"); + options.Add("event_categories"); + options.Add("event_notifications"); + options.Add("classified_categories"); + options.Add("buddy-list"); + options.Add("ui-config"); + options.Add("tutorial_settings"); + options.Add("login-flags"); + options.Add("global-textures"); + options.Add("adult_compliant"); + + this.Options = options.ToArray(); + this.MethodName = "login_to_simulator"; + this.Start = "last"; + this.Platform = NetworkManager.GetPlatform(); + this.MAC = NetworkManager.GetMAC(); + this.ViewerDigest = String.Empty; + this.ID0 = NetworkManager.GetMAC(); + this.AgreeToTos = true; + this.ReadCritical = true; + this.LastExecEvent = LastExecStatus.Normal; + } + + /// + /// Instantiates new LoginParams object and fills in the values + /// + /// Instance of GridClient to read settings from + /// Login first name + /// Login last name + /// Password + /// Login channnel (application name) + /// Client version, should be application name + version number + public LoginParams(GridClient client, string firstName, string lastName, string password, string channel, string version) + : this() + { + this.URI = client.Settings.LOGIN_SERVER; + this.Timeout = client.Settings.LOGIN_TIMEOUT; + this.FirstName = firstName; + this.LastName = lastName; + this.Password = password; + this.Channel = channel; + this.Version = version; + } + + /// + /// Instantiates new LoginParams object and fills in the values + /// + /// Instance of GridClient to read settings from + /// Login first name + /// Login last name + /// Password + /// Login channnel (application name) + /// Client version, should be application name + version number + /// URI of the login server + public LoginParams(GridClient client, string firstName, string lastName, string password, string channel, string version, string loginURI) + : this(client, firstName, lastName, password, channel, version) + { + this.URI = loginURI; + } + } + + public struct BuddyListEntry + { + public int buddy_rights_given; + public string buddy_id; + public int buddy_rights_has; + } + + /// + /// The decoded data returned from the login server after a successful login + /// + public struct LoginResponseData + { + /// true, false, indeterminate + //[XmlRpcMember("login")] + public string Login; + public bool Success; + public string Reason; + /// Login message of the day + public string Message; + public UUID AgentID; + public UUID SessionID; + public UUID SecureSessionID; + public string FirstName; + public string LastName; + public string StartLocation; + /// M or PG, also agent_region_access and agent_access_max + public string AgentAccess; + public Vector3 LookAt; + public ulong HomeRegion; + public Vector3 HomePosition; + public Vector3 HomeLookAt; + public int CircuitCode; + public int RegionX; + public int RegionY; + public int SimPort; + public IPAddress SimIP; + public string SeedCapability; + public BuddyListEntry[] BuddyList; + public int SecondsSinceEpoch; + public string UDPBlacklist; + + #region Inventory + + public UUID InventoryRoot; + public UUID LibraryRoot; + public InventoryFolder[] InventorySkeleton; + public InventoryFolder[] LibrarySkeleton; + public UUID LibraryOwner; + + #endregion + + #region Redirection + + public string NextMethod; + public string NextUrl; + public string[] NextOptions; + public int NextDuration; + + #endregion + + // These aren't currently being utilized by the library + public string AgentAccessMax; + public string AgentRegionAccess; + public int AOTransition; + public string InventoryHost; + public int MaxAgentGroups; + public string OpenIDUrl; + public string AgentAppearanceServiceURL; + public uint COFVersion; + public string InitialOutfit; + public bool FirstLogin; + + /// + /// Parse LLSD Login Reply Data + /// + /// An + /// contaning the login response data + /// XML-RPC logins do not require this as XML-RPC.NET + /// automatically populates the struct properly using attributes + public void Parse(OSDMap reply) + { + try + { + AgentID = ParseUUID("agent_id", reply); + SessionID = ParseUUID("session_id", reply); + SecureSessionID = ParseUUID("secure_session_id", reply); + FirstName = ParseString("first_name", reply).Trim('"'); + LastName = ParseString("last_name", reply).Trim('"'); + StartLocation = ParseString("start_location", reply); + AgentAccess = ParseString("agent_access", reply); + LookAt = ParseVector3("look_at", reply); + Reason = ParseString("reason", reply); + Message = ParseString("message", reply); + + Login = reply["login"].AsString(); + Success = reply["login"].AsBoolean(); + } + catch (OSDException e) + { + Logger.Log("Login server returned (some) invalid data: " + e.Message, Helpers.LogLevel.Warning); + } + + // Home + OSDMap home = null; + OSD osdHome = OSDParser.DeserializeLLSDNotation(reply["home"].AsString()); + + if (osdHome.Type == OSDType.Map) + { + home = (OSDMap)osdHome; + + OSD homeRegion; + if (home.TryGetValue("region_handle", out homeRegion) && homeRegion.Type == OSDType.Array) + { + OSDArray homeArray = (OSDArray)homeRegion; + if (homeArray.Count == 2) + HomeRegion = Utils.UIntsToLong((uint)homeArray[0].AsInteger(), (uint)homeArray[1].AsInteger()); + else + HomeRegion = 0; + } + + HomePosition = ParseVector3("position", home); + HomeLookAt = ParseVector3("look_at", home); + } + else + { + HomeRegion = 0; + HomePosition = Vector3.Zero; + HomeLookAt = Vector3.Zero; + } + + CircuitCode = (int)ParseUInt("circuit_code", reply); + RegionX = (int)ParseUInt("region_x", reply); + RegionY = (int)ParseUInt("region_y", reply); + SimPort = (short)ParseUInt("sim_port", reply); + string simIP = ParseString("sim_ip", reply); + IPAddress.TryParse(simIP, out SimIP); + SeedCapability = ParseString("seed_capability", reply); + + // Buddy list + OSD buddyLLSD; + if (reply.TryGetValue("buddy-list", out buddyLLSD) && buddyLLSD.Type == OSDType.Array) + { + List buddys = new List(); + OSDArray buddyArray = (OSDArray)buddyLLSD; + for (int i = 0; i < buddyArray.Count; i++) + { + if (buddyArray[i].Type == OSDType.Map) + { + BuddyListEntry bud = new BuddyListEntry(); + OSDMap buddy = (OSDMap)buddyArray[i]; + + bud.buddy_id = buddy["buddy_id"].AsString(); + bud.buddy_rights_given = (int)ParseUInt("buddy_rights_given", buddy); + bud.buddy_rights_has = (int)ParseUInt("buddy_rights_has", buddy); + + buddys.Add(bud); + } + BuddyList = buddys.ToArray(); + } + } + + SecondsSinceEpoch = (int)ParseUInt("seconds_since_epoch", reply); + + InventoryRoot = ParseMappedUUID("inventory-root", "folder_id", reply); + InventorySkeleton = ParseInventorySkeleton("inventory-skeleton", reply); + + LibraryOwner = ParseMappedUUID("inventory-lib-owner", "agent_id", reply); + LibraryRoot = ParseMappedUUID("inventory-lib-root", "folder_id", reply); + LibrarySkeleton = ParseInventorySkeleton("inventory-skel-lib", reply); + } + + public void Parse(Hashtable reply) + { + try + { + AgentID = ParseUUID("agent_id", reply); + SessionID = ParseUUID("session_id", reply); + SecureSessionID = ParseUUID("secure_session_id", reply); + FirstName = ParseString("first_name", reply).Trim('"'); + LastName = ParseString("last_name", reply).Trim('"'); + // "first_login" for brand new accounts + StartLocation = ParseString("start_location", reply); + AgentAccess = ParseString("agent_access", reply); + LookAt = ParseVector3("look_at", reply); + Reason = ParseString("reason", reply); + Message = ParseString("message", reply); + + if (reply.ContainsKey("login")) + { + Login = (string)reply["login"]; + Success = Login == "true"; + + // Parse redirect options + if (Login == "indeterminate") + { + NextUrl = ParseString("next_url", reply); + NextDuration = (int)ParseUInt("next_duration", reply); + NextMethod = ParseString("next_method", reply); + NextOptions = (string[])((ArrayList)reply["next_options"]).ToArray(typeof(string)); + } + } + } + catch (Exception e) + { + Logger.Log("Login server returned (some) invalid data: " + e.Message, Helpers.LogLevel.Warning); + } + if (!Success) + return; + + // Home + OSDMap home = null; + if (reply.ContainsKey("home")) + { + OSD osdHome = OSDParser.DeserializeLLSDNotation(reply["home"].ToString()); + + if (osdHome.Type == OSDType.Map) + { + home = (OSDMap)osdHome; + + OSD homeRegion; + if (home.TryGetValue("region_handle", out homeRegion) && homeRegion.Type == OSDType.Array) + { + OSDArray homeArray = (OSDArray)homeRegion; + if (homeArray.Count == 2) + HomeRegion = Utils.UIntsToLong((uint)homeArray[0].AsInteger(), + (uint)homeArray[1].AsInteger()); + else + HomeRegion = 0; + } + + HomePosition = ParseVector3("position", home); + HomeLookAt = ParseVector3("look_at", home); + } + } + else + { + HomeRegion = 0; + HomePosition = Vector3.Zero; + HomeLookAt = Vector3.Zero; + } + + CircuitCode = (int)ParseUInt("circuit_code", reply); + RegionX = (int)ParseUInt("region_x", reply); + RegionY = (int)ParseUInt("region_y", reply); + SimPort = (short)ParseUInt("sim_port", reply); + string simIP = ParseString("sim_ip", reply); + IPAddress.TryParse(simIP, out SimIP); + SeedCapability = ParseString("seed_capability", reply); + + // Buddy list + if (reply.ContainsKey("buddy-list") && reply["buddy-list"] is ArrayList) + { + List buddys = new List(); + + ArrayList buddyArray = (ArrayList)reply["buddy-list"]; + for (int i = 0; i < buddyArray.Count; i++) + { + if (buddyArray[i] is Hashtable) + { + BuddyListEntry bud = new BuddyListEntry(); + Hashtable buddy = (Hashtable)buddyArray[i]; + + bud.buddy_id = ParseString("buddy_id", buddy); + bud.buddy_rights_given = (int)ParseUInt("buddy_rights_given", buddy); + bud.buddy_rights_has = (int)ParseUInt("buddy_rights_has", buddy); + + buddys.Add(bud); + } + } + + BuddyList = buddys.ToArray(); + } + + SecondsSinceEpoch = (int)ParseUInt("seconds_since_epoch", reply); + + InventoryRoot = ParseMappedUUID("inventory-root", "folder_id", reply); + InventorySkeleton = ParseInventorySkeleton("inventory-skeleton", reply); + + LibraryOwner = ParseMappedUUID("inventory-lib-owner", "agent_id", reply); + LibraryRoot = ParseMappedUUID("inventory-lib-root", "folder_id", reply); + LibrarySkeleton = ParseInventorySkeleton("inventory-skel-lib", reply); + + // UDP Blacklist + if (reply.ContainsKey("udp_blacklist")) + { + UDPBlacklist = ParseString("udp_blacklist", reply); + } + + if (reply.ContainsKey("max-agent-groups")) + { + MaxAgentGroups = (int)ParseUInt("max-agent-groups", reply); + } + else + { + MaxAgentGroups = -1; + } + + if (reply.ContainsKey("openid_url")) + { + OpenIDUrl = ParseString("openid_url", reply); + } + + if (reply.ContainsKey("agent_appearance_service")) + { + AgentAppearanceServiceURL = ParseString("agent_appearance_service", reply); + } + + COFVersion = 0; + if (reply.ContainsKey("cof_version")) + { + COFVersion = ParseUInt("cof_version", reply); + } + + InitialOutfit = string.Empty; + if (reply.ContainsKey("initial-outfit") && reply["initial-outfit"] is ArrayList) + { + ArrayList array = (ArrayList)reply["initial-outfit"]; + for (int i = 0; i < array.Count; i++) + { + if (array[i] is Hashtable) + { + Hashtable map = (Hashtable)array[i]; + InitialOutfit = ParseString("folder_name", map); + } + } + } + + FirstLogin = false; + if (reply.ContainsKey("login-flags") && reply["login-flags"] is ArrayList) + { + ArrayList array = (ArrayList)reply["login-flags"]; + for (int i = 0; i < array.Count; i++) + { + if (array[i] is Hashtable) + { + Hashtable map = (Hashtable)array[i]; + FirstLogin = ParseString("ever_logged_in", map) == "N"; + } + } + } + + + } + + #region Parsing Helpers + + public static uint ParseUInt(string key, OSDMap reply) + { + OSD osd; + if (reply.TryGetValue(key, out osd)) + return osd.AsUInteger(); + else + return 0; + } + + public static uint ParseUInt(string key, Hashtable reply) + { + if (reply.ContainsKey(key)) + { + object value = reply[key]; + if (value is int) + return (uint)(int)value; + } + + return 0; + } + + public static UUID ParseUUID(string key, OSDMap reply) + { + OSD osd; + if (reply.TryGetValue(key, out osd)) + return osd.AsUUID(); + else + return UUID.Zero; + } + + public static UUID ParseUUID(string key, Hashtable reply) + { + if (reply.ContainsKey(key)) + { + UUID value; + if (UUID.TryParse((string)reply[key], out value)) + return value; + } + + return UUID.Zero; + } + + public static string ParseString(string key, OSDMap reply) + { + OSD osd; + if (reply.TryGetValue(key, out osd)) + return osd.AsString(); + else + return String.Empty; + } + + public static string ParseString(string key, Hashtable reply) + { + if (reply.ContainsKey(key)) + return String.Format("{0}", reply[key]); + + return String.Empty; + } + + public static Vector3 ParseVector3(string key, OSDMap reply) + { + OSD osd; + if (reply.TryGetValue(key, out osd)) + { + if (osd.Type == OSDType.Array) + { + return ((OSDArray)osd).AsVector3(); + } + else if (osd.Type == OSDType.String) + { + OSDArray array = (OSDArray)OSDParser.DeserializeLLSDNotation(osd.AsString()); + return array.AsVector3(); + } + } + + return Vector3.Zero; + } + + public static Vector3 ParseVector3(string key, Hashtable reply) + { + if (reply.ContainsKey(key)) + { + object value = reply[key]; + + if (value is IList) + { + IList list = (IList)value; + if (list.Count == 3) + { + float x, y, z; + Single.TryParse((string)list[0], out x); + Single.TryParse((string)list[1], out y); + Single.TryParse((string)list[2], out z); + + return new Vector3(x, y, z); + } + } + else if (value is string) + { + OSDArray array = (OSDArray)OSDParser.DeserializeLLSDNotation((string)value); + return array.AsVector3(); + } + } + + return Vector3.Zero; + } + + public static UUID ParseMappedUUID(string key, string key2, OSDMap reply) + { + OSD folderOSD; + if (reply.TryGetValue(key, out folderOSD) && folderOSD.Type == OSDType.Array) + { + OSDArray array = (OSDArray)folderOSD; + if (array.Count == 1 && array[0].Type == OSDType.Map) + { + OSDMap map = (OSDMap)array[0]; + OSD folder; + if (map.TryGetValue(key2, out folder)) + return folder.AsUUID(); + } + } + + return UUID.Zero; + } + + public static UUID ParseMappedUUID(string key, string key2, Hashtable reply) + { + if (reply.ContainsKey(key) && reply[key] is ArrayList) + { + ArrayList array = (ArrayList)reply[key]; + if (array.Count == 1 && array[0] is Hashtable) + { + Hashtable map = (Hashtable)array[0]; + return ParseUUID(key2, map); + } + } + + return UUID.Zero; + } + + public static InventoryFolder[] ParseInventoryFolders(string key, UUID owner, OSDMap reply) + { + List folders = new List(); + + OSD skeleton; + if (reply.TryGetValue(key, out skeleton) && skeleton.Type == OSDType.Array) + { + OSDArray array = (OSDArray)skeleton; + + for (int i = 0; i < array.Count; i++) + { + if (array[i].Type == OSDType.Map) + { + OSDMap map = (OSDMap)array[i]; + InventoryFolder folder = new InventoryFolder(map["folder_id"].AsUUID()); + folder.PreferredType = (AssetType)map["type_default"].AsInteger(); + folder.Version = map["version"].AsInteger(); + folder.OwnerID = owner; + folder.ParentUUID = map["parent_id"].AsUUID(); + folder.Name = map["name"].AsString(); + + folders.Add(folder); + } + } + } + + return folders.ToArray(); + } + + public InventoryFolder[] ParseInventorySkeleton(string key, OSDMap reply) + { + List folders = new List(); + + OSD skeleton; + if (reply.TryGetValue(key, out skeleton) && skeleton.Type == OSDType.Array) + { + OSDArray array = (OSDArray)skeleton; + for (int i = 0; i < array.Count; i++) + { + if (array[i].Type == OSDType.Map) + { + OSDMap map = (OSDMap)array[i]; + InventoryFolder folder = new InventoryFolder(map["folder_id"].AsUUID()); + folder.Name = map["name"].AsString(); + folder.ParentUUID = map["parent_id"].AsUUID(); + folder.PreferredType = (AssetType)map["type_default"].AsInteger(); + folder.Version = map["version"].AsInteger(); + folders.Add(folder); + } + } + } + return folders.ToArray(); + } + + public InventoryFolder[] ParseInventorySkeleton(string key, Hashtable reply) + { + UUID ownerID; + if (key.Equals("inventory-skel-lib")) + ownerID = LibraryOwner; + else + ownerID = AgentID; + + List folders = new List(); + + if (reply.ContainsKey(key) && reply[key] is ArrayList) + { + ArrayList array = (ArrayList)reply[key]; + for (int i = 0; i < array.Count; i++) + { + if (array[i] is Hashtable) + { + Hashtable map = (Hashtable)array[i]; + InventoryFolder folder = new InventoryFolder(ParseUUID("folder_id", map)); + folder.Name = ParseString("name", map); + folder.ParentUUID = ParseUUID("parent_id", map); + folder.PreferredType = (AssetType)ParseUInt("type_default", map); + folder.Version = (int)ParseUInt("version", map); + folder.OwnerID = ownerID; + + folders.Add(folder); + } + } + } + + return folders.ToArray(); + } + + #endregion Parsing Helpers + } + + #endregion Structs + + /// + /// Login Routines + /// + public partial class NetworkManager + { + #region Delegates + + + //////LoginProgress + //// LoginProgress + /// The event subscribers, null of no subscribers + private EventHandler m_LoginProgress; + + ///Raises the LoginProgress Event + /// A LoginProgressEventArgs object containing + /// the data sent from the simulator + protected virtual void OnLoginProgress(LoginProgressEventArgs e) + { + EventHandler handler = m_LoginProgress; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_LoginProgressLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler LoginProgress + { + add { lock (m_LoginProgressLock) { m_LoginProgress += value; } } + remove { lock (m_LoginProgressLock) { m_LoginProgress -= value; } } + } + + ///// The event subscribers, null of no subscribers + //private EventHandler m_LoggedIn; + + /////Raises the LoggedIn Event + ///// A LoggedInEventArgs object containing + ///// the data sent from the simulator + //protected virtual void OnLoggedIn(LoggedInEventArgs e) + //{ + // EventHandler handler = m_LoggedIn; + // if (handler != null) + // handler(this, e); + //} + + ///// Thread sync lock object + //private readonly object m_LoggedInLock = new object(); + + ///// Raised when the simulator sends us data containing + ///// ... + //public event EventHandler LoggedIn + //{ + // add { lock (m_LoggedInLock) { m_LoggedIn += value; } } + // remove { lock (m_LoggedInLock) { m_LoggedIn -= value; } } + //} + + /// + /// + /// + /// + /// + /// + /// + /// + public delegate void LoginResponseCallback(bool loginSuccess, bool redirect, string message, string reason, LoginResponseData replyData); + + #endregion Delegates + + #region Events + + /// Called when a reply is received from the login server, the + /// login sequence will block until this event returns + private event LoginResponseCallback OnLoginResponse; + + #endregion Events + + #region Public Members + /// Seed CAPS URL returned from the login server + public string LoginSeedCapability = String.Empty; + /// Current state of logging in + public LoginStatus LoginStatusCode { get { return InternalStatusCode; } } + /// Upon login failure, contains a short string key for the + /// type of login error that occurred + public string LoginErrorKey { get { return InternalErrorKey; } } + /// The raw XML-RPC reply from the login server, exactly as it + /// was received (minus the HTTP header) + public string RawLoginReply { get { return InternalRawLoginReply; } } + /// During login this contains a descriptive version of + /// LoginStatusCode. After a successful login this will contain the + /// message of the day, and after a failed login a descriptive error + /// message will be returned + public string LoginMessage { get { return InternalLoginMessage; } } + /// Maximum number of groups an agent can belong to, -1 for unlimited + public int MaxAgentGroups = -1; + /// Server side baking service URL + public string AgentAppearanceServiceURL; + /// Parsed login response data + public LoginResponseData LoginResponseData; + #endregion + + #region Private Members + private LoginParams CurrentContext = null; + private AutoResetEvent LoginEvent = new AutoResetEvent(false); + private LoginStatus InternalStatusCode = LoginStatus.None; + private string InternalErrorKey = String.Empty; + private string InternalLoginMessage = String.Empty; + private string InternalRawLoginReply = String.Empty; + private Dictionary CallbackOptions = new Dictionary(); + + /// A list of packets obtained during the login process which + /// networkmanager will log but not process + private readonly List UDPBlacklist = new List(); + #endregion + + #region Public Methods + + /// + /// Generate sane default values for a login request + /// + /// Account first name + /// Account last name + /// Account password + /// Client application name (channel) + /// Client application name + version + /// A populated struct containing + /// sane defaults + public LoginParams DefaultLoginParams(string firstName, string lastName, string password, + string channel, string version) + { + return new LoginParams(Client, firstName, lastName, password, channel, version); + } + + /// + /// Simplified login that takes the most common and required fields + /// + /// Account first name + /// Account last name + /// Account password + /// Client application name (channel) + /// Client application name + version + /// Whether the login was successful or not. On failure the + /// LoginErrorKey string will contain the error code and LoginMessage + /// will contain a description of the error + public bool Login(string firstName, string lastName, string password, string channel, string version) + { + return Login(firstName, lastName, password, channel, "last", version); + } + + /// + /// Simplified login that takes the most common fields along with a + /// starting location URI, and can accept an MD5 string instead of a + /// plaintext password + /// + /// Account first name + /// Account last name + /// Account password or MD5 hash of the password + /// such as $1$1682a1e45e9f957dcdf0bb56eb43319c + /// Client application name (channel) + /// Starting location URI that can be built with + /// StartLocation() + /// Client application name + version + /// Whether the login was successful or not. On failure the + /// LoginErrorKey string will contain the error code and LoginMessage + /// will contain a description of the error + public bool Login(string firstName, string lastName, string password, string channel, string start, + string version) + { + LoginParams loginParams = DefaultLoginParams(firstName, lastName, password, channel, version); + loginParams.Start = start; + + return Login(loginParams); + } + + /// + /// Login that takes a struct of all the values that will be passed to + /// the login server + /// + /// The values that will be passed to the login + /// server, all fields must be set even if they are String.Empty + /// Whether the login was successful or not. On failure the + /// LoginErrorKey string will contain the error code and LoginMessage + /// will contain a description of the error + public bool Login(LoginParams loginParams) + { + BeginLogin(loginParams); + + LoginEvent.WaitOne(loginParams.Timeout, false); + + if (CurrentContext != null) + { + CurrentContext = null; // Will force any pending callbacks to bail out early + InternalStatusCode = LoginStatus.Failed; + InternalLoginMessage = "Timed out"; + return false; + } + + return (InternalStatusCode == LoginStatus.Success); + } + + public void BeginLogin(LoginParams loginParams) + { + // FIXME: Now that we're using CAPS we could cancel the current login and start a new one + if (CurrentContext != null) + throw new Exception("Login already in progress"); + + LoginEvent.Reset(); + CurrentContext = loginParams; + + BeginLogin(); + } + + public void RegisterLoginResponseCallback(LoginResponseCallback callback) + { + RegisterLoginResponseCallback(callback, null); + } + + + public void RegisterLoginResponseCallback(LoginResponseCallback callback, string[] options) + { + CallbackOptions.Add(callback, options); + OnLoginResponse += callback; + } + + public void UnregisterLoginResponseCallback(LoginResponseCallback callback) + { + CallbackOptions.Remove(callback); + OnLoginResponse -= callback; + } + + /// + /// Build a start location URI for passing to the Login function + /// + /// Name of the simulator to start in + /// X coordinate to start at + /// Y coordinate to start at + /// Z coordinate to start at + /// String with a URI that can be used to login to a specified + /// location + public static string StartLocation(string sim, int x, int y, int z) + { + return String.Format("uri:{0}&{1}&{2}&{3}", sim, x, y, z); + } + public void AbortLogin() + { + LoginParams loginParams = CurrentContext; + CurrentContext = null; // Will force any pending callbacks to bail out early + // FIXME: Now that we're using CAPS we could cancel the current login and start a new one + if (loginParams == null) + { + Logger.DebugLog("No Login was in progress: " + CurrentContext, Client); + } + else + { + InternalStatusCode = LoginStatus.Failed; + InternalLoginMessage = "Aborted"; + } + UpdateLoginStatus(LoginStatus.Failed, "Abort Requested"); + } + + #endregion + + #region Private Methods + + private void BeginLogin() + { + LoginParams loginParams = CurrentContext; + // Generate a random ID to identify this login attempt + loginParams.LoginID = UUID.Random(); + CurrentContext = loginParams; + + #region Sanity Check loginParams + + if (loginParams.Options == null) + loginParams.Options = new List().ToArray(); + + if (loginParams.Password == null) + loginParams.Password = String.Empty; + + // Convert the password to MD5 if it isn't already + if (loginParams.Password.Length != 35 && !loginParams.Password.StartsWith("$1$")) + loginParams.Password = Utils.MD5(loginParams.Password); + + if (loginParams.ViewerDigest == null) + loginParams.ViewerDigest = String.Empty; + + if (loginParams.Version == null) + loginParams.Version = String.Empty; + + if (loginParams.UserAgent == null) + loginParams.UserAgent = String.Empty; + + if (loginParams.Platform == null) + loginParams.Platform = String.Empty; + + if (loginParams.MAC == null) + loginParams.MAC = String.Empty; + + if (string.IsNullOrEmpty(loginParams.Channel)) + { + Logger.Log("Viewer channel not set. This is a TOS violation on some grids.", Helpers.LogLevel.Warning); + loginParams.Channel = "libopenmetaverse generic client"; + } + + if (loginParams.Author == null) + loginParams.Author = String.Empty; + + #endregion + + // TODO: Allow a user callback to be defined for handling the cert + ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy(); + // Even though this will compile on Mono 2.4, it throws a runtime exception + //ServicePointManager.ServerCertificateValidationCallback = TrustAllCertificatePolicy.TrustAllCertificateHandler; + + if (Client.Settings.USE_LLSD_LOGIN) + { + #region LLSD Based Login + + // Create the CAPS login structure + OSDMap loginLLSD = new OSDMap(); + loginLLSD["first"] = OSD.FromString(loginParams.FirstName); + loginLLSD["last"] = OSD.FromString(loginParams.LastName); + loginLLSD["passwd"] = OSD.FromString(loginParams.Password); + loginLLSD["start"] = OSD.FromString(loginParams.Start); + loginLLSD["channel"] = OSD.FromString(loginParams.Channel); + loginLLSD["version"] = OSD.FromString(loginParams.Version); + loginLLSD["platform"] = OSD.FromString(loginParams.Platform); + loginLLSD["mac"] = OSD.FromString(loginParams.MAC); + loginLLSD["agree_to_tos"] = OSD.FromBoolean(loginParams.AgreeToTos); + loginLLSD["read_critical"] = OSD.FromBoolean(loginParams.ReadCritical); + loginLLSD["viewer_digest"] = OSD.FromString(loginParams.ViewerDigest); + loginLLSD["id0"] = OSD.FromString(loginParams.ID0); + loginLLSD["last_exec_event"] = OSD.FromInteger((int)loginParams.LastExecEvent); + + // Create the options LLSD array + OSDArray optionsOSD = new OSDArray(); + for (int i = 0; i < loginParams.Options.Length; i++) + optionsOSD.Add(OSD.FromString(loginParams.Options[i])); + + foreach (string[] callbackOpts in CallbackOptions.Values) + { + if (callbackOpts != null) + { + for (int i = 0; i < callbackOpts.Length; i++) + { + if (!optionsOSD.Contains(callbackOpts[i])) + optionsOSD.Add(callbackOpts[i]); + } + } + } + loginLLSD["options"] = optionsOSD; + + // Make the CAPS POST for login + Uri loginUri; + try + { + loginUri = new Uri(loginParams.URI); + } + catch (Exception ex) + { + Logger.Log(String.Format("Failed to parse login URI {0}, {1}", loginParams.URI, ex.Message), + Helpers.LogLevel.Error, Client); + return; + } + + CapsClient loginRequest = new CapsClient(loginUri); + loginRequest.OnComplete += new CapsClient.CompleteCallback(LoginReplyLLSDHandler); + loginRequest.UserData = CurrentContext; + UpdateLoginStatus(LoginStatus.ConnectingToLogin, String.Format("Logging in as {0} {1}...", loginParams.FirstName, loginParams.LastName)); + loginRequest.BeginGetResponse(loginLLSD, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + + #endregion + } + else + { + #region XML-RPC Based Login Code + + // Create the Hashtable for XmlRpcCs + Hashtable loginXmlRpc = new Hashtable(); + loginXmlRpc["first"] = loginParams.FirstName; + loginXmlRpc["last"] = loginParams.LastName; + loginXmlRpc["passwd"] = loginParams.Password; + loginXmlRpc["start"] = loginParams.Start; + loginXmlRpc["channel"] = loginParams.Channel; + loginXmlRpc["version"] = loginParams.Version; + loginXmlRpc["platform"] = loginParams.Platform; + loginXmlRpc["mac"] = loginParams.MAC; + if (loginParams.AgreeToTos) + loginXmlRpc["agree_to_tos"] = "true"; + if (loginParams.ReadCritical) + loginXmlRpc["read_critical"] = "true"; + loginXmlRpc["id0"] = loginParams.ID0; + loginXmlRpc["last_exec_event"] = (int)loginParams.LastExecEvent; + + // Create the options array + ArrayList options = new ArrayList(); + for (int i = 0; i < loginParams.Options.Length; i++) + options.Add(loginParams.Options[i]); + + foreach (string[] callbackOpts in CallbackOptions.Values) + { + if (callbackOpts != null) + { + for (int i = 0; i < callbackOpts.Length; i++) + { + if (!options.Contains(callbackOpts[i])) + options.Add(callbackOpts[i]); + } + } + } + loginXmlRpc["options"] = options; + + try + { + ArrayList loginArray = new ArrayList(1); + loginArray.Add(loginXmlRpc); + XmlRpcRequest request = new XmlRpcRequest(CurrentContext.MethodName, loginArray); + var cc = CurrentContext; + // Start the request + Thread requestThread = new Thread( + delegate() + { + try + { + LoginReplyXmlRpcHandler( + request.Send(cc.URI, cc.Timeout), + loginParams); + } + catch (Exception e) + { + UpdateLoginStatus(LoginStatus.Failed, "Error opening the login server connection: " + e.Message); + } + }); + requestThread.Name = "XML-RPC Login"; + requestThread.Start(); + } + catch (Exception e) + { + UpdateLoginStatus(LoginStatus.Failed, "Error opening the login server connection: " + e); + } + + #endregion + } + } + + private void UpdateLoginStatus(LoginStatus status, string message) + { + InternalStatusCode = status; + InternalLoginMessage = message; + + Logger.DebugLog("Login status: " + status.ToString() + ": " + message, Client); + + // If we reached a login resolution trigger the event + if (status == LoginStatus.Success || status == LoginStatus.Failed) + { + CurrentContext = null; + LoginEvent.Set(); + } + + // Fire the login status callback + if (m_LoginProgress != null) + { + OnLoginProgress(new LoginProgressEventArgs(status, message, InternalErrorKey)); + } + } + + + /// + /// LoginParams and the initial login XmlRpcRequest were made on a remote machine. + /// This method now initializes libomv with the results. + /// + public void RemoteLoginHandler(LoginResponseData response, LoginParams newContext) + { + CurrentContext = newContext; + LoginReplyXmlRpcHandler(response, newContext); + } + + + /// + /// Handles response from XML-RPC login replies + /// + private void LoginReplyXmlRpcHandler(XmlRpcResponse response, LoginParams context) + { + LoginResponseData reply = new LoginResponseData(); + // Fetch the login response + if (response == null || !(response.Value is Hashtable)) + { + UpdateLoginStatus(LoginStatus.Failed, "Invalid or missing login response from the server"); + Logger.Log("Invalid or missing login response from the server", Helpers.LogLevel.Warning); + return; + } + + try + { + reply.Parse((Hashtable)response.Value); + if (context.LoginID != CurrentContext.LoginID) + { + Logger.Log("Login response does not match login request. Only one login can be attempted at a time", + Helpers.LogLevel.Error); + return; + } + } + catch (Exception e) + { + UpdateLoginStatus(LoginStatus.Failed, "Error retrieving the login response from the server: " + e.Message); + Logger.Log("Login response failure: " + e.Message + " " + e.StackTrace, Helpers.LogLevel.Warning); + return; + } + LoginReplyXmlRpcHandler(reply, context); + } + + + /// + /// Handles response from XML-RPC login replies with already parsed LoginResponseData + /// + private void LoginReplyXmlRpcHandler(LoginResponseData reply, LoginParams context) + { + LoginResponseData = reply; + ushort simPort = 0; + uint regionX = 0; + uint regionY = 0; + string reason = reply.Reason; + string message = reply.Message; + + if (reply.Login == "true") + { + // Remove the quotes around our first name. + if (reply.FirstName[0] == '"') + reply.FirstName = reply.FirstName.Remove(0, 1); + if (reply.FirstName[reply.FirstName.Length - 1] == '"') + reply.FirstName = reply.FirstName.Remove(reply.FirstName.Length - 1); + + #region Critical Information + + try + { + // Networking + Client.Network.CircuitCode = (uint)reply.CircuitCode; + regionX = (uint)reply.RegionX; + regionY = (uint)reply.RegionY; + simPort = (ushort)reply.SimPort; + LoginSeedCapability = reply.SeedCapability; + } + catch (Exception) + { + UpdateLoginStatus(LoginStatus.Failed, "Login server failed to return critical information"); + return; + } + + #endregion Critical Information + + /* Add any blacklisted UDP packets to the blacklist + * for exclusion from packet processing */ + if (reply.UDPBlacklist != null) + UDPBlacklist.AddRange(reply.UDPBlacklist.Split(',')); + + // Misc: + MaxAgentGroups = reply.MaxAgentGroups; + AgentAppearanceServiceURL = reply.AgentAppearanceServiceURL; + + //uint timestamp = (uint)reply.seconds_since_epoch; + //DateTime time = Helpers.UnixTimeToDateTime(timestamp); // TODO: Do something with this? + + // Unhandled: + // reply.gestures + // reply.event_categories + // reply.classified_categories + // reply.event_notifications + // reply.ui_config + // reply.login_flags + // reply.global_textures + // reply.inventory_lib_root + // reply.inventory_lib_owner + // reply.inventory_skeleton + // reply.inventory_skel_lib + // reply.initial_outfit + } + + bool redirect = (reply.Login == "indeterminate"); + + try + { + if (OnLoginResponse != null) + { + try { OnLoginResponse(reply.Success, redirect, message, reason, reply); } + catch (Exception ex) { Logger.Log(ex.ToString(), Helpers.LogLevel.Error); } + } + } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, ex); } + + // Make the next network jump, if needed + if (redirect) + { + UpdateLoginStatus(LoginStatus.Redirecting, "Redirecting login..."); + LoginParams loginParams = CurrentContext; + loginParams.URI = reply.NextUrl; + loginParams.MethodName = reply.NextMethod; + loginParams.Options = reply.NextOptions; + + // Sleep for some amount of time while the servers work + int seconds = reply.NextDuration; + Logger.Log("Sleeping for " + seconds + " seconds during a login redirect", + Helpers.LogLevel.Info); + Thread.Sleep(seconds * 1000); + + CurrentContext = loginParams; + BeginLogin(); + } + else if (reply.Success) + { + UpdateLoginStatus(LoginStatus.ConnectingToSim, "Connecting to simulator..."); + + ulong handle = Utils.UIntsToLong(regionX, regionY); + + // Connect to the sim given in the login reply + if (Connect(reply.SimIP, simPort, handle, true, LoginSeedCapability) != null) + { + // Request the economy data right after login + SendPacket(new EconomyDataRequestPacket()); + + // Update the login message with the MOTD returned from the server + UpdateLoginStatus(LoginStatus.Success, message); + } + else + { + UpdateLoginStatus(LoginStatus.Failed, "Unable to connect to simulator"); + } + } + else + { + // Make sure a usable error key is set + + if (!String.IsNullOrEmpty(reason)) + InternalErrorKey = reason; + else + InternalErrorKey = "unknown"; + + UpdateLoginStatus(LoginStatus.Failed, message); + } + } + + /// + /// Handle response from LLSD login replies + /// + /// + /// + /// + private void LoginReplyLLSDHandler(CapsClient client, OSD result, Exception error) + { + if (error == null) + { + if (result != null && result.Type == OSDType.Map) + { + OSDMap map = (OSDMap)result; + OSD osd; + + LoginResponseData data = new LoginResponseData(); + data.Parse(map); + + if (map.TryGetValue("login", out osd)) + { + bool loginSuccess = osd.AsBoolean(); + bool redirect = (osd.AsString() == "indeterminate"); + + if (redirect) + { + // Login redirected + + // Make the next login URL jump + UpdateLoginStatus(LoginStatus.Redirecting, data.Message); + + LoginParams loginParams = CurrentContext; + loginParams.URI = LoginResponseData.ParseString("next_url", map); + //CurrentContext.Params.MethodName = LoginResponseData.ParseString("next_method", map); + + // Sleep for some amount of time while the servers work + int seconds = (int)LoginResponseData.ParseUInt("next_duration", map); + Logger.Log("Sleeping for " + seconds + " seconds during a login redirect", + Helpers.LogLevel.Info); + Thread.Sleep(seconds * 1000); + + // Ignore next_options for now + CurrentContext = loginParams; + + BeginLogin(); + } + else if (loginSuccess) + { + // Login succeeded + + // Fire the login callback + if (OnLoginResponse != null) + { + try { OnLoginResponse(loginSuccess, redirect, data.Message, data.Reason, data); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + } + + // These parameters are stored in NetworkManager, so instead of registering + // another callback for them we just set the values here + CircuitCode = (uint)data.CircuitCode; + LoginSeedCapability = data.SeedCapability; + + UpdateLoginStatus(LoginStatus.ConnectingToSim, "Connecting to simulator..."); + + ulong handle = Utils.UIntsToLong((uint)data.RegionX, (uint)data.RegionY); + + if (data.SimIP != null && data.SimPort != 0) + { + // Connect to the sim given in the login reply + if (Connect(data.SimIP, (ushort)data.SimPort, handle, true, LoginSeedCapability) != null) + { + // Request the economy data right after login + SendPacket(new EconomyDataRequestPacket()); + + // Update the login message with the MOTD returned from the server + UpdateLoginStatus(LoginStatus.Success, data.Message); + } + else + { + UpdateLoginStatus(LoginStatus.Failed, + "Unable to establish a UDP connection to the simulator"); + } + } + else + { + UpdateLoginStatus(LoginStatus.Failed, + "Login server did not return a simulator address"); + } + } + else + { + // Login failed + + // Make sure a usable error key is set + if (data.Reason != String.Empty) + InternalErrorKey = data.Reason; + else + InternalErrorKey = "unknown"; + + UpdateLoginStatus(LoginStatus.Failed, data.Message); + } + } + else + { + // Got an LLSD map but no login value + UpdateLoginStatus(LoginStatus.Failed, "login parameter missing in the response"); + } + } + else + { + // No LLSD response + InternalErrorKey = "bad response"; + UpdateLoginStatus(LoginStatus.Failed, "Empty or unparseable login response"); + } + } + else + { + // Connection error + InternalErrorKey = "no connection"; + UpdateLoginStatus(LoginStatus.Failed, error.Message); + } + } + + /// + /// Get current OS + /// + /// Either "Win" or "Linux" + public static string GetPlatform() + { + switch (Environment.OSVersion.Platform) + { + case PlatformID.Unix: + return "Linux"; + default: + return "Win"; + } + } + + /// + /// Get clients default Mac Address + /// + /// A string containing the first found Mac Address + public static string GetMAC() + { + string mac = String.Empty; + + try + { + System.Net.NetworkInformation.NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); + + if (nics != null && nics.Length > 0) + { + for (int i = 0; i < nics.Length; i++) + { + string adapterMac = nics[i].GetPhysicalAddress().ToString().ToUpper(); + if (adapterMac.Length == 12 && adapterMac != "000000000000") + { + mac = adapterMac; + continue; + } + } + } + } + catch { } + + if (mac.Length < 12) + mac = UUID.Random().ToString().Substring(24, 12); + + return String.Format("{0}:{1}:{2}:{3}:{4}:{5}", + mac.Substring(0, 2), + mac.Substring(2, 2), + mac.Substring(4, 2), + mac.Substring(6, 2), + mac.Substring(8, 2), + mac.Substring(10, 2)); + } + + #endregion + } + #region EventArgs + + public class LoginProgressEventArgs : EventArgs + { + private readonly LoginStatus m_Status; + private readonly String m_Message; + private readonly String m_FailReason; + + public LoginStatus Status { get { return m_Status; } } + public String Message { get { return m_Message; } } + public string FailReason { get { return m_FailReason; } } + + public LoginProgressEventArgs(LoginStatus login, String message, String failReason) + { + this.m_Status = login; + this.m_Message = message; + this.m_FailReason = failReason; + } + } + + #endregion EventArgs +} \ No newline at end of file diff --git a/OpenMetaverse/Messages/LindenMessages.cs b/OpenMetaverse/Messages/LindenMessages.cs new file mode 100644 index 0000000..b82845c --- /dev/null +++ b/OpenMetaverse/Messages/LindenMessages.cs @@ -0,0 +1,5254 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using System.IO; +using ComponentAce.Compression.Libs.zlib; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Interfaces; + +namespace OpenMetaverse.Messages.Linden +{ + #region Teleport/Region/Movement Messages + + /// + /// Sent to the client to indicate a teleport request has completed + /// + public class TeleportFinishMessage : IMessage + { + /// The of the agent + public UUID AgentID; + /// + public int LocationID; + /// The simulators handle the agent teleported to + public ulong RegionHandle; + /// A Uri which contains a list of Capabilities the simulator supports + public Uri SeedCapability; + /// Indicates the level of access required + /// to access the simulator, or the content rating, or the simulators + /// map status + public SimAccess SimAccess; + /// The IP Address of the simulator + public IPAddress IP; + /// The UDP Port the simulator will listen for UDP traffic on + public int Port; + /// Status flags indicating the state of the Agent upon arrival, Flying, etc. + public TeleportFlags Flags; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + + OSDArray infoArray = new OSDArray(1); + + OSDMap info = new OSDMap(8); + info.Add("AgentID", OSD.FromUUID(AgentID)); + info.Add("LocationID", OSD.FromInteger(LocationID)); // Unused by the client + info.Add("RegionHandle", OSD.FromULong(RegionHandle)); + info.Add("SeedCapability", OSD.FromUri(SeedCapability)); + info.Add("SimAccess", OSD.FromInteger((byte)SimAccess)); + info.Add("SimIP", MessageUtils.FromIP(IP)); + info.Add("SimPort", OSD.FromInteger(Port)); + info.Add("TeleportFlags", OSD.FromUInteger((uint)Flags)); + + infoArray.Add(info); + + map.Add("Info", infoArray); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray array = (OSDArray)map["Info"]; + OSDMap blockMap = (OSDMap)array[0]; + + AgentID = blockMap["AgentID"].AsUUID(); + LocationID = blockMap["LocationID"].AsInteger(); + RegionHandle = blockMap["RegionHandle"].AsULong(); + SeedCapability = blockMap["SeedCapability"].AsUri(); + SimAccess = (SimAccess)blockMap["SimAccess"].AsInteger(); + IP = MessageUtils.ToIP(blockMap["SimIP"]); + Port = blockMap["SimPort"].AsInteger(); + Flags = (TeleportFlags)blockMap["TeleportFlags"].AsUInteger(); + } + } + + /// + /// Sent to the viewer when a neighboring simulator is requesting the agent make a connection to it. + /// + public class EstablishAgentCommunicationMessage : IMessage + { + public UUID AgentID; + public IPAddress Address; + public int Port; + public Uri SeedCapability; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + map["agent-id"] = OSD.FromUUID(AgentID); + map["sim-ip-and-port"] = OSD.FromString(String.Format("{0}:{1}", Address, Port)); + map["seed-capability"] = OSD.FromUri(SeedCapability); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + string ipAndPort = map["sim-ip-and-port"].AsString(); + int i = ipAndPort.IndexOf(':'); + + AgentID = map["agent-id"].AsUUID(); + Address = IPAddress.Parse(ipAndPort.Substring(0, i)); + Port = Int32.Parse(ipAndPort.Substring(i + 1)); + SeedCapability = map["seed-capability"].AsUri(); + } + } + + public class CrossedRegionMessage : IMessage + { + public Vector3 LookAt; + public Vector3 Position; + public UUID AgentID; + public UUID SessionID; + public ulong RegionHandle; + public Uri SeedCapability; + public IPAddress IP; + public int Port; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + + OSDArray infoArray = new OSDArray(1); + OSDMap infoMap = new OSDMap(2); + infoMap["LookAt"] = OSD.FromVector3(LookAt); + infoMap["Position"] = OSD.FromVector3(Position); + infoArray.Add(infoMap); + map["Info"] = infoArray; + + OSDArray agentDataArray = new OSDArray(1); + OSDMap agentDataMap = new OSDMap(2); + agentDataMap["AgentID"] = OSD.FromUUID(AgentID); + agentDataMap["SessionID"] = OSD.FromUUID(SessionID); + agentDataArray.Add(agentDataMap); + map["AgentData"] = agentDataArray; + + OSDArray regionDataArray = new OSDArray(1); + OSDMap regionDataMap = new OSDMap(4); + regionDataMap["RegionHandle"] = OSD.FromULong(RegionHandle); + regionDataMap["SeedCapability"] = OSD.FromUri(SeedCapability); + regionDataMap["SimIP"] = MessageUtils.FromIP(IP); + regionDataMap["SimPort"] = OSD.FromInteger(Port); + regionDataArray.Add(regionDataMap); + map["RegionData"] = regionDataArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDMap infoMap = (OSDMap)((OSDArray)map["Info"])[0]; + LookAt = infoMap["LookAt"].AsVector3(); + Position = infoMap["Position"].AsVector3(); + + OSDMap agentDataMap = (OSDMap)((OSDArray)map["AgentData"])[0]; + AgentID = agentDataMap["AgentID"].AsUUID(); + SessionID = agentDataMap["SessionID"].AsUUID(); + + OSDMap regionDataMap = (OSDMap)((OSDArray)map["RegionData"])[0]; + RegionHandle = regionDataMap["RegionHandle"].AsULong(); + SeedCapability = regionDataMap["SeedCapability"].AsUri(); + IP = MessageUtils.ToIP(regionDataMap["SimIP"]); + Port = regionDataMap["SimPort"].AsInteger(); + } + } + + public class EnableSimulatorMessage : IMessage + { + public class SimulatorInfoBlock + { + public ulong RegionHandle; + public IPAddress IP; + public int Port; + } + + public SimulatorInfoBlock[] Simulators; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + + OSDArray array = new OSDArray(Simulators.Length); + for (int i = 0; i < Simulators.Length; i++) + { + SimulatorInfoBlock block = Simulators[i]; + + OSDMap blockMap = new OSDMap(3); + blockMap["Handle"] = OSD.FromULong(block.RegionHandle); + blockMap["IP"] = MessageUtils.FromIP(block.IP); + blockMap["Port"] = OSD.FromInteger(block.Port); + array.Add(blockMap); + } + + map["SimulatorInfo"] = array; + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray array = (OSDArray)map["SimulatorInfo"]; + Simulators = new SimulatorInfoBlock[array.Count]; + + for (int i = 0; i < array.Count; i++) + { + OSDMap blockMap = (OSDMap)array[i]; + + SimulatorInfoBlock block = new SimulatorInfoBlock(); + block.RegionHandle = blockMap["Handle"].AsULong(); + block.IP = MessageUtils.ToIP(blockMap["IP"]); + block.Port = blockMap["Port"].AsInteger(); + Simulators[i] = block; + } + } + } + + /// + /// A message sent to the client which indicates a teleport request has failed + /// and contains some information on why it failed + /// + public class TeleportFailedMessage : IMessage + { + /// + public string ExtraParams; + /// A string key of the reason the teleport failed e.g. CouldntTPCloser + /// Which could be used to look up a value in a dictionary or enum + public string MessageKey; + /// The of the Agent + public UUID AgentID; + /// A string human readable message containing the reason + /// An example: Could not teleport closer to destination + public string Reason; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + + OSDMap alertInfoMap = new OSDMap(2); + + alertInfoMap["ExtraParams"] = OSD.FromString(ExtraParams); + alertInfoMap["Message"] = OSD.FromString(MessageKey); + OSDArray alertArray = new OSDArray(); + alertArray.Add(alertInfoMap); + map["AlertInfo"] = alertArray; + + OSDMap infoMap = new OSDMap(2); + infoMap["AgentID"] = OSD.FromUUID(AgentID); + infoMap["Reason"] = OSD.FromString(Reason); + OSDArray infoArray = new OSDArray(); + infoArray.Add(infoMap); + map["Info"] = infoArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + + OSDArray alertInfoArray = (OSDArray)map["AlertInfo"]; + + OSDMap alertInfoMap = (OSDMap)alertInfoArray[0]; + ExtraParams = alertInfoMap["ExtraParams"].AsString(); + MessageKey = alertInfoMap["Message"].AsString(); + + OSDArray infoArray = (OSDArray)map["Info"]; + OSDMap infoMap = (OSDMap)infoArray[0]; + AgentID = infoMap["AgentID"].AsUUID(); + Reason = infoMap["Reason"].AsString(); + } + } + + public class LandStatReplyMessage : IMessage + { + public uint ReportType; + public uint RequestFlags; + public uint TotalObjectCount; + + public class ReportDataBlock + { + public Vector3 Location; + public string OwnerName; + public float Score; + public UUID TaskID; + public uint TaskLocalID; + public string TaskName; + public float MonoScore; + public DateTime TimeStamp; + } + + public ReportDataBlock[] ReportDataBlocks; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + + OSDMap requestDataMap = new OSDMap(3); + requestDataMap["ReportType"] = OSD.FromUInteger(this.ReportType); + requestDataMap["RequestFlags"] = OSD.FromUInteger(this.RequestFlags); + requestDataMap["TotalObjectCount"] = OSD.FromUInteger(this.TotalObjectCount); + + OSDArray requestDatArray = new OSDArray(); + requestDatArray.Add(requestDataMap); + map["RequestData"] = requestDatArray; + + OSDArray reportDataArray = new OSDArray(); + OSDArray dataExtendedArray = new OSDArray(); + for (int i = 0; i < ReportDataBlocks.Length; i++) + { + OSDMap reportMap = new OSDMap(8); + reportMap["LocationX"] = OSD.FromReal(ReportDataBlocks[i].Location.X); + reportMap["LocationY"] = OSD.FromReal(ReportDataBlocks[i].Location.Y); + reportMap["LocationZ"] = OSD.FromReal(ReportDataBlocks[i].Location.Z); + reportMap["OwnerName"] = OSD.FromString(ReportDataBlocks[i].OwnerName); + reportMap["Score"] = OSD.FromReal(ReportDataBlocks[i].Score); + reportMap["TaskID"] = OSD.FromUUID(ReportDataBlocks[i].TaskID); + reportMap["TaskLocalID"] = OSD.FromReal(ReportDataBlocks[i].TaskLocalID); + reportMap["TaskName"] = OSD.FromString(ReportDataBlocks[i].TaskName); + reportDataArray.Add(reportMap); + + OSDMap extendedMap = new OSDMap(2); + extendedMap["MonoScore"] = OSD.FromReal(ReportDataBlocks[i].MonoScore); + extendedMap["TimeStamp"] = OSD.FromDate(ReportDataBlocks[i].TimeStamp); + dataExtendedArray.Add(extendedMap); + } + + map["ReportData"] = reportDataArray; + map["DataExtended"] = dataExtendedArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + + OSDArray requestDataArray = (OSDArray)map["RequestData"]; + OSDMap requestMap = (OSDMap)requestDataArray[0]; + + this.ReportType = requestMap["ReportType"].AsUInteger(); + this.RequestFlags = requestMap["RequestFlags"].AsUInteger(); + this.TotalObjectCount = requestMap["TotalObjectCount"].AsUInteger(); + + if (TotalObjectCount < 1) + { + ReportDataBlocks = new ReportDataBlock[0]; + return; + } + + OSDArray dataArray = (OSDArray)map["ReportData"]; + OSDArray dataExtendedArray = (OSDArray)map["DataExtended"]; + + ReportDataBlocks = new ReportDataBlock[dataArray.Count]; + for (int i = 0; i < dataArray.Count; i++) + { + OSDMap blockMap = (OSDMap)dataArray[i]; + OSDMap extMap = (OSDMap)dataExtendedArray[i]; + ReportDataBlock block = new ReportDataBlock(); + block.Location = new Vector3( + (float)blockMap["LocationX"].AsReal(), + (float)blockMap["LocationY"].AsReal(), + (float)blockMap["LocationZ"].AsReal()); + block.OwnerName = blockMap["OwnerName"].AsString(); + block.Score = (float)blockMap["Score"].AsReal(); + block.TaskID = blockMap["TaskID"].AsUUID(); + block.TaskLocalID = blockMap["TaskLocalID"].AsUInteger(); + block.TaskName = blockMap["TaskName"].AsString(); + block.MonoScore = (float)extMap["MonoScore"].AsReal(); + block.TimeStamp = Utils.UnixTimeToDateTime(extMap["TimeStamp"].AsUInteger()); + + ReportDataBlocks[i] = block; + } + } + } + + #endregion + + #region Parcel Messages + + /// + /// Contains a list of prim owner information for a specific parcel in a simulator + /// + /// + /// A Simulator will always return at least 1 entry + /// If agent does not have proper permission the OwnerID will be UUID.Zero + /// If agent does not have proper permission OR there are no primitives on parcel + /// the DataBlocksExtended map will not be sent from the simulator + /// + public class ParcelObjectOwnersReplyMessage : IMessage + { + /// + /// Prim ownership information for a specified owner on a single parcel + /// + public class PrimOwner + { + /// The of the prim owner, + /// UUID.Zero if agent has no permission to view prim owner information + public UUID OwnerID; + /// The total number of prims + public int Count; + /// True if the OwnerID is a + public bool IsGroupOwned; + /// True if the owner is online + /// This is no longer used by the LL Simulators + public bool OnlineStatus; + /// The date the most recent prim was rezzed + public DateTime TimeStamp; + } + + /// An Array of objects + public PrimOwner[] PrimOwnersBlock; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDArray dataArray = new OSDArray(PrimOwnersBlock.Length); + OSDArray dataExtendedArray = new OSDArray(); + + for (int i = 0; i < PrimOwnersBlock.Length; i++) + { + OSDMap dataMap = new OSDMap(4); + dataMap["OwnerID"] = OSD.FromUUID(PrimOwnersBlock[i].OwnerID); + dataMap["Count"] = OSD.FromInteger(PrimOwnersBlock[i].Count); + dataMap["IsGroupOwned"] = OSD.FromBoolean(PrimOwnersBlock[i].IsGroupOwned); + dataMap["OnlineStatus"] = OSD.FromBoolean(PrimOwnersBlock[i].OnlineStatus); + dataArray.Add(dataMap); + + OSDMap dataExtendedMap = new OSDMap(1); + dataExtendedMap["TimeStamp"] = OSD.FromDate(PrimOwnersBlock[i].TimeStamp); + dataExtendedArray.Add(dataExtendedMap); + } + + OSDMap map = new OSDMap(); + map.Add("Data", dataArray); + if (dataExtendedArray.Count > 0) + map.Add("DataExtended", dataExtendedArray); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray dataArray = (OSDArray)map["Data"]; + + // DataExtended is optional, will not exist of parcel contains zero prims + OSDArray dataExtendedArray; + if (map.ContainsKey("DataExtended")) + { + dataExtendedArray = (OSDArray)map["DataExtended"]; + } + else + { + dataExtendedArray = new OSDArray(); + } + + PrimOwnersBlock = new PrimOwner[dataArray.Count]; + + for (int i = 0; i < dataArray.Count; i++) + { + OSDMap dataMap = (OSDMap)dataArray[i]; + PrimOwner block = new PrimOwner(); + block.OwnerID = dataMap["OwnerID"].AsUUID(); + block.Count = dataMap["Count"].AsInteger(); + block.IsGroupOwned = dataMap["IsGroupOwned"].AsBoolean(); + block.OnlineStatus = dataMap["OnlineStatus"].AsBoolean(); // deprecated + + /* if the agent has no permissions, or there are no prims, the counts + * should not match up, so we don't decode the DataExtended map */ + if (dataExtendedArray.Count == dataArray.Count) + { + OSDMap dataExtendedMap = (OSDMap)dataExtendedArray[i]; + block.TimeStamp = Utils.UnixTimeToDateTime(dataExtendedMap["TimeStamp"].AsUInteger()); + } + + PrimOwnersBlock[i] = block; + } + } + } + + /// + /// The details of a single parcel in a region, also contains some regionwide globals + /// + [Serializable] + public class ParcelPropertiesMessage : IMessage + { + /// Simulator-local ID of this parcel + public int LocalID; + /// Maximum corner of the axis-aligned bounding box for this + /// parcel + public Vector3 AABBMax; + /// Minimum corner of the axis-aligned bounding box for this + /// parcel + public Vector3 AABBMin; + /// Total parcel land area + public int Area; + /// + public uint AuctionID; + /// Key of authorized buyer + public UUID AuthBuyerID; + /// Bitmap describing land layout in 4x4m squares across the + /// entire region + public byte[] Bitmap; + /// + public ParcelCategory Category; + /// Date land was claimed + public DateTime ClaimDate; + /// Appears to always be zero + public int ClaimPrice; + /// Parcel Description + public string Desc; + /// + public ParcelFlags ParcelFlags; + /// + public UUID GroupID; + /// Total number of primitives owned by the parcel group on + /// this parcel + public int GroupPrims; + /// Whether the land is deeded to a group or not + public bool IsGroupOwned; + /// + public LandingType LandingType; + /// Maximum number of primitives this parcel supports + public int MaxPrims; + /// The Asset UUID of the Texture which when applied to a + /// primitive will display the media + public UUID MediaID; + /// A URL which points to any Quicktime supported media type + public string MediaURL; + /// A byte, if 0x1 viewer should auto scale media to fit object + public bool MediaAutoScale; + /// URL For Music Stream + public string MusicURL; + /// Parcel Name + public string Name; + /// Autoreturn value in minutes for others' objects + public int OtherCleanTime; + /// + public int OtherCount; + /// Total number of other primitives on this parcel + public int OtherPrims; + /// UUID of the owner of this parcel + public UUID OwnerID; + /// Total number of primitives owned by the parcel owner on + /// this parcel + public int OwnerPrims; + /// + public float ParcelPrimBonus; + /// How long is pass valid for + public float PassHours; + /// Price for a temporary pass + public int PassPrice; + /// + public int PublicCount; + /// Disallows people outside the parcel from being able to see in + public bool Privacy; + /// + public bool RegionDenyAnonymous; + /// + public bool RegionDenyIdentified; + /// + public bool RegionDenyTransacted; + /// True if the region denies access to age unverified users + public bool RegionDenyAgeUnverified; + /// + public bool RegionPushOverride; + /// This field is no longer used + public int RentPrice; + /// The result of a request for parcel properties + public ParcelResult RequestResult; + /// Sale price of the parcel, only useful if ForSale is set + /// The SalePrice will remain the same after an ownership + /// transfer (sale), so it can be used to see the purchase price after + /// a sale if the new owner has not changed it + public int SalePrice; + /// + /// Number of primitives your avatar is currently + /// selecting and sitting on in this parcel + /// + public int SelectedPrims; + /// + public int SelfCount; + /// + /// A number which increments by 1, starting at 0 for each ParcelProperties request. + /// Can be overriden by specifying the sequenceID with the ParcelPropertiesRequest being sent. + /// a Negative number indicates the action in has occurred. + /// + public int SequenceID; + /// Maximum primitives across the entire simulator + public int SimWideMaxPrims; + /// Total primitives across the entire simulator + public int SimWideTotalPrims; + /// + public bool SnapSelection; + /// Key of parcel snapshot + public UUID SnapshotID; + /// Parcel ownership status + public ParcelStatus Status; + /// Total number of primitives on this parcel + public int TotalPrims; + /// + public Vector3 UserLocation; + /// + public Vector3 UserLookAt; + /// A description of the media + public string MediaDesc; + /// An Integer which represents the height of the media + public int MediaHeight; + /// An integer which represents the width of the media + public int MediaWidth; + /// A boolean, if true the viewer should loop the media + public bool MediaLoop; + /// A string which contains the mime type of the media + public string MediaType; + /// true to obscure (hide) media url + public bool ObscureMedia; + /// true to obscure (hide) music url + public bool ObscureMusic; + /// true if avatars in this parcel should be invisible to people outside + public bool SeeAVs; + /// true if avatars outside can hear any sounds avatars inside play + public bool AnyAVSounds; + /// true if group members outside can hear any sounds avatars inside play + public bool GroupAVSounds; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + + OSDArray dataArray = new OSDArray(1); + OSDMap parcelDataMap = new OSDMap(47); + parcelDataMap["LocalID"] = OSD.FromInteger(LocalID); + parcelDataMap["AABBMax"] = OSD.FromVector3(AABBMax); + parcelDataMap["AABBMin"] = OSD.FromVector3(AABBMin); + parcelDataMap["Area"] = OSD.FromInteger(Area); + parcelDataMap["AuctionID"] = OSD.FromInteger(AuctionID); + parcelDataMap["AuthBuyerID"] = OSD.FromUUID(AuthBuyerID); + parcelDataMap["Bitmap"] = OSD.FromBinary(Bitmap); + parcelDataMap["Category"] = OSD.FromInteger((int)Category); + parcelDataMap["ClaimDate"] = OSD.FromDate(ClaimDate); + parcelDataMap["ClaimPrice"] = OSD.FromInteger(ClaimPrice); + parcelDataMap["Desc"] = OSD.FromString(Desc); + parcelDataMap["ParcelFlags"] = OSD.FromUInteger((uint)ParcelFlags); + parcelDataMap["GroupID"] = OSD.FromUUID(GroupID); + parcelDataMap["GroupPrims"] = OSD.FromInteger(GroupPrims); + parcelDataMap["IsGroupOwned"] = OSD.FromBoolean(IsGroupOwned); + parcelDataMap["LandingType"] = OSD.FromInteger((int)LandingType); + parcelDataMap["MaxPrims"] = OSD.FromInteger(MaxPrims); + parcelDataMap["MediaID"] = OSD.FromUUID(MediaID); + parcelDataMap["MediaURL"] = OSD.FromString(MediaURL); + parcelDataMap["MediaAutoScale"] = OSD.FromBoolean(MediaAutoScale); + parcelDataMap["MusicURL"] = OSD.FromString(MusicURL); + parcelDataMap["Name"] = OSD.FromString(Name); + parcelDataMap["OtherCleanTime"] = OSD.FromInteger(OtherCleanTime); + parcelDataMap["OtherCount"] = OSD.FromInteger(OtherCount); + parcelDataMap["OtherPrims"] = OSD.FromInteger(OtherPrims); + parcelDataMap["OwnerID"] = OSD.FromUUID(OwnerID); + parcelDataMap["OwnerPrims"] = OSD.FromInteger(OwnerPrims); + parcelDataMap["ParcelPrimBonus"] = OSD.FromReal((float)ParcelPrimBonus); + parcelDataMap["PassHours"] = OSD.FromReal((float)PassHours); + parcelDataMap["PassPrice"] = OSD.FromInteger(PassPrice); + parcelDataMap["PublicCount"] = OSD.FromInteger(PublicCount); + parcelDataMap["Privacy"] = OSD.FromBoolean(Privacy); + parcelDataMap["RegionDenyAnonymous"] = OSD.FromBoolean(RegionDenyAnonymous); + parcelDataMap["RegionDenyIdentified"] = OSD.FromBoolean(RegionDenyIdentified); + parcelDataMap["RegionDenyTransacted"] = OSD.FromBoolean(RegionDenyTransacted); + parcelDataMap["RegionPushOverride"] = OSD.FromBoolean(RegionPushOverride); + parcelDataMap["RentPrice"] = OSD.FromInteger(RentPrice); + parcelDataMap["RequestResult"] = OSD.FromInteger((int)RequestResult); + parcelDataMap["SalePrice"] = OSD.FromInteger(SalePrice); + parcelDataMap["SelectedPrims"] = OSD.FromInteger(SelectedPrims); + parcelDataMap["SelfCount"] = OSD.FromInteger(SelfCount); + parcelDataMap["SequenceID"] = OSD.FromInteger(SequenceID); + parcelDataMap["SimWideMaxPrims"] = OSD.FromInteger(SimWideMaxPrims); + parcelDataMap["SimWideTotalPrims"] = OSD.FromInteger(SimWideTotalPrims); + parcelDataMap["SnapSelection"] = OSD.FromBoolean(SnapSelection); + parcelDataMap["SnapshotID"] = OSD.FromUUID(SnapshotID); + parcelDataMap["Status"] = OSD.FromInteger((int)Status); + parcelDataMap["TotalPrims"] = OSD.FromInteger(TotalPrims); + parcelDataMap["UserLocation"] = OSD.FromVector3(UserLocation); + parcelDataMap["UserLookAt"] = OSD.FromVector3(UserLookAt); + parcelDataMap["SeeAVs"] = OSD.FromBoolean(SeeAVs); + parcelDataMap["AnyAVSounds"] = OSD.FromBoolean(AnyAVSounds); + parcelDataMap["GroupAVSounds"] = OSD.FromBoolean(GroupAVSounds); + dataArray.Add(parcelDataMap); + map["ParcelData"] = dataArray; + + OSDArray mediaDataArray = new OSDArray(1); + OSDMap mediaDataMap = new OSDMap(7); + mediaDataMap["MediaDesc"] = OSD.FromString(MediaDesc); + mediaDataMap["MediaHeight"] = OSD.FromInteger(MediaHeight); + mediaDataMap["MediaWidth"] = OSD.FromInteger(MediaWidth); + mediaDataMap["MediaLoop"] = OSD.FromBoolean(MediaLoop); + mediaDataMap["MediaType"] = OSD.FromString(MediaType); + mediaDataMap["ObscureMedia"] = OSD.FromBoolean(ObscureMedia); + mediaDataMap["ObscureMusic"] = OSD.FromBoolean(ObscureMusic); + mediaDataArray.Add(mediaDataMap); + map["MediaData"] = mediaDataArray; + + OSDArray ageVerificationBlockArray = new OSDArray(1); + OSDMap ageVerificationBlockMap = new OSDMap(1); + ageVerificationBlockMap["RegionDenyAgeUnverified"] = OSD.FromBoolean(RegionDenyAgeUnverified); + ageVerificationBlockArray.Add(ageVerificationBlockMap); + map["AgeVerificationBlock"] = ageVerificationBlockArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDMap parcelDataMap = (OSDMap)((OSDArray)map["ParcelData"])[0]; + LocalID = parcelDataMap["LocalID"].AsInteger(); + AABBMax = parcelDataMap["AABBMax"].AsVector3(); + AABBMin = parcelDataMap["AABBMin"].AsVector3(); + Area = parcelDataMap["Area"].AsInteger(); + AuctionID = (uint)parcelDataMap["AuctionID"].AsInteger(); + AuthBuyerID = parcelDataMap["AuthBuyerID"].AsUUID(); + Bitmap = parcelDataMap["Bitmap"].AsBinary(); + Category = (ParcelCategory)parcelDataMap["Category"].AsInteger(); + ClaimDate = Utils.UnixTimeToDateTime((uint)parcelDataMap["ClaimDate"].AsInteger()); + ClaimPrice = parcelDataMap["ClaimPrice"].AsInteger(); + Desc = parcelDataMap["Desc"].AsString(); + + // LL sends this as binary, we'll convert it here + if (parcelDataMap["ParcelFlags"].Type == OSDType.Binary) + { + byte[] bytes = parcelDataMap["ParcelFlags"].AsBinary(); + if (BitConverter.IsLittleEndian) + Array.Reverse(bytes); + ParcelFlags = (ParcelFlags)BitConverter.ToUInt32(bytes, 0); + } + else + { + ParcelFlags = (ParcelFlags)parcelDataMap["ParcelFlags"].AsUInteger(); + } + GroupID = parcelDataMap["GroupID"].AsUUID(); + GroupPrims = parcelDataMap["GroupPrims"].AsInteger(); + IsGroupOwned = parcelDataMap["IsGroupOwned"].AsBoolean(); + LandingType = (LandingType)parcelDataMap["LandingType"].AsInteger(); + MaxPrims = parcelDataMap["MaxPrims"].AsInteger(); + MediaID = parcelDataMap["MediaID"].AsUUID(); + MediaURL = parcelDataMap["MediaURL"].AsString(); + MediaAutoScale = parcelDataMap["MediaAutoScale"].AsBoolean(); // 0x1 = yes + MusicURL = parcelDataMap["MusicURL"].AsString(); + Name = parcelDataMap["Name"].AsString(); + OtherCleanTime = parcelDataMap["OtherCleanTime"].AsInteger(); + OtherCount = parcelDataMap["OtherCount"].AsInteger(); + OtherPrims = parcelDataMap["OtherPrims"].AsInteger(); + OwnerID = parcelDataMap["OwnerID"].AsUUID(); + OwnerPrims = parcelDataMap["OwnerPrims"].AsInteger(); + ParcelPrimBonus = (float)parcelDataMap["ParcelPrimBonus"].AsReal(); + PassHours = (float)parcelDataMap["PassHours"].AsReal(); + PassPrice = parcelDataMap["PassPrice"].AsInteger(); + PublicCount = parcelDataMap["PublicCount"].AsInteger(); + Privacy = parcelDataMap["Privacy"].AsBoolean(); + RegionDenyAnonymous = parcelDataMap["RegionDenyAnonymous"].AsBoolean(); + RegionDenyIdentified = parcelDataMap["RegionDenyIdentified"].AsBoolean(); + RegionDenyTransacted = parcelDataMap["RegionDenyTransacted"].AsBoolean(); + RegionPushOverride = parcelDataMap["RegionPushOverride"].AsBoolean(); + RentPrice = parcelDataMap["RentPrice"].AsInteger(); + RequestResult = (ParcelResult)parcelDataMap["RequestResult"].AsInteger(); + SalePrice = parcelDataMap["SalePrice"].AsInteger(); + SelectedPrims = parcelDataMap["SelectedPrims"].AsInteger(); + SelfCount = parcelDataMap["SelfCount"].AsInteger(); + SequenceID = parcelDataMap["SequenceID"].AsInteger(); + SimWideMaxPrims = parcelDataMap["SimWideMaxPrims"].AsInteger(); + SimWideTotalPrims = parcelDataMap["SimWideTotalPrims"].AsInteger(); + SnapSelection = parcelDataMap["SnapSelection"].AsBoolean(); + SnapshotID = parcelDataMap["SnapshotID"].AsUUID(); + Status = (ParcelStatus)parcelDataMap["Status"].AsInteger(); + TotalPrims = parcelDataMap["TotalPrims"].AsInteger(); + UserLocation = parcelDataMap["UserLocation"].AsVector3(); + UserLookAt = parcelDataMap["UserLookAt"].AsVector3(); + SeeAVs = parcelDataMap["SeeAVs"].AsBoolean(); + AnyAVSounds = parcelDataMap["AnyAVSounds"].AsBoolean(); + GroupAVSounds = parcelDataMap["GroupAVSounds"].AsBoolean(); + + if (map.ContainsKey("MediaData")) // temporary, OpenSim doesn't send this block + { + OSDMap mediaDataMap = (OSDMap)((OSDArray)map["MediaData"])[0]; + MediaDesc = mediaDataMap["MediaDesc"].AsString(); + MediaHeight = mediaDataMap["MediaHeight"].AsInteger(); + MediaWidth = mediaDataMap["MediaWidth"].AsInteger(); + MediaLoop = mediaDataMap["MediaLoop"].AsBoolean(); + MediaType = mediaDataMap["MediaType"].AsString(); + ObscureMedia = mediaDataMap["ObscureMedia"].AsBoolean(); + ObscureMusic = mediaDataMap["ObscureMusic"].AsBoolean(); + } + + OSDMap ageVerificationBlockMap = (OSDMap)((OSDArray)map["AgeVerificationBlock"])[0]; + RegionDenyAgeUnverified = ageVerificationBlockMap["RegionDenyAgeUnverified"].AsBoolean(); + } + } + + /// A message sent from the viewer to the simulator to updated a specific parcels settings + public class ParcelPropertiesUpdateMessage : IMessage + { + /// The of the agent authorized to purchase this + /// parcel of land or a NULL if the sale is authorized to anyone + public UUID AuthBuyerID; + /// true to enable auto scaling of the parcel media + public bool MediaAutoScale; + /// The category of this parcel used when search is enabled to restrict + /// search results + public ParcelCategory Category; + /// A string containing the description to set + public string Desc; + /// The of the which allows for additional + /// powers and restrictions. + public UUID GroupID; + /// The which specifies how avatars which teleport + /// to this parcel are handled + public LandingType Landing; + /// The LocalID of the parcel to update settings on + public int LocalID; + /// A string containing the description of the media which can be played + /// to visitors + public string MediaDesc; + /// + public int MediaHeight; + /// + public bool MediaLoop; + /// + public UUID MediaID; + /// + public string MediaType; + /// + public string MediaURL; + /// + public int MediaWidth; + /// + public string MusicURL; + /// + public string Name; + /// + public bool ObscureMedia; + /// + public bool ObscureMusic; + /// + public ParcelFlags ParcelFlags; + /// + public float PassHours; + /// + public uint PassPrice; + /// + public bool Privacy; + /// + public uint SalePrice; + /// + public UUID SnapshotID; + /// + public Vector3 UserLocation; + /// + public Vector3 UserLookAt; + /// true if avatars in this parcel should be invisible to people outside + public bool SeeAVs; + /// true if avatars outside can hear any sounds avatars inside play + public bool AnyAVSounds; + /// true if group members outside can hear any sounds avatars inside play + public bool GroupAVSounds; + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + AuthBuyerID = map["auth_buyer_id"].AsUUID(); + MediaAutoScale = map["auto_scale"].AsBoolean(); + Category = (ParcelCategory)map["category"].AsInteger(); + Desc = map["description"].AsString(); + GroupID = map["group_id"].AsUUID(); + Landing = (LandingType)map["landing_type"].AsUInteger(); + LocalID = map["local_id"].AsInteger(); + MediaDesc = map["media_desc"].AsString(); + MediaHeight = map["media_height"].AsInteger(); + MediaLoop = map["media_loop"].AsBoolean(); + MediaID = map["media_id"].AsUUID(); + MediaType = map["media_type"].AsString(); + MediaURL = map["media_url"].AsString(); + MediaWidth = map["media_width"].AsInteger(); + MusicURL = map["music_url"].AsString(); + Name = map["name"].AsString(); + ObscureMedia = map["obscure_media"].AsBoolean(); + ObscureMusic = map["obscure_music"].AsBoolean(); + ParcelFlags = (ParcelFlags)map["parcel_flags"].AsUInteger(); + PassHours = (float)map["pass_hours"].AsReal(); + PassPrice = map["pass_price"].AsUInteger(); + Privacy = map["privacy"].AsBoolean(); + SalePrice = map["sale_price"].AsUInteger(); + SnapshotID = map["snapshot_id"].AsUUID(); + UserLocation = map["user_location"].AsVector3(); + UserLookAt = map["user_look_at"].AsVector3(); + if (map.ContainsKey("see_avs")) + { + SeeAVs = map["see_avs"].AsBoolean(); + AnyAVSounds = map["any_av_sounds"].AsBoolean(); + GroupAVSounds = map["group_av_sounds"].AsBoolean(); + } + else + { + SeeAVs = true; + AnyAVSounds = true; + GroupAVSounds = true; + } + } + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["auth_buyer_id"] = OSD.FromUUID(AuthBuyerID); + map["auto_scale"] = OSD.FromBoolean(MediaAutoScale); + map["category"] = OSD.FromInteger((byte)Category); + map["description"] = OSD.FromString(Desc); + map["flags"] = OSD.FromBinary(Utils.EmptyBytes); + map["group_id"] = OSD.FromUUID(GroupID); + map["landing_type"] = OSD.FromInteger((byte)Landing); + map["local_id"] = OSD.FromInteger(LocalID); + map["media_desc"] = OSD.FromString(MediaDesc); + map["media_height"] = OSD.FromInteger(MediaHeight); + map["media_id"] = OSD.FromUUID(MediaID); + map["media_loop"] = OSD.FromBoolean(MediaLoop); + map["media_type"] = OSD.FromString(MediaType); + map["media_url"] = OSD.FromString(MediaURL); + map["media_width"] = OSD.FromInteger(MediaWidth); + map["music_url"] = OSD.FromString(MusicURL); + map["name"] = OSD.FromString(Name); + map["obscure_media"] = OSD.FromBoolean(ObscureMedia); + map["obscure_music"] = OSD.FromBoolean(ObscureMusic); + map["parcel_flags"] = OSD.FromUInteger((uint)ParcelFlags); + map["pass_hours"] = OSD.FromReal(PassHours); + map["privacy"] = OSD.FromBoolean(Privacy); + map["pass_price"] = OSD.FromInteger(PassPrice); + map["sale_price"] = OSD.FromInteger(SalePrice); + map["snapshot_id"] = OSD.FromUUID(SnapshotID); + map["user_location"] = OSD.FromVector3(UserLocation); + map["user_look_at"] = OSD.FromVector3(UserLookAt); + map["see_avs"] = OSD.FromBoolean(SeeAVs); + map["any_av_sounds"] = OSD.FromBoolean(AnyAVSounds); + map["group_av_sounds"] = OSD.FromBoolean(GroupAVSounds); + + return map; + } + } + + /// Base class used for the RemoteParcelRequest message + [Serializable] + public abstract class RemoteParcelRequestBlock + { + public abstract OSDMap Serialize(); + public abstract void Deserialize(OSDMap map); + } + + /// + /// A message sent from the viewer to the simulator to request information + /// on a remote parcel + /// + public class RemoteParcelRequestRequest : RemoteParcelRequestBlock + { + /// Local sim position of the parcel we are looking up + public Vector3 Location; + /// Region handle of the parcel we are looking up + public ulong RegionHandle; + /// Region of the parcel we are looking up + public UUID RegionID; + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + map["location"] = OSD.FromVector3(Location); + map["region_handle"] = OSD.FromULong(RegionHandle); + map["region_id"] = OSD.FromUUID(RegionID); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + Location = map["location"].AsVector3(); + RegionHandle = map["region_handle"].AsULong(); + RegionID = map["region_id"].AsUUID(); + } + } + + /// + /// A message sent from the simulator to the viewer in response to a + /// which will contain parcel information + /// + [Serializable] + public class RemoteParcelRequestReply : RemoteParcelRequestBlock + { + /// The grid-wide unique parcel ID + public UUID ParcelID; + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + map["parcel_id"] = OSD.FromUUID(ParcelID); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + if (map == null || !map.ContainsKey("parcel_id")) + ParcelID = UUID.Zero; + else + ParcelID = map["parcel_id"].AsUUID(); + } + } + + /// + /// A message containing a request for a remote parcel from a viewer, or a response + /// from the simulator to that request + /// + [Serializable] + public class RemoteParcelRequestMessage : IMessage + { + /// The request or response details block + public RemoteParcelRequestBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("parcel_id")) + Request = new RemoteParcelRequestReply(); + else if (map.ContainsKey("location")) + Request = new RemoteParcelRequestRequest(); + else + Logger.Log("Unable to deserialize RemoteParcelRequest: No message handler exists for method: " + map.AsString(), Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + #endregion + + #region Inventory Messages + + public class NewFileAgentInventoryMessage : IMessage + { + public UUID FolderID; + public AssetType AssetType; + public InventoryType InventoryType; + public string Name; + public string Description; + public PermissionMask EveryoneMask; + public PermissionMask GroupMask; + public PermissionMask NextOwnerMask; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(5); + map["folder_id"] = OSD.FromUUID(FolderID); + map["asset_type"] = OSD.FromString(Utils.AssetTypeToString(AssetType)); + map["inventory_type"] = OSD.FromString(Utils.InventoryTypeToString(InventoryType)); + map["name"] = OSD.FromString(Name); + map["description"] = OSD.FromString(Description); + map["everyone_mask"] = OSD.FromInteger((int)EveryoneMask); + map["group_mask"] = OSD.FromInteger((int)GroupMask); + map["next_owner_mask"] = OSD.FromInteger((int)NextOwnerMask); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + FolderID = map["folder_id"].AsUUID(); + AssetType = Utils.StringToAssetType(map["asset_type"].AsString()); + InventoryType = Utils.StringToInventoryType(map["inventory_type"].AsString()); + Name = map["name"].AsString(); + Description = map["description"].AsString(); + EveryoneMask = (PermissionMask)map["everyone_mask"].AsInteger(); + GroupMask = (PermissionMask)map["group_mask"].AsInteger(); + NextOwnerMask = (PermissionMask)map["next_owner_mask"].AsInteger(); + } + } + + public class NewFileAgentInventoryReplyMessage : IMessage + { + public string State; + public Uri Uploader; + + public NewFileAgentInventoryReplyMessage() + { + State = "upload"; + } + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["state"] = OSD.FromString(State); + map["uploader"] = OSD.FromUri(Uploader); + + return map; + } + + public void Deserialize(OSDMap map) + { + State = map["state"].AsString(); + Uploader = map["uploader"].AsUri(); + } + } + + public class NewFileAgentInventoryVariablePriceMessage : IMessage + { + public UUID FolderID; + public AssetType AssetType; + public InventoryType InventoryType; + public string Name; + public string Description; + public PermissionMask EveryoneMask; + public PermissionMask GroupMask; + public PermissionMask NextOwnerMask; + // TODO: asset_resources? + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["folder_id"] = OSD.FromUUID(FolderID); + map["asset_type"] = OSD.FromString(Utils.AssetTypeToString(AssetType)); + map["inventory_type"] = OSD.FromString(Utils.InventoryTypeToString(InventoryType)); + map["name"] = OSD.FromString(Name); + map["description"] = OSD.FromString(Description); + map["everyone_mask"] = OSD.FromInteger((int)EveryoneMask); + map["group_mask"] = OSD.FromInteger((int)GroupMask); + map["next_owner_mask"] = OSD.FromInteger((int)NextOwnerMask); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + FolderID = map["folder_id"].AsUUID(); + AssetType = Utils.StringToAssetType(map["asset_type"].AsString()); + InventoryType = Utils.StringToInventoryType(map["inventory_type"].AsString()); + Name = map["name"].AsString(); + Description = map["description"].AsString(); + EveryoneMask = (PermissionMask)map["everyone_mask"].AsInteger(); + GroupMask = (PermissionMask)map["group_mask"].AsInteger(); + NextOwnerMask = (PermissionMask)map["next_owner_mask"].AsInteger(); + } + } + + public class NewFileAgentInventoryVariablePriceReplyMessage : IMessage + { + public int ResourceCost; + public string State; + public int UploadPrice; + public Uri Rsvp; + + public NewFileAgentInventoryVariablePriceReplyMessage() + { + State = "confirm_upload"; + } + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["resource_cost"] = OSD.FromInteger(ResourceCost); + map["state"] = OSD.FromString(State); + map["upload_price"] = OSD.FromInteger(UploadPrice); + map["rsvp"] = OSD.FromUri(Rsvp); + + return map; + } + + public void Deserialize(OSDMap map) + { + ResourceCost = map["resource_cost"].AsInteger(); + State = map["state"].AsString(); + UploadPrice = map["upload_price"].AsInteger(); + Rsvp = map["rsvp"].AsUri(); + } + } + + public class NewFileAgentInventoryUploadReplyMessage : IMessage + { + public UUID NewInventoryItem; + public UUID NewAsset; + public string State; + public PermissionMask NewBaseMask; + public PermissionMask NewEveryoneMask; + public PermissionMask NewOwnerMask; + public PermissionMask NewNextOwnerMask; + + public NewFileAgentInventoryUploadReplyMessage() + { + State = "complete"; + } + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["new_inventory_item"] = OSD.FromUUID(NewInventoryItem); + map["new_asset"] = OSD.FromUUID(NewAsset); + map["state"] = OSD.FromString(State); + map["new_base_mask"] = OSD.FromInteger((int)NewBaseMask); + map["new_everyone_mask"] = OSD.FromInteger((int)NewEveryoneMask); + map["new_owner_mask"] = OSD.FromInteger((int)NewOwnerMask); + map["new_next_owner_mask"] = OSD.FromInteger((int)NewNextOwnerMask); + + return map; + } + + public void Deserialize(OSDMap map) + { + NewInventoryItem = map["new_inventory_item"].AsUUID(); + NewAsset = map["new_asset"].AsUUID(); + State = map["state"].AsString(); + NewBaseMask = (PermissionMask)map["new_base_mask"].AsInteger(); + NewEveryoneMask = (PermissionMask)map["new_everyone_mask"].AsInteger(); + NewOwnerMask = (PermissionMask)map["new_owner_mask"].AsInteger(); + NewNextOwnerMask = (PermissionMask)map["new_next_owner_mask"].AsInteger(); + } + } + + public class BulkUpdateInventoryMessage : IMessage + { + public class FolderDataInfo + { + public UUID FolderID; + public UUID ParentID; + public string Name; + public AssetType Type; + + public static FolderDataInfo FromOSD(OSD data) + { + FolderDataInfo ret = new FolderDataInfo(); + + if (!(data is OSDMap)) return ret; + + OSDMap map = (OSDMap)data; + + ret.FolderID = map["FolderID"]; + ret.ParentID = map["ParentID"]; + ret.Name = map["Name"]; + ret.Type = (AssetType)map["Type"].AsInteger(); + return ret; + } + } + + public class ItemDataInfo + { + public UUID ItemID; + public uint CallbackID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public PermissionMask BaseMask; + public PermissionMask OwnerMask; + public PermissionMask GroupMask; + public PermissionMask EveryoneMask; + public PermissionMask NextOwnerMask; + public bool GroupOwned; + public UUID AssetID; + public AssetType Type; + public InventoryType InvType; + public uint Flags; + public SaleType SaleType; + public int SalePrice; + public string Name; + public string Description; + public DateTime CreationDate; + public uint CRC; + + public static ItemDataInfo FromOSD(OSD data) + { + ItemDataInfo ret = new ItemDataInfo(); + + if (!(data is OSDMap)) return ret; + + OSDMap map = (OSDMap)data; + + ret.ItemID = map["ItemID"]; + ret.CallbackID = map["CallbackID"]; + ret.FolderID = map["FolderID"]; + ret.CreatorID = map["CreatorID"]; + ret.OwnerID = map["OwnerID"]; + ret.GroupID = map["GroupID"]; + ret.BaseMask = (PermissionMask)map["BaseMask"].AsUInteger(); + ret.OwnerMask = (PermissionMask)map["OwnerMask"].AsUInteger(); + ret.GroupMask = (PermissionMask)map["GroupMask"].AsUInteger(); + ret.EveryoneMask = (PermissionMask)map["EveryoneMask"].AsUInteger(); + ret.NextOwnerMask = (PermissionMask)map["NextOwnerMask"].AsUInteger(); + ret.GroupOwned = map["GroupOwned"]; + ret.AssetID = map["AssetID"]; + ret.Type = (AssetType)map["Type"].AsInteger(); + ret.InvType = (InventoryType)map["InvType"].AsInteger(); + ret.Flags = map["Flags"]; + ret.SaleType = (SaleType)map["SaleType"].AsInteger(); + ret.SalePrice = map["SaleType"]; + ret.Name = map["Name"]; + ret.Description = map["Description"]; + ret.CreationDate = Utils.UnixTimeToDateTime(map["CreationDate"]); + ret.CRC = map["CRC"]; + + return ret; + } + } + + public UUID AgentID; + public UUID TransactionID; + public FolderDataInfo[] FolderData; + public ItemDataInfo[] ItemData; + + public OSDMap Serialize() + { + throw new NotImplementedException(); + } + + public void Deserialize(OSDMap map) + { + if (map["AgentData"] is OSDArray) + { + OSDArray array = (OSDArray)map["AgentData"]; + if (array.Count > 0) + { + OSDMap adata = (OSDMap)array[0]; + AgentID = adata["AgentID"]; + TransactionID = adata["TransactionID"]; + } + } + + if (map["FolderData"] is OSDArray) + { + OSDArray array = (OSDArray)map["FolderData"]; + FolderData = new FolderDataInfo[array.Count]; + for (int i = 0; i < array.Count; i++) + { + FolderData[i] = FolderDataInfo.FromOSD(array[i]); + } + } + else + { + FolderData = new FolderDataInfo[0]; + } + + if (map["ItemData"] is OSDArray) + { + OSDArray array = (OSDArray)map["ItemData"]; + ItemData = new ItemDataInfo[array.Count]; + for (int i = 0; i < array.Count; i++) + { + ItemData[i] = ItemDataInfo.FromOSD(array[i]); + } + } + else + { + ItemData = new ItemDataInfo[0]; + } + } + } + + #endregion + + #region Agent Messages + + /// + /// A message sent from the simulator to an agent which contains + /// the groups the agent is in + /// + public class AgentGroupDataUpdateMessage : IMessage + { + /// The Agent receiving the message + public UUID AgentID; + + /// Group Details specific to the agent + public class GroupData + { + /// true of the agent accepts group notices + public bool AcceptNotices; + /// The agents tier contribution to the group + public int Contribution; + /// The Groups + public UUID GroupID; + /// The of the groups insignia + public UUID GroupInsigniaID; + /// The name of the group + public string GroupName; + /// The aggregate permissions the agent has in the group for all roles the agent + /// is assigned + public GroupPowers GroupPowers; + } + + /// An optional block containing additional agent specific information + public class NewGroupData + { + /// true of the agent allows this group to be + /// listed in their profile + public bool ListInProfile; + } + + /// An array containing information + /// for each the agent is a member of + public GroupData[] GroupDataBlock; + /// An array containing information + /// for each the agent is a member of + public NewGroupData[] NewGroupDataBlock; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + + OSDMap agent = new OSDMap(1); + agent["AgentID"] = OSD.FromUUID(AgentID); + + OSDArray agentArray = new OSDArray(); + agentArray.Add(agent); + + map["AgentData"] = agentArray; + + OSDArray groupDataArray = new OSDArray(GroupDataBlock.Length); + + for (int i = 0; i < GroupDataBlock.Length; i++) + { + OSDMap group = new OSDMap(6); + group["AcceptNotices"] = OSD.FromBoolean(GroupDataBlock[i].AcceptNotices); + group["Contribution"] = OSD.FromInteger(GroupDataBlock[i].Contribution); + group["GroupID"] = OSD.FromUUID(GroupDataBlock[i].GroupID); + group["GroupInsigniaID"] = OSD.FromUUID(GroupDataBlock[i].GroupInsigniaID); + group["GroupName"] = OSD.FromString(GroupDataBlock[i].GroupName); + group["GroupPowers"] = OSD.FromLong((long)GroupDataBlock[i].GroupPowers); + groupDataArray.Add(group); + } + + map["GroupData"] = groupDataArray; + + OSDArray newGroupDataArray = new OSDArray(NewGroupDataBlock.Length); + + for (int i = 0; i < NewGroupDataBlock.Length; i++) + { + OSDMap group = new OSDMap(1); + group["ListInProfile"] = OSD.FromBoolean(NewGroupDataBlock[i].ListInProfile); + newGroupDataArray.Add(group); + } + + map["NewGroupData"] = newGroupDataArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray agentArray = (OSDArray)map["AgentData"]; + OSDMap agentMap = (OSDMap)agentArray[0]; + AgentID = agentMap["AgentID"].AsUUID(); + + OSDArray groupArray = (OSDArray)map["GroupData"]; + + GroupDataBlock = new GroupData[groupArray.Count]; + + for (int i = 0; i < groupArray.Count; i++) + { + OSDMap groupMap = (OSDMap)groupArray[i]; + + GroupData groupData = new GroupData(); + + groupData.GroupID = groupMap["GroupID"].AsUUID(); + groupData.Contribution = groupMap["Contribution"].AsInteger(); + groupData.GroupInsigniaID = groupMap["GroupInsigniaID"].AsUUID(); + groupData.GroupName = groupMap["GroupName"].AsString(); + groupData.GroupPowers = (GroupPowers)groupMap["GroupPowers"].AsLong(); + groupData.AcceptNotices = groupMap["AcceptNotices"].AsBoolean(); + GroupDataBlock[i] = groupData; + } + + // If request for current groups came very close to login + // the Linden sim will not include the NewGroupData block, but + // it will instead set all ListInProfile fields to false + if (map.ContainsKey("NewGroupData")) + { + OSDArray newGroupArray = (OSDArray)map["NewGroupData"]; + + NewGroupDataBlock = new NewGroupData[newGroupArray.Count]; + + for (int i = 0; i < newGroupArray.Count; i++) + { + OSDMap newGroupMap = (OSDMap)newGroupArray[i]; + NewGroupData newGroupData = new NewGroupData(); + newGroupData.ListInProfile = newGroupMap["ListInProfile"].AsBoolean(); + NewGroupDataBlock[i] = newGroupData; + } + } + else + { + NewGroupDataBlock = new NewGroupData[GroupDataBlock.Length]; + for (int i = 0; i < NewGroupDataBlock.Length; i++) + { + NewGroupData newGroupData = new NewGroupData(); + newGroupData.ListInProfile = false; + NewGroupDataBlock[i] = newGroupData; + } + } + } + } + + /// + /// A message sent from the viewer to the simulator which + /// specifies the language and permissions for others to detect + /// the language specified + /// + public class UpdateAgentLanguageMessage : IMessage + { + /// A string containng the default language + /// to use for the agent + public string Language; + /// true of others are allowed to + /// know the language setting + public bool LanguagePublic; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + + map["language"] = OSD.FromString(Language); + map["language_is_public"] = OSD.FromBoolean(LanguagePublic); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + LanguagePublic = map["language_is_public"].AsBoolean(); + Language = map["language"].AsString(); + } + } + + /// + /// An EventQueue message sent from the simulator to an agent when the agent + /// leaves a group + /// + public class AgentDropGroupMessage : IMessage + { + /// An object containing the Agents UUID, and the Groups UUID + public class AgentData + { + /// The ID of the Agent leaving the group + public UUID AgentID; + /// The GroupID the Agent is leaving + public UUID GroupID; + } + + /// + /// An Array containing the AgentID and GroupID + /// + public AgentData[] AgentDataBlock; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + + OSDArray agentDataArray = new OSDArray(AgentDataBlock.Length); + + for (int i = 0; i < AgentDataBlock.Length; i++) + { + OSDMap agentMap = new OSDMap(2); + agentMap["AgentID"] = OSD.FromUUID(AgentDataBlock[i].AgentID); + agentMap["GroupID"] = OSD.FromUUID(AgentDataBlock[i].GroupID); + agentDataArray.Add(agentMap); + } + map["AgentData"] = agentDataArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray agentDataArray = (OSDArray)map["AgentData"]; + + AgentDataBlock = new AgentData[agentDataArray.Count]; + + for (int i = 0; i < agentDataArray.Count; i++) + { + OSDMap agentMap = (OSDMap)agentDataArray[i]; + AgentData agentData = new AgentData(); + + agentData.AgentID = agentMap["AgentID"].AsUUID(); + agentData.GroupID = agentMap["GroupID"].AsUUID(); + + AgentDataBlock[i] = agentData; + } + } + } + + public class AgentStateUpdateMessage : IMessage + { + public OSDMap RawData; + public bool CanModifyNavmesh; + public bool HasModifiedNavmesh; + public string MaxAccess; // PG, M, A + public bool AlterNavmeshObjects; + public bool AlterPermanentObjects; + public int GodLevel; + public string Language; + public bool LanguageIsPublic; + + public void Deserialize(OSDMap map) + { + RawData = map; + CanModifyNavmesh = map["can_modify_navmesh"]; + HasModifiedNavmesh = map["has_modified_navmesh"]; + if (map["preferences"] is OSDMap) + { + var prefs = (OSDMap)map["preferences"]; + AlterNavmeshObjects = prefs["alter_navmesh_objects"]; + AlterPermanentObjects = prefs["alter_permanent_objects"]; + GodLevel = prefs["god_level"]; + Language = prefs["language"]; + LanguageIsPublic = prefs["language_is_public"]; + if (prefs["access_prefs"] is OSDMap) + { + var access = (OSDMap)prefs["access_prefs"]; + MaxAccess = access["max"]; + } + } + } + + public OSDMap Serialize() + { + RawData = new OSDMap(); + RawData["can_modify_navmesh"] = CanModifyNavmesh; + RawData["has_modified_navmesh"] = HasModifiedNavmesh; + + OSDMap prefs = new OSDMap(); + { + OSDMap access = new OSDMap(); + { + access["max"] = MaxAccess; + } + prefs["access_prefs"] = access; + prefs["alter_navmesh_objects"] = AlterNavmeshObjects; + prefs["alter_permanent_objects"] = AlterPermanentObjects; + prefs["god_level"] = GodLevel; + prefs["language"] = Language; + prefs["language_is_public"] = LanguageIsPublic; + } + RawData["preferences"] = prefs; + return RawData; + } + + } + + /// Base class for Asset uploads/results via Capabilities + public abstract class AssetUploaderBlock + { + /// + /// The request state + /// + public string State; + + /// + /// Serialize the object + /// + /// An containing the objects data + public abstract OSDMap Serialize(); + + /// + /// Deserialize the message + /// + /// An containing the data + public abstract void Deserialize(OSDMap map); + } + + /// + /// A message sent from the viewer to the simulator to request a temporary upload capability + /// which allows an asset to be uploaded + /// + public class UploaderRequestUpload : AssetUploaderBlock + { + /// The Capability URL sent by the simulator to upload the baked texture to + public Uri Url; + + public UploaderRequestUpload() + { + State = "upload"; + } + + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["state"] = OSD.FromString(State); + map["uploader"] = OSD.FromUri(Url); + + return map; + } + + public override void Deserialize(OSDMap map) + { + Url = map["uploader"].AsUri(); + State = map["state"].AsString(); + } + } + + /// + /// A message sent from the simulator that will inform the agent the upload is complete, + /// and the UUID of the uploaded asset + /// + public class UploaderRequestComplete : AssetUploaderBlock + { + /// The uploaded texture asset ID + public UUID AssetID; + + public UploaderRequestComplete() + { + State = "complete"; + } + + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["state"] = OSD.FromString(State); + map["new_asset"] = OSD.FromUUID(AssetID); + + return map; + } + + public override void Deserialize(OSDMap map) + { + AssetID = map["new_asset"].AsUUID(); + State = map["state"].AsString(); + } + } + + /// + /// A message sent from the viewer to the simulator to request a temporary + /// capability URI which is used to upload an agents baked appearance textures + /// + public class UploadBakedTextureMessage : IMessage + { + /// Object containing request or response + public AssetUploaderBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("state") && map["state"].AsString().Equals("upload")) + Request = new UploaderRequestUpload(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("complete")) + Request = new UploaderRequestComplete(); + else + Logger.Log("Unable to deserialize UploadBakedTexture: No message handler exists for state " + map["state"].AsString(), Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + #endregion + + #region Voice Messages + /// + /// A message sent from the simulator which indicates the minimum version required for + /// using voice chat + /// + public class RequiredVoiceVersionMessage : IMessage + { + /// Major Version Required + public int MajorVersion; + /// Minor version required + public int MinorVersion; + /// The name of the region sending the version requrements + public string RegionName; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(4); + map["major_version"] = OSD.FromInteger(MajorVersion); + map["minor_version"] = OSD.FromInteger(MinorVersion); + map["region_name"] = OSD.FromString(RegionName); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + MajorVersion = map["major_version"].AsInteger(); + MinorVersion = map["minor_version"].AsInteger(); + RegionName = map["region_name"].AsString(); + } + } + + /// + /// A message sent from the simulator to the viewer containing the + /// voice server URI + /// + public class ParcelVoiceInfoRequestMessage : IMessage + { + /// The Parcel ID which the voice server URI applies + public int ParcelID; + /// The name of the region + public string RegionName; + /// A uri containing the server/channel information + /// which the viewer can utilize to participate in voice conversations + public Uri SipChannelUri; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + map["parcel_local_id"] = OSD.FromInteger(ParcelID); + map["region_name"] = OSD.FromString(RegionName); + + OSDMap vcMap = new OSDMap(1); + vcMap["channel_uri"] = OSD.FromUri(SipChannelUri); + + map["voice_credentials"] = vcMap; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + ParcelID = map["parcel_local_id"].AsInteger(); + RegionName = map["region_name"].AsString(); + + OSDMap vcMap = (OSDMap)map["voice_credentials"]; + SipChannelUri = vcMap["channel_uri"].AsUri(); + } + } + + /// + /// + /// + public class ProvisionVoiceAccountRequestMessage : IMessage + { + /// + public string Password; + /// + public string Username; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + + map["username"] = OSD.FromString(Username); + map["password"] = OSD.FromString(Password); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + Username = map["username"].AsString(); + Password = map["password"].AsString(); + } + } + + #endregion + + #region Script/Notecards Messages + /// + /// A message sent by the viewer to the simulator to request a temporary + /// capability for a script contained with in a Tasks inventory to be updated + /// + public class UploadScriptTaskMessage : IMessage + { + /// Object containing request or response + public AssetUploaderBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("state") && map["state"].Equals("upload")) + Request = new UploaderRequestUpload(); + else if (map.ContainsKey("state") && map["state"].Equals("complete")) + Request = new UploaderRequestComplete(); + else + Logger.Log("Unable to deserialize UploadScriptTask: No message handler exists for state " + map["state"].AsString(), Helpers.LogLevel.Warning); + + Request.Deserialize(map); + } + } + + /// + /// A message sent from the simulator to the viewer to indicate + /// a Tasks scripts status. + /// + public class ScriptRunningReplyMessage : IMessage + { + /// The Asset ID of the script + public UUID ItemID; + /// True of the script is compiled/ran using the mono interpreter, false indicates it + /// uses the older less efficient lsl2 interprter + public bool Mono; + /// The Task containing the scripts + public UUID ObjectID; + /// true of the script is in a running state + public bool Running; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + + OSDMap scriptMap = new OSDMap(4); + scriptMap["ItemID"] = OSD.FromUUID(ItemID); + scriptMap["Mono"] = OSD.FromBoolean(Mono); + scriptMap["ObjectID"] = OSD.FromUUID(ObjectID); + scriptMap["Running"] = OSD.FromBoolean(Running); + + OSDArray scriptArray = new OSDArray(1); + scriptArray.Add((OSD)scriptMap); + + map["Script"] = scriptArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray scriptArray = (OSDArray)map["Script"]; + + OSDMap scriptMap = (OSDMap)scriptArray[0]; + + ItemID = scriptMap["ItemID"].AsUUID(); + Mono = scriptMap["Mono"].AsBoolean(); + ObjectID = scriptMap["ObjectID"].AsUUID(); + Running = scriptMap["Running"].AsBoolean(); + } + } + + /// + /// A message containing the request/response used for updating a gesture + /// contained with an agents inventory + /// + public class UpdateGestureAgentInventoryMessage : IMessage + { + /// Object containing request or response + public AssetUploaderBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("item_id")) + Request = new UpdateAgentInventoryRequestMessage(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("upload")) + Request = new UploaderRequestUpload(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("complete")) + Request = new UploaderRequestComplete(); + else + Logger.Log("Unable to deserialize UpdateGestureAgentInventory: No message handler exists: " + map.AsString(), Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + + /// + /// A message request/response which is used to update a notecard contained within + /// a tasks inventory + /// + public class UpdateNotecardTaskInventoryMessage : IMessage + { + /// The of the Task containing the notecard asset to update + public UUID TaskID; + /// The notecard assets contained in the tasks inventory + public UUID ItemID; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + map["task_id"] = OSD.FromUUID(TaskID); + map["item_id"] = OSD.FromUUID(ItemID); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + TaskID = map["task_id"].AsUUID(); + ItemID = map["item_id"].AsUUID(); + } + } + + // TODO: Add Test + /// + /// A reusable class containing a message sent from the viewer to the simulator to request a temporary uploader capability + /// which is used to update an asset in an agents inventory + /// + public class UpdateAgentInventoryRequestMessage : AssetUploaderBlock + { + /// + /// The Notecard AssetID to replace + /// + public UUID ItemID; + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + map["item_id"] = OSD.FromUUID(ItemID); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + ItemID = map["item_id"].AsUUID(); + } + } + + /// + /// A message containing the request/response used for updating a notecard + /// contained with an agents inventory + /// + public class UpdateNotecardAgentInventoryMessage : IMessage + { + /// Object containing request or response + public AssetUploaderBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("item_id")) + Request = new UpdateAgentInventoryRequestMessage(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("upload")) + Request = new UploaderRequestUpload(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("complete")) + Request = new UploaderRequestComplete(); + else + Logger.Log("Unable to deserialize UpdateNotecardAgentInventory: No message handler exists for state " + map["state"].AsString(), Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + + public class CopyInventoryFromNotecardMessage : IMessage + { + public int CallbackID; + public UUID FolderID; + public UUID ItemID; + public UUID NotecardID; + public UUID ObjectID; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(5); + map["callback-id"] = OSD.FromInteger(CallbackID); + map["folder-id"] = OSD.FromUUID(FolderID); + map["item-id"] = OSD.FromUUID(ItemID); + map["notecard-id"] = OSD.FromUUID(NotecardID); + map["object-id"] = OSD.FromUUID(ObjectID); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + CallbackID = map["callback-id"].AsInteger(); + FolderID = map["folder-id"].AsUUID(); + ItemID = map["item-id"].AsUUID(); + NotecardID = map["notecard-id"].AsUUID(); + ObjectID = map["object-id"].AsUUID(); + } + } + + /// + /// A message sent from the simulator to the viewer which indicates + /// an error occurred while attempting to update a script in an agents or tasks + /// inventory + /// + public class UploaderScriptRequestError : AssetUploaderBlock + { + /// true of the script was successfully compiled by the simulator + public bool Compiled; + /// A string containing the error which occured while trying + /// to update the script + public string Error; + /// A new AssetID assigned to the script + public UUID AssetID; + + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(4); + map["state"] = OSD.FromString(State); + map["new_asset"] = OSD.FromUUID(AssetID); + map["compiled"] = OSD.FromBoolean(Compiled); + + OSDArray errorsArray = new OSDArray(); + errorsArray.Add(Error); + + + map["errors"] = errorsArray; + return map; + } + + public override void Deserialize(OSDMap map) + { + AssetID = map["new_asset"].AsUUID(); + Compiled = map["compiled"].AsBoolean(); + State = map["state"].AsString(); + + OSDArray errorsArray = (OSDArray)map["errors"]; + Error = errorsArray[0].AsString(); + } + } + + /// + /// A message sent from the viewer to the simulator + /// requesting the update of an existing script contained + /// within a tasks inventory + /// + public class UpdateScriptTaskUpdateMessage : AssetUploaderBlock + { + /// if true, set the script mode to running + public bool ScriptRunning; + /// The scripts InventoryItem ItemID to update + public UUID ItemID; + /// A lowercase string containing either "mono" or "lsl2" which + /// specifies the script is compiled and ran on the mono runtime, or the older + /// lsl runtime + public string Target; // mono or lsl2 + /// The tasks which contains the script to update + public UUID TaskID; + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(4); + map["is_script_running"] = OSD.FromBoolean(ScriptRunning); + map["item_id"] = OSD.FromUUID(ItemID); + map["target"] = OSD.FromString(Target); + map["task_id"] = OSD.FromUUID(TaskID); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + ScriptRunning = map["is_script_running"].AsBoolean(); + ItemID = map["item_id"].AsUUID(); + Target = map["target"].AsString(); + TaskID = map["task_id"].AsUUID(); + } + } + + /// + /// A message containing either the request or response used in updating a script inside + /// a tasks inventory + /// + public class UpdateScriptTaskMessage : IMessage + { + /// Object containing request or response + public AssetUploaderBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("task_id")) + Request = new UpdateScriptTaskUpdateMessage(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("upload")) + Request = new UploaderRequestUpload(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("complete") + && map.ContainsKey("errors")) + Request = new UploaderScriptRequestError(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("complete")) + Request = new UploaderRequestScriptComplete(); + else + Logger.Log("Unable to deserialize UpdateScriptTaskMessage: No message handler exists for state " + map["state"].AsString(), Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + + /// + /// Response from the simulator to notify the viewer the upload is completed, and + /// the UUID of the script asset and its compiled status + /// + public class UploaderRequestScriptComplete : AssetUploaderBlock + { + /// The uploaded texture asset ID + public UUID AssetID; + /// true of the script was compiled successfully + public bool Compiled; + + public UploaderRequestScriptComplete() + { + State = "complete"; + } + + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["state"] = OSD.FromString(State); + map["new_asset"] = OSD.FromUUID(AssetID); + map["compiled"] = OSD.FromBoolean(Compiled); + return map; + } + + public override void Deserialize(OSDMap map) + { + AssetID = map["new_asset"].AsUUID(); + Compiled = map["compiled"].AsBoolean(); + } + } + + /// + /// A message sent from a viewer to the simulator requesting a temporary uploader capability + /// used to update a script contained in an agents inventory + /// + public class UpdateScriptAgentRequestMessage : AssetUploaderBlock + { + /// The existing asset if of the script in the agents inventory to replace + public UUID ItemID; + /// The language of the script + /// Defaults to lsl version 2, "mono" might be another possible option + public string Target = "lsl2"; // lsl2 + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["item_id"] = OSD.FromUUID(ItemID); + map["target"] = OSD.FromString(Target); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + ItemID = map["item_id"].AsUUID(); + Target = map["target"].AsString(); + } + } + + /// + /// A message containing either the request or response used in updating a script inside + /// an agents inventory + /// + public class UpdateScriptAgentMessage : IMessage + { + /// Object containing request or response + public AssetUploaderBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("item_id")) + Request = new UpdateScriptAgentRequestMessage(); + else if (map.ContainsKey("errors")) + Request = new UploaderScriptRequestError(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("upload")) + Request = new UploaderRequestUpload(); + else if (map.ContainsKey("state") && map["state"].AsString().Equals("complete")) + Request = new UploaderRequestScriptComplete(); + else + Logger.Log("Unable to deserialize UpdateScriptAgent: No message handler exists for state " + map["state"].AsString(), Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + + + public class SendPostcardMessage : IMessage + { + public string FromEmail; + public string Message; + public string FromName; + public Vector3 GlobalPosition; + public string Subject; + public string ToEmail; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(6); + map["from"] = OSD.FromString(FromEmail); + map["msg"] = OSD.FromString(Message); + map["name"] = OSD.FromString(FromName); + map["pos-global"] = OSD.FromVector3(GlobalPosition); + map["subject"] = OSD.FromString(Subject); + map["to"] = OSD.FromString(ToEmail); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + FromEmail = map["from"].AsString(); + Message = map["msg"].AsString(); + FromName = map["name"].AsString(); + GlobalPosition = map["pos-global"].AsVector3(); + Subject = map["subject"].AsString(); + ToEmail = map["to"].AsString(); + } + } + + #endregion + + #region Grid/Maps + + /// Base class for Map Layers via Capabilities + public abstract class MapLayerMessageBase + { + /// + public int Flags; + + /// + /// Serialize the object + /// + /// An containing the objects data + public abstract OSDMap Serialize(); + + /// + /// Deserialize the message + /// + /// An containing the data + public abstract void Deserialize(OSDMap map); + } + + /// + /// Sent by an agent to the capabilities server to request map layers + /// + public class MapLayerRequestVariant : MapLayerMessageBase + { + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + map["Flags"] = OSD.FromInteger(Flags); + return map; + } + + public override void Deserialize(OSDMap map) + { + Flags = map["Flags"].AsInteger(); + } + } + + /// + /// A message sent from the simulator to the viewer which contains an array of map images and their grid coordinates + /// + public class MapLayerReplyVariant : MapLayerMessageBase + { + /// + /// An object containing map location details + /// + public class LayerData + { + /// The Asset ID of the regions tile overlay + public UUID ImageID; + /// The grid location of the southern border of the map tile + public int Bottom; + /// The grid location of the western border of the map tile + public int Left; + /// The grid location of the eastern border of the map tile + public int Right; + /// The grid location of the northern border of the map tile + public int Top; + } + + /// An array containing LayerData items + public LayerData[] LayerDataBlocks; + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + OSDMap agentMap = new OSDMap(1); + agentMap["Flags"] = OSD.FromInteger(Flags); + map["AgentData"] = agentMap; + + OSDArray layerArray = new OSDArray(LayerDataBlocks.Length); + + for (int i = 0; i < LayerDataBlocks.Length; i++) + { + OSDMap layerMap = new OSDMap(5); + layerMap["ImageID"] = OSD.FromUUID(LayerDataBlocks[i].ImageID); + layerMap["Bottom"] = OSD.FromInteger(LayerDataBlocks[i].Bottom); + layerMap["Left"] = OSD.FromInteger(LayerDataBlocks[i].Left); + layerMap["Top"] = OSD.FromInteger(LayerDataBlocks[i].Top); + layerMap["Right"] = OSD.FromInteger(LayerDataBlocks[i].Right); + + layerArray.Add(layerMap); + } + + map["LayerData"] = layerArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + OSDMap agentMap = (OSDMap)map["AgentData"]; + Flags = agentMap["Flags"].AsInteger(); + + OSDArray layerArray = (OSDArray)map["LayerData"]; + + LayerDataBlocks = new LayerData[layerArray.Count]; + + for (int i = 0; i < LayerDataBlocks.Length; i++) + { + OSDMap layerMap = (OSDMap)layerArray[i]; + + LayerData layer = new LayerData(); + layer.ImageID = layerMap["ImageID"].AsUUID(); + layer.Top = layerMap["Top"].AsInteger(); + layer.Right = layerMap["Right"].AsInteger(); + layer.Left = layerMap["Left"].AsInteger(); + layer.Bottom = layerMap["Bottom"].AsInteger(); + + LayerDataBlocks[i] = layer; + } + } + } + + public class MapLayerMessage : IMessage + { + /// Object containing request or response + public MapLayerMessageBase Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("LayerData")) + Request = new MapLayerReplyVariant(); + else if (map.ContainsKey("Flags")) + Request = new MapLayerRequestVariant(); + else + Logger.Log("Unable to deserialize MapLayerMessage: No message handler exists", Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + + #endregion + + #region Session/Communication + + /// + /// New as of 1.23 RC1, no details yet. + /// + public class ProductInfoRequestMessage : IMessage + { + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + throw new NotImplementedException(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + throw new NotImplementedException(); + } + } + + #region ChatSessionRequestMessage + + + public abstract class SearchStatRequestBlock + { + public abstract OSDMap Serialize(); + public abstract void Deserialize(OSDMap map); + } + + // variant A - the request to the simulator + public class SearchStatRequestRequest : SearchStatRequestBlock + { + public UUID ClassifiedID; + + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + map["classified_id"] = OSD.FromUUID(ClassifiedID); + return map; + } + + public override void Deserialize(OSDMap map) + { + ClassifiedID = map["classified_id"].AsUUID(); + } + } + + public class SearchStatRequestReply : SearchStatRequestBlock + { + public int MapClicks; + public int ProfileClicks; + public int SearchMapClicks; + public int SearchProfileClicks; + public int SearchTeleportClicks; + public int TeleportClicks; + + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(6); + map["map_clicks"] = OSD.FromInteger(MapClicks); + map["profile_clicks"] = OSD.FromInteger(ProfileClicks); + map["search_map_clicks"] = OSD.FromInteger(SearchMapClicks); + map["search_profile_clicks"] = OSD.FromInteger(SearchProfileClicks); + map["search_teleport_clicks"] = OSD.FromInteger(SearchTeleportClicks); + map["teleport_clicks"] = OSD.FromInteger(TeleportClicks); + return map; + } + + public override void Deserialize(OSDMap map) + { + MapClicks = map["map_clicks"].AsInteger(); + ProfileClicks = map["profile_clicks"].AsInteger(); + SearchMapClicks = map["search_map_clicks"].AsInteger(); + SearchProfileClicks = map["search_profile_clicks"].AsInteger(); + SearchTeleportClicks = map["search_teleport_clicks"].AsInteger(); + TeleportClicks = map["teleport_clicks"].AsInteger(); + } + } + + public class SearchStatRequestMessage : IMessage + { + public SearchStatRequestBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("map_clicks")) + Request = new SearchStatRequestReply(); + else if (map.ContainsKey("classified_id")) + Request = new SearchStatRequestRequest(); + else + Logger.Log("Unable to deserialize SearchStatRequest: No message handler exists for method " + map["method"].AsString(), Helpers.LogLevel.Warning); + + Request.Deserialize(map); + } + } + + public abstract class ChatSessionRequestBlock + { + /// A string containing the method used + public string Method; + + public abstract OSDMap Serialize(); + public abstract void Deserialize(OSDMap map); + } + + /// + /// A request sent from an agent to the Simulator to begin a new conference. + /// Contains a list of Agents which will be included in the conference + /// + public class ChatSessionRequestStartConference : ChatSessionRequestBlock + { + /// An array containing the of the agents invited to this conference + public UUID[] AgentsBlock; + /// The conferences Session ID + public UUID SessionID; + + public ChatSessionRequestStartConference() + { + Method = "start conference"; + } + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + map["method"] = OSD.FromString(Method); + OSDArray agentsArray = new OSDArray(); + for (int i = 0; i < AgentsBlock.Length; i++) + { + agentsArray.Add(OSD.FromUUID(AgentsBlock[i])); + } + map["params"] = agentsArray; + map["session-id"] = OSD.FromUUID(SessionID); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + Method = map["method"].AsString(); + OSDArray agentsArray = (OSDArray)map["params"]; + + AgentsBlock = new UUID[agentsArray.Count]; + + for (int i = 0; i < agentsArray.Count; i++) + { + AgentsBlock[i] = agentsArray[i].AsUUID(); + } + + SessionID = map["session-id"].AsUUID(); + } + } + + /// + /// A moderation request sent from a conference moderator + /// Contains an agent and an optional action to take + /// + public class ChatSessionRequestMuteUpdate : ChatSessionRequestBlock + { + /// The Session ID + public UUID SessionID; + /// + public UUID AgentID; + /// A list containing Key/Value pairs, known valid values: + /// key: text value: true/false - allow/disallow specified agents ability to use text in session + /// key: voice value: true/false - allow/disallow specified agents ability to use voice in session + /// + /// "text" or "voice" + public string RequestKey; + /// + public bool RequestValue; + + public ChatSessionRequestMuteUpdate() + { + Method = "mute update"; + } + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + map["method"] = OSD.FromString(Method); + + OSDMap muteMap = new OSDMap(1); + muteMap[RequestKey] = OSD.FromBoolean(RequestValue); + + OSDMap paramMap = new OSDMap(2); + paramMap["agent_id"] = OSD.FromUUID(AgentID); + paramMap["mute_info"] = muteMap; + + map["params"] = paramMap; + map["session-id"] = OSD.FromUUID(SessionID); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + Method = map["method"].AsString(); + SessionID = map["session-id"].AsUUID(); + + OSDMap paramsMap = (OSDMap)map["params"]; + OSDMap muteMap = (OSDMap)paramsMap["mute_info"]; + + AgentID = paramsMap["agent_id"].AsUUID(); + + if (muteMap.ContainsKey("text")) + RequestKey = "text"; + else if (muteMap.ContainsKey("voice")) + RequestKey = "voice"; + + RequestValue = muteMap[RequestKey].AsBoolean(); + } + } + + /// + /// A message sent from the agent to the simulator which tells the + /// simulator we've accepted a conference invitation + /// + public class ChatSessionAcceptInvitation : ChatSessionRequestBlock + { + /// The conference SessionID + public UUID SessionID; + + public ChatSessionAcceptInvitation() + { + Method = "accept invitation"; + } + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["method"] = OSD.FromString(Method); + map["session-id"] = OSD.FromUUID(SessionID); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + Method = map["method"].AsString(); + SessionID = map["session-id"].AsUUID(); + } + } + + public class ChatSessionRequestMessage : IMessage + { + public ChatSessionRequestBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("method") && map["method"].AsString().Equals("start conference")) + Request = new ChatSessionRequestStartConference(); + else if (map.ContainsKey("method") && map["method"].AsString().Equals("mute update")) + Request = new ChatSessionRequestMuteUpdate(); + else if (map.ContainsKey("method") && map["method"].AsString().Equals("accept invitation")) + Request = new ChatSessionAcceptInvitation(); + else + Logger.Log("Unable to deserialize ChatSessionRequest: No message handler exists for method " + map["method"].AsString(), Helpers.LogLevel.Warning); + + Request.Deserialize(map); + } + } + + #endregion + + public class ChatterboxSessionEventReplyMessage : IMessage + { + public UUID SessionID; + public bool Success; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["success"] = OSD.FromBoolean(Success); + map["session_id"] = OSD.FromUUID(SessionID); // FIXME: Verify this is correct map name + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + Success = map["success"].AsBoolean(); + SessionID = map["session_id"].AsUUID(); + } + } + + public class ChatterBoxSessionStartReplyMessage : IMessage + { + public UUID SessionID; + public UUID TempSessionID; + public bool Success; + + public string SessionName; + // FIXME: Replace int with an enum + public int Type; + public bool VoiceEnabled; + public bool ModeratedVoice; + + /* Is Text moderation possible? */ + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap moderatedMap = new OSDMap(1); + moderatedMap["voice"] = OSD.FromBoolean(ModeratedVoice); + + OSDMap sessionMap = new OSDMap(4); + sessionMap["type"] = OSD.FromInteger(Type); + sessionMap["session_name"] = OSD.FromString(SessionName); + sessionMap["voice_enabled"] = OSD.FromBoolean(VoiceEnabled); + sessionMap["moderated_mode"] = moderatedMap; + + OSDMap map = new OSDMap(4); + map["session_id"] = OSD.FromUUID(SessionID); + map["temp_session_id"] = OSD.FromUUID(TempSessionID); + map["success"] = OSD.FromBoolean(Success); + map["session_info"] = sessionMap; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + SessionID = map["session_id"].AsUUID(); + TempSessionID = map["temp_session_id"].AsUUID(); + Success = map["success"].AsBoolean(); + + if (Success) + { + OSDMap sessionMap = (OSDMap)map["session_info"]; + SessionName = sessionMap["session_name"].AsString(); + Type = sessionMap["type"].AsInteger(); + VoiceEnabled = sessionMap["voice_enabled"].AsBoolean(); + + OSDMap moderatedModeMap = (OSDMap)sessionMap["moderated_mode"]; + ModeratedVoice = moderatedModeMap["voice"].AsBoolean(); + } + } + } + + public class ChatterBoxInvitationMessage : IMessage + { + /// Key of sender + public UUID FromAgentID; + /// Name of sender + public string FromAgentName; + /// Key of destination avatar + public UUID ToAgentID; + /// ID of originating estate + public uint ParentEstateID; + /// Key of originating region + public UUID RegionID; + /// Coordinates in originating region + public Vector3 Position; + /// Instant message type + public InstantMessageDialog Dialog; + /// Group IM session toggle + public bool GroupIM; + /// Key of IM session, for Group Messages, the groups UUID + public UUID IMSessionID; + /// Timestamp of the instant message + public DateTime Timestamp; + /// Instant message text + public string Message; + /// Whether this message is held for offline avatars + public InstantMessageOnline Offline; + /// Context specific packed data + public byte[] BinaryBucket; + /// Is this invitation for voice group/conference chat + public bool Voice; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap dataMap = new OSDMap(3); + dataMap["timestamp"] = OSD.FromDate(Timestamp); + dataMap["type"] = OSD.FromInteger((uint)Dialog); + dataMap["binary_bucket"] = OSD.FromBinary(BinaryBucket); + + OSDMap paramsMap = new OSDMap(11); + paramsMap["from_id"] = OSD.FromUUID(FromAgentID); + paramsMap["from_name"] = OSD.FromString(FromAgentName); + paramsMap["to_id"] = OSD.FromUUID(ToAgentID); + paramsMap["parent_estate_id"] = OSD.FromInteger(ParentEstateID); + paramsMap["region_id"] = OSD.FromUUID(RegionID); + paramsMap["position"] = OSD.FromVector3(Position); + paramsMap["from_group"] = OSD.FromBoolean(GroupIM); + paramsMap["id"] = OSD.FromUUID(IMSessionID); + paramsMap["message"] = OSD.FromString(Message); + paramsMap["offline"] = OSD.FromInteger((uint)Offline); + + paramsMap["data"] = dataMap; + + OSDMap imMap = new OSDMap(1); + imMap["message_params"] = paramsMap; + + OSDMap map = new OSDMap(1); + map["instantmessage"] = imMap; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("voice")) + { + FromAgentID = map["from_id"].AsUUID(); + FromAgentName = map["from_name"].AsString(); + IMSessionID = map["session_id"].AsUUID(); + BinaryBucket = Utils.StringToBytes(map["session_name"].AsString()); + Voice = true; + } + else + { + OSDMap im = (OSDMap)map["instantmessage"]; + OSDMap msg = (OSDMap)im["message_params"]; + OSDMap msgdata = (OSDMap)msg["data"]; + + FromAgentID = msg["from_id"].AsUUID(); + FromAgentName = msg["from_name"].AsString(); + ToAgentID = msg["to_id"].AsUUID(); + ParentEstateID = (uint)msg["parent_estate_id"].AsInteger(); + RegionID = msg["region_id"].AsUUID(); + Position = msg["position"].AsVector3(); + GroupIM = msg["from_group"].AsBoolean(); + IMSessionID = msg["id"].AsUUID(); + Message = msg["message"].AsString(); + Offline = (InstantMessageOnline)msg["offline"].AsInteger(); + Dialog = (InstantMessageDialog)msgdata["type"].AsInteger(); + BinaryBucket = msgdata["binary_bucket"].AsBinary(); + Timestamp = msgdata["timestamp"].AsDate(); + Voice = false; + } + } + } + + public class RegionInfoMessage : IMessage + { + public int ParcelLocalID; + public string RegionName; + public string ChannelUri; + + #region IMessage Members + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + map["parcel_local_id"] = OSD.FromInteger(ParcelLocalID); + map["region_name"] = OSD.FromString(RegionName); + OSDMap voiceMap = new OSDMap(1); + voiceMap["channel_uri"] = OSD.FromString(ChannelUri); + map["voice_credentials"] = voiceMap; + return map; + } + + public void Deserialize(OSDMap map) + { + this.ParcelLocalID = map["parcel_local_id"].AsInteger(); + this.RegionName = map["region_name"].AsString(); + OSDMap voiceMap = (OSDMap)map["voice_credentials"]; + this.ChannelUri = voiceMap["channel_uri"].AsString(); + } + + #endregion + } + + /// + /// Sent from the simulator to the viewer. + /// + /// When an agent initially joins a session the AgentUpdatesBlock object will contain a list of session members including + /// a boolean indicating they can use voice chat in this session, a boolean indicating they are allowed to moderate + /// this session, and lastly a string which indicates another agent is entering the session with the Transition set to "ENTER" + /// + /// During the session lifetime updates on individuals are sent. During the update the booleans sent during the initial join are + /// excluded with the exception of the Transition field. This indicates a new user entering or exiting the session with + /// the string "ENTER" or "LEAVE" respectively. + /// + public class ChatterBoxSessionAgentListUpdatesMessage : IMessage + { + // initial when agent joins session + // eventsbodyagent_updates32939971-a520-4b52-8ca5-6085d0e39933infocan_voice_chat1is_moderator1transitionENTERca00e3e1-0fdb-4136-8ed4-0aab739b29e8infocan_voice_chat1is_moderator0transitionENTERsession_idbe7a1def-bd8a-5043-5d5b-49e3805adf6bupdates32939971-a520-4b52-8ca5-6085d0e39933ENTERca00e3e1-0fdb-4136-8ed4-0aab739b29e8ENTERmessageChatterBoxSessionAgentListUpdatesbodyagent_updates32939971-a520-4b52-8ca5-6085d0e39933infocan_voice_chat1is_moderator1session_idbe7a1def-bd8a-5043-5d5b-49e3805adf6bupdatesmessageChatterBoxSessionAgentListUpdatesid5 + + // a message containing only moderator updates + // eventsbodyagent_updatesca00e3e1-0fdb-4136-8ed4-0aab739b29e8infomutestext1session_idbe7a1def-bd8a-5043-5d5b-49e3805adf6bupdatesmessageChatterBoxSessionAgentListUpdatesid7 + + public UUID SessionID; + + public class AgentUpdatesBlock + { + public UUID AgentID; + + public bool CanVoiceChat; + public bool IsModerator; + // transition "transition" = "ENTER" or "LEAVE" + public string Transition; // TODO: switch to an enum "ENTER" or "LEAVE" + + public bool MuteText; + public bool MuteVoice; + } + + public AgentUpdatesBlock[] Updates; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + + OSDMap agent_updatesMap = new OSDMap(1); + for (int i = 0; i < Updates.Length; i++) + { + OSDMap mutesMap = new OSDMap(2); + mutesMap["text"] = OSD.FromBoolean(Updates[i].MuteText); + mutesMap["voice"] = OSD.FromBoolean(Updates[i].MuteVoice); + + OSDMap infoMap = new OSDMap(4); + infoMap["can_voice_chat"] = OSD.FromBoolean((bool)Updates[i].CanVoiceChat); + infoMap["is_moderator"] = OSD.FromBoolean((bool)Updates[i].IsModerator); + infoMap["mutes"] = mutesMap; + + OSDMap imap = new OSDMap(1); + imap["info"] = infoMap; + imap["transition"] = OSD.FromString(Updates[i].Transition); + + agent_updatesMap.Add(Updates[i].AgentID.ToString(), imap); + } + + map.Add("agent_updates", agent_updatesMap); + + map["session_id"] = OSD.FromUUID(SessionID); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + + OSDMap agent_updates = (OSDMap)map["agent_updates"]; + SessionID = map["session_id"].AsUUID(); + + List updatesList = new List(); + + foreach (KeyValuePair kvp in agent_updates) + { + + if (kvp.Key == "updates") + { + // This appears to be redundant and duplicated by the info block, more dumps will confirm this + /* 32939971-a520-4b52-8ca5-6085d0e39933 + ENTER */ + } + else if (kvp.Key == "session_id") + { + // I am making the assumption that each osdmap will contain the information for a + // single session. This is how the map appears to read however more dumps should be taken + // to confirm this. + /* session_id + 984f6a1e-4ceb-6366-8d5e-a18c6819c6f7 */ + + } + else // key is an agent uuid (we hope!) + { + // should be the agents uuid as the key, and "info" as the datablock + /* 32939971-a520-4b52-8ca5-6085d0e39933 + + info + + can_voice_chat + 1 + is_moderator + 1 + + transition + ENTER + */ + AgentUpdatesBlock block = new AgentUpdatesBlock(); + block.AgentID = UUID.Parse(kvp.Key); + + OSDMap infoMap = (OSDMap)agent_updates[kvp.Key]; + + OSDMap agentPermsMap = (OSDMap)infoMap["info"]; + + block.CanVoiceChat = agentPermsMap["can_voice_chat"].AsBoolean(); + block.IsModerator = agentPermsMap["is_moderator"].AsBoolean(); + + block.Transition = infoMap["transition"].AsString(); + + if (agentPermsMap.ContainsKey("mutes")) + { + OSDMap mutesMap = (OSDMap)agentPermsMap["mutes"]; + block.MuteText = mutesMap["text"].AsBoolean(); + block.MuteVoice = mutesMap["voice"].AsBoolean(); + } + updatesList.Add(block); + } + } + + Updates = new AgentUpdatesBlock[updatesList.Count]; + + for (int i = 0; i < updatesList.Count; i++) + { + AgentUpdatesBlock block = new AgentUpdatesBlock(); + block.AgentID = updatesList[i].AgentID; + block.CanVoiceChat = updatesList[i].CanVoiceChat; + block.IsModerator = updatesList[i].IsModerator; + block.MuteText = updatesList[i].MuteText; + block.MuteVoice = updatesList[i].MuteVoice; + block.Transition = updatesList[i].Transition; + Updates[i] = block; + } + } + } + + /// + /// An EventQueue message sent when the agent is forcibly removed from a chatterbox session + /// + public class ForceCloseChatterBoxSessionMessage : IMessage + { + /// + /// A string containing the reason the agent was removed + /// + public string Reason; + /// + /// The ChatterBoxSession's SessionID + /// + public UUID SessionID; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["reason"] = OSD.FromString(Reason); + map["session_id"] = OSD.FromUUID(SessionID); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + Reason = map["reason"].AsString(); + SessionID = map["session_id"].AsUUID(); + } + } + + #endregion + + #region EventQueue + + public abstract class EventMessageBlock + { + public abstract OSDMap Serialize(); + public abstract void Deserialize(OSDMap map); + } + + public class EventQueueAck : EventMessageBlock + { + public int AckID; + public bool Done; + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["ack"] = OSD.FromInteger(AckID); + map["done"] = OSD.FromBoolean(Done); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + AckID = map["ack"].AsInteger(); + Done = map["done"].AsBoolean(); + } + } + + public class EventQueueEvent : EventMessageBlock + { + public class QueueEvent + { + public IMessage EventMessage; + public string MessageKey; + } + + public int Sequence; + public QueueEvent[] MessageEvents; + + /// + /// Serialize the object + /// + /// An containing the objects data + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + + OSDArray eventsArray = new OSDArray(); + + for (int i = 0; i < MessageEvents.Length; i++) + { + OSDMap eventMap = new OSDMap(2); + eventMap["body"] = MessageEvents[i].EventMessage.Serialize(); + eventMap["message"] = OSD.FromString(MessageEvents[i].MessageKey); + eventsArray.Add(eventMap); + } + + map["events"] = eventsArray; + map["id"] = OSD.FromInteger(Sequence); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + Sequence = map["id"].AsInteger(); + OSDArray arrayEvents = (OSDArray)map["events"]; + + MessageEvents = new QueueEvent[arrayEvents.Count]; + + for (int i = 0; i < arrayEvents.Count; i++) + { + OSDMap eventMap = (OSDMap)arrayEvents[i]; + QueueEvent ev = new QueueEvent(); + + ev.MessageKey = eventMap["message"].AsString(); + ev.EventMessage = MessageUtils.DecodeEvent(ev.MessageKey, (OSDMap)eventMap["body"]); + MessageEvents[i] = ev; + } + } + } + + public class EventQueueGetMessage : IMessage + { + public EventMessageBlock Messages; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Messages.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("ack")) + Messages = new EventQueueAck(); + else if (map.ContainsKey("events")) + Messages = new EventQueueEvent(); + else + Logger.Log("Unable to deserialize EventQueueGetMessage: No message handler exists for event", Helpers.LogLevel.Warning); + + Messages.Deserialize(map); + } + } + + #endregion + + #region Stats Messages + + public class ViewerStatsMessage : IMessage + { + public int AgentsInView; + public float AgentFPS; + public string AgentLanguage; + public float AgentMemoryUsed; + public float MetersTraveled; + public float AgentPing; + public int RegionsVisited; + public float AgentRuntime; + public float SimulatorFPS; + public DateTime AgentStartTime; + public string AgentVersion; + + public float object_kbytes; + public float texture_kbytes; + public float world_kbytes; + + public float MiscVersion; + public bool VertexBuffersEnabled; + + public UUID SessionID; + + public int StatsDropped; + public int StatsFailedResends; + public int FailuresInvalid; + public int FailuresOffCircuit; + public int FailuresResent; + public int FailuresSendPacket; + + public int MiscInt1; + public int MiscInt2; + public string MiscString1; + + public int InCompressedPackets; + public float InKbytes; + public float InPackets; + public float InSavings; + + public int OutCompressedPackets; + public float OutKbytes; + public float OutPackets; + public float OutSavings; + + public string SystemCPU; + public string SystemGPU; + public int SystemGPUClass; + public string SystemGPUVendor; + public string SystemGPUVersion; + public string SystemOS; + public int SystemInstalledRam; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(5); + map["session_id"] = OSD.FromUUID(SessionID); + + OSDMap agentMap = new OSDMap(11); + agentMap["agents_in_view"] = OSD.FromInteger(AgentsInView); + agentMap["fps"] = OSD.FromReal(AgentFPS); + agentMap["language"] = OSD.FromString(AgentLanguage); + agentMap["mem_use"] = OSD.FromReal(AgentMemoryUsed); + agentMap["meters_traveled"] = OSD.FromReal(MetersTraveled); + agentMap["ping"] = OSD.FromReal(AgentPing); + agentMap["regions_visited"] = OSD.FromInteger(RegionsVisited); + agentMap["run_time"] = OSD.FromReal(AgentRuntime); + agentMap["sim_fps"] = OSD.FromReal(SimulatorFPS); + agentMap["start_time"] = OSD.FromUInteger(Utils.DateTimeToUnixTime(AgentStartTime)); + agentMap["version"] = OSD.FromString(AgentVersion); + map["agent"] = agentMap; + + + OSDMap downloadsMap = new OSDMap(3); // downloads + downloadsMap["object_kbytes"] = OSD.FromReal(object_kbytes); + downloadsMap["texture_kbytes"] = OSD.FromReal(texture_kbytes); + downloadsMap["world_kbytes"] = OSD.FromReal(world_kbytes); + map["downloads"] = downloadsMap; + + OSDMap miscMap = new OSDMap(2); + miscMap["Version"] = OSD.FromReal(MiscVersion); + miscMap["Vertex Buffers Enabled"] = OSD.FromBoolean(VertexBuffersEnabled); + map["misc"] = miscMap; + + OSDMap statsMap = new OSDMap(2); + + OSDMap failuresMap = new OSDMap(6); + failuresMap["dropped"] = OSD.FromInteger(StatsDropped); + failuresMap["failed_resends"] = OSD.FromInteger(StatsFailedResends); + failuresMap["invalid"] = OSD.FromInteger(FailuresInvalid); + failuresMap["off_circuit"] = OSD.FromInteger(FailuresOffCircuit); + failuresMap["resent"] = OSD.FromInteger(FailuresResent); + failuresMap["send_packet"] = OSD.FromInteger(FailuresSendPacket); + statsMap["failures"] = failuresMap; + + OSDMap statsMiscMap = new OSDMap(3); + statsMiscMap["int_1"] = OSD.FromInteger(MiscInt1); + statsMiscMap["int_2"] = OSD.FromInteger(MiscInt2); + statsMiscMap["string_1"] = OSD.FromString(MiscString1); + statsMap["misc"] = statsMiscMap; + + OSDMap netMap = new OSDMap(3); + + // in + OSDMap netInMap = new OSDMap(4); + netInMap["compressed_packets"] = OSD.FromInteger(InCompressedPackets); + netInMap["kbytes"] = OSD.FromReal(InKbytes); + netInMap["packets"] = OSD.FromReal(InPackets); + netInMap["savings"] = OSD.FromReal(InSavings); + netMap["in"] = netInMap; + // out + OSDMap netOutMap = new OSDMap(4); + netOutMap["compressed_packets"] = OSD.FromInteger(OutCompressedPackets); + netOutMap["kbytes"] = OSD.FromReal(OutKbytes); + netOutMap["packets"] = OSD.FromReal(OutPackets); + netOutMap["savings"] = OSD.FromReal(OutSavings); + netMap["out"] = netOutMap; + + statsMap["net"] = netMap; + + //system + OSDMap systemStatsMap = new OSDMap(7); + systemStatsMap["cpu"] = OSD.FromString(SystemCPU); + systemStatsMap["gpu"] = OSD.FromString(SystemGPU); + systemStatsMap["gpu_class"] = OSD.FromInteger(SystemGPUClass); + systemStatsMap["gpu_vendor"] = OSD.FromString(SystemGPUVendor); + systemStatsMap["gpu_version"] = OSD.FromString(SystemGPUVersion); + systemStatsMap["os"] = OSD.FromString(SystemOS); + systemStatsMap["ram"] = OSD.FromInteger(SystemInstalledRam); + map["system"] = systemStatsMap; + + map["stats"] = statsMap; + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + SessionID = map["session_id"].AsUUID(); + + OSDMap agentMap = (OSDMap)map["agent"]; + AgentsInView = agentMap["agents_in_view"].AsInteger(); + AgentFPS = (float)agentMap["fps"].AsReal(); + AgentLanguage = agentMap["language"].AsString(); + AgentMemoryUsed = (float)agentMap["mem_use"].AsReal(); + MetersTraveled = agentMap["meters_traveled"].AsInteger(); + AgentPing = (float)agentMap["ping"].AsReal(); + RegionsVisited = agentMap["regions_visited"].AsInteger(); + AgentRuntime = (float)agentMap["run_time"].AsReal(); + SimulatorFPS = (float)agentMap["sim_fps"].AsReal(); + AgentStartTime = Utils.UnixTimeToDateTime(agentMap["start_time"].AsUInteger()); + AgentVersion = agentMap["version"].AsString(); + + OSDMap downloadsMap = (OSDMap)map["downloads"]; + object_kbytes = (float)downloadsMap["object_kbytes"].AsReal(); + texture_kbytes = (float)downloadsMap["texture_kbytes"].AsReal(); + world_kbytes = (float)downloadsMap["world_kbytes"].AsReal(); + + OSDMap miscMap = (OSDMap)map["misc"]; + MiscVersion = (float)miscMap["Version"].AsReal(); + VertexBuffersEnabled = miscMap["Vertex Buffers Enabled"].AsBoolean(); + + OSDMap statsMap = (OSDMap)map["stats"]; + OSDMap failuresMap = (OSDMap)statsMap["failures"]; + StatsDropped = failuresMap["dropped"].AsInteger(); + StatsFailedResends = failuresMap["failed_resends"].AsInteger(); + FailuresInvalid = failuresMap["invalid"].AsInteger(); + FailuresOffCircuit = failuresMap["off_circuit"].AsInteger(); + FailuresResent = failuresMap["resent"].AsInteger(); + FailuresSendPacket = failuresMap["send_packet"].AsInteger(); + + OSDMap statsMiscMap = (OSDMap)statsMap["misc"]; + MiscInt1 = statsMiscMap["int_1"].AsInteger(); + MiscInt2 = statsMiscMap["int_2"].AsInteger(); + MiscString1 = statsMiscMap["string_1"].AsString(); + OSDMap netMap = (OSDMap)statsMap["net"]; + // in + OSDMap netInMap = (OSDMap)netMap["in"]; + InCompressedPackets = netInMap["compressed_packets"].AsInteger(); + InKbytes = netInMap["kbytes"].AsInteger(); + InPackets = netInMap["packets"].AsInteger(); + InSavings = netInMap["savings"].AsInteger(); + // out + OSDMap netOutMap = (OSDMap)netMap["out"]; + OutCompressedPackets = netOutMap["compressed_packets"].AsInteger(); + OutKbytes = netOutMap["kbytes"].AsInteger(); + OutPackets = netOutMap["packets"].AsInteger(); + OutSavings = netOutMap["savings"].AsInteger(); + + //system + OSDMap systemStatsMap = (OSDMap)map["system"]; + SystemCPU = systemStatsMap["cpu"].AsString(); + SystemGPU = systemStatsMap["gpu"].AsString(); + SystemGPUClass = systemStatsMap["gpu_class"].AsInteger(); + SystemGPUVendor = systemStatsMap["gpu_vendor"].AsString(); + SystemGPUVersion = systemStatsMap["gpu_version"].AsString(); + SystemOS = systemStatsMap["os"].AsString(); + SystemInstalledRam = systemStatsMap["ram"].AsInteger(); + } + } + + /// + /// + /// + public class PlacesReplyMessage : IMessage + { + public UUID AgentID; + public UUID QueryID; + public UUID TransactionID; + + public class QueryData + { + public int ActualArea; + public int BillableArea; + public string Description; + public float Dwell; + public int Flags; + public float GlobalX; + public float GlobalY; + public float GlobalZ; + public string Name; + public UUID OwnerID; + public string SimName; + public UUID SnapShotID; + public string ProductSku; + public int Price; + } + + public QueryData[] QueryDataBlocks; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + + // add the AgentData map + OSDMap agentIDmap = new OSDMap(2); + agentIDmap["AgentID"] = OSD.FromUUID(AgentID); + agentIDmap["QueryID"] = OSD.FromUUID(QueryID); + + OSDArray agentDataArray = new OSDArray(); + agentDataArray.Add(agentIDmap); + + map["AgentData"] = agentDataArray; + + // add the QueryData map + OSDArray dataBlocksArray = new OSDArray(QueryDataBlocks.Length); + for (int i = 0; i < QueryDataBlocks.Length; i++) + { + OSDMap queryDataMap = new OSDMap(14); + queryDataMap["ActualArea"] = OSD.FromInteger(QueryDataBlocks[i].ActualArea); + queryDataMap["BillableArea"] = OSD.FromInteger(QueryDataBlocks[i].BillableArea); + queryDataMap["Desc"] = OSD.FromString(QueryDataBlocks[i].Description); + queryDataMap["Dwell"] = OSD.FromReal(QueryDataBlocks[i].Dwell); + queryDataMap["Flags"] = OSD.FromInteger(QueryDataBlocks[i].Flags); + queryDataMap["GlobalX"] = OSD.FromReal(QueryDataBlocks[i].GlobalX); + queryDataMap["GlobalY"] = OSD.FromReal(QueryDataBlocks[i].GlobalY); + queryDataMap["GlobalZ"] = OSD.FromReal(QueryDataBlocks[i].GlobalZ); + queryDataMap["Name"] = OSD.FromString(QueryDataBlocks[i].Name); + queryDataMap["OwnerID"] = OSD.FromUUID(QueryDataBlocks[i].OwnerID); + queryDataMap["Price"] = OSD.FromInteger(QueryDataBlocks[i].Price); + queryDataMap["SimName"] = OSD.FromString(QueryDataBlocks[i].SimName); + queryDataMap["SnapshotID"] = OSD.FromUUID(QueryDataBlocks[i].SnapShotID); + queryDataMap["ProductSKU"] = OSD.FromString(QueryDataBlocks[i].ProductSku); + dataBlocksArray.Add(queryDataMap); + } + + map["QueryData"] = dataBlocksArray; + + // add the TransactionData map + OSDMap transMap = new OSDMap(1); + transMap["TransactionID"] = OSD.FromUUID(TransactionID); + OSDArray transArray = new OSDArray(); + transArray.Add(transMap); + map["TransactionData"] = transArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray agentDataArray = (OSDArray)map["AgentData"]; + + OSDMap agentDataMap = (OSDMap)agentDataArray[0]; + AgentID = agentDataMap["AgentID"].AsUUID(); + QueryID = agentDataMap["QueryID"].AsUUID(); + + + OSDArray dataBlocksArray = (OSDArray)map["QueryData"]; + QueryDataBlocks = new QueryData[dataBlocksArray.Count]; + for (int i = 0; i < dataBlocksArray.Count; i++) + { + OSDMap dataMap = (OSDMap)dataBlocksArray[i]; + QueryData data = new QueryData(); + data.ActualArea = dataMap["ActualArea"].AsInteger(); + data.BillableArea = dataMap["BillableArea"].AsInteger(); + data.Description = dataMap["Desc"].AsString(); + data.Dwell = (float)dataMap["Dwell"].AsReal(); + data.Flags = dataMap["Flags"].AsInteger(); + data.GlobalX = (float)dataMap["GlobalX"].AsReal(); + data.GlobalY = (float)dataMap["GlobalY"].AsReal(); + data.GlobalZ = (float)dataMap["GlobalZ"].AsReal(); + data.Name = dataMap["Name"].AsString(); + data.OwnerID = dataMap["OwnerID"].AsUUID(); + data.Price = dataMap["Price"].AsInteger(); + data.SimName = dataMap["SimName"].AsString(); + data.SnapShotID = dataMap["SnapshotID"].AsUUID(); + data.ProductSku = dataMap["ProductSKU"].AsString(); + QueryDataBlocks[i] = data; + } + + OSDArray transactionArray = (OSDArray)map["TransactionData"]; + OSDMap transactionDataMap = (OSDMap)transactionArray[0]; + TransactionID = transactionDataMap["TransactionID"].AsUUID(); + } + } + + public class UpdateAgentInformationMessage : IMessage + { + public string MaxAccess; // PG, A, or M + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + OSDMap prefsMap = new OSDMap(1); + prefsMap["max"] = OSD.FromString(MaxAccess); + map["access_prefs"] = prefsMap; + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDMap prefsMap = (OSDMap)map["access_prefs"]; + MaxAccess = prefsMap["max"].AsString(); + } + } + + [Serializable] + public class DirLandReplyMessage : IMessage + { + public UUID AgentID; + public UUID QueryID; + + [Serializable] + public class QueryReply + { + public int ActualArea; + public bool Auction; + public bool ForSale; + public string Name; + public UUID ParcelID; + public string ProductSku; + public int SalePrice; + } + + public QueryReply[] QueryReplies; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + + OSDMap agentMap = new OSDMap(1); + agentMap["AgentID"] = OSD.FromUUID(AgentID); + OSDArray agentDataArray = new OSDArray(1); + agentDataArray.Add(agentMap); + map["AgentData"] = agentDataArray; + + OSDMap queryMap = new OSDMap(1); + queryMap["QueryID"] = OSD.FromUUID(QueryID); + OSDArray queryDataArray = new OSDArray(1); + queryDataArray.Add(queryMap); + map["QueryData"] = queryDataArray; + + OSDArray queryReplyArray = new OSDArray(); + for (int i = 0; i < QueryReplies.Length; i++) + { + OSDMap queryReply = new OSDMap(100); + queryReply["ActualArea"] = OSD.FromInteger(QueryReplies[i].ActualArea); + queryReply["Auction"] = OSD.FromBoolean(QueryReplies[i].Auction); + queryReply["ForSale"] = OSD.FromBoolean(QueryReplies[i].ForSale); + queryReply["Name"] = OSD.FromString(QueryReplies[i].Name); + queryReply["ParcelID"] = OSD.FromUUID(QueryReplies[i].ParcelID); + queryReply["ProductSKU"] = OSD.FromString(QueryReplies[i].ProductSku); + queryReply["SalePrice"] = OSD.FromInteger(QueryReplies[i].SalePrice); + + queryReplyArray.Add(queryReply); + } + map["QueryReplies"] = queryReplyArray; + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + OSDArray agentDataArray = (OSDArray)map["AgentData"]; + OSDMap agentDataMap = (OSDMap)agentDataArray[0]; + AgentID = agentDataMap["AgentID"].AsUUID(); + + OSDArray queryDataArray = (OSDArray)map["QueryData"]; + OSDMap queryDataMap = (OSDMap)queryDataArray[0]; + QueryID = queryDataMap["QueryID"].AsUUID(); + + OSDArray queryRepliesArray = (OSDArray)map["QueryReplies"]; + + QueryReplies = new QueryReply[queryRepliesArray.Count]; + for (int i = 0; i < queryRepliesArray.Count; i++) + { + QueryReply reply = new QueryReply(); + OSDMap replyMap = (OSDMap)queryRepliesArray[i]; + reply.ActualArea = replyMap["ActualArea"].AsInteger(); + reply.Auction = replyMap["Auction"].AsBoolean(); + reply.ForSale = replyMap["ForSale"].AsBoolean(); + reply.Name = replyMap["Name"].AsString(); + reply.ParcelID = replyMap["ParcelID"].AsUUID(); + reply.ProductSku = replyMap["ProductSKU"].AsString(); + reply.SalePrice = replyMap["SalePrice"].AsInteger(); + + QueryReplies[i] = reply; + } + } + } + + #endregion + + #region Object Messages + + public class UploadObjectAssetMessage : IMessage + { + public class Object + { + public class Face + { + public Bumpiness Bump; + public Color4 Color; + public bool Fullbright; + public float Glow; + public UUID ImageID; + public float ImageRot; + public int MediaFlags; + public float OffsetS; + public float OffsetT; + public float ScaleS; + public float ScaleT; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["bump"] = OSD.FromInteger((int)Bump); + map["colors"] = OSD.FromColor4(Color); + map["fullbright"] = OSD.FromBoolean(Fullbright); + map["glow"] = OSD.FromReal(Glow); + map["imageid"] = OSD.FromUUID(ImageID); + map["imagerot"] = OSD.FromReal(ImageRot); + map["media_flags"] = OSD.FromInteger(MediaFlags); + map["offsets"] = OSD.FromReal(OffsetS); + map["offsett"] = OSD.FromReal(OffsetT); + map["scales"] = OSD.FromReal(ScaleS); + map["scalet"] = OSD.FromReal(ScaleT); + + return map; + } + + public void Deserialize(OSDMap map) + { + Bump = (Bumpiness)map["bump"].AsInteger(); + Color = map["colors"].AsColor4(); + Fullbright = map["fullbright"].AsBoolean(); + Glow = (float)map["glow"].AsReal(); + ImageID = map["imageid"].AsUUID(); + ImageRot = (float)map["imagerot"].AsReal(); + MediaFlags = map["media_flags"].AsInteger(); + OffsetS = (float)map["offsets"].AsReal(); + OffsetT = (float)map["offsett"].AsReal(); + ScaleS = (float)map["scales"].AsReal(); + ScaleT = (float)map["scalet"].AsReal(); + } + } + + public class ExtraParam + { + public ExtraParamType Type; + public byte[] ExtraParamData; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["extra_parameter"] = OSD.FromInteger((int)Type); + map["param_data"] = OSD.FromBinary(ExtraParamData); + + return map; + } + + public void Deserialize(OSDMap map) + { + Type = (ExtraParamType)map["extra_parameter"].AsInteger(); + ExtraParamData = map["param_data"].AsBinary(); + } + } + + public Face[] Faces; + public ExtraParam[] ExtraParams; + public UUID GroupID; + public Material Material; + public string Name; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Scale; + public float PathBegin; + public int PathCurve; + public float PathEnd; + public float RadiusOffset; + public float Revolutions; + public float ScaleX; + public float ScaleY; + public float ShearX; + public float ShearY; + public float Skew; + public float TaperX; + public float TaperY; + public float Twist; + public float TwistBegin; + public float ProfileBegin; + public int ProfileCurve; + public float ProfileEnd; + public float ProfileHollow; + public UUID SculptID; + public SculptType SculptType; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + + map["group-id"] = OSD.FromUUID(GroupID); + map["material"] = OSD.FromInteger((int)Material); + map["name"] = OSD.FromString(Name); + map["pos"] = OSD.FromVector3(Position); + map["rotation"] = OSD.FromQuaternion(Rotation); + map["scale"] = OSD.FromVector3(Scale); + + // Extra params + OSDArray extraParams = new OSDArray(); + if (ExtraParams != null) + { + for (int i = 0; i < ExtraParams.Length; i++) + extraParams.Add(ExtraParams[i].Serialize()); + } + map["extra_parameters"] = extraParams; + + // Faces + OSDArray faces = new OSDArray(); + if (Faces != null) + { + for (int i = 0; i < Faces.Length; i++) + faces.Add(Faces[i].Serialize()); + } + map["facelist"] = faces; + + // Shape + OSDMap shape = new OSDMap(); + OSDMap path = new OSDMap(); + path["begin"] = OSD.FromReal(PathBegin); + path["curve"] = OSD.FromInteger(PathCurve); + path["end"] = OSD.FromReal(PathEnd); + path["radius_offset"] = OSD.FromReal(RadiusOffset); + path["revolutions"] = OSD.FromReal(Revolutions); + path["scale_x"] = OSD.FromReal(ScaleX); + path["scale_y"] = OSD.FromReal(ScaleY); + path["shear_x"] = OSD.FromReal(ShearX); + path["shear_y"] = OSD.FromReal(ShearY); + path["skew"] = OSD.FromReal(Skew); + path["taper_x"] = OSD.FromReal(TaperX); + path["taper_y"] = OSD.FromReal(TaperY); + path["twist"] = OSD.FromReal(Twist); + path["twist_begin"] = OSD.FromReal(TwistBegin); + shape["path"] = path; + OSDMap profile = new OSDMap(); + profile["begin"] = OSD.FromReal(ProfileBegin); + profile["curve"] = OSD.FromInteger(ProfileCurve); + profile["end"] = OSD.FromReal(ProfileEnd); + profile["hollow"] = OSD.FromReal(ProfileHollow); + shape["profile"] = profile; + OSDMap sculpt = new OSDMap(); + sculpt["id"] = OSD.FromUUID(SculptID); + sculpt["type"] = OSD.FromInteger((int)SculptType); + shape["sculpt"] = sculpt; + map["shape"] = shape; + + return map; + } + + public void Deserialize(OSDMap map) + { + GroupID = map["group-id"].AsUUID(); + Material = (Material)map["material"].AsInteger(); + Name = map["name"].AsString(); + Position = map["pos"].AsVector3(); + Rotation = map["rotation"].AsQuaternion(); + Scale = map["scale"].AsVector3(); + + // Extra params + OSDArray extraParams = map["extra_parameters"] as OSDArray; + if (extraParams != null) + { + ExtraParams = new ExtraParam[extraParams.Count]; + for (int i = 0; i < extraParams.Count; i++) + { + ExtraParam extraParam = new ExtraParam(); + extraParam.Deserialize(extraParams[i] as OSDMap); + ExtraParams[i] = extraParam; + } + } + else + { + ExtraParams = new ExtraParam[0]; + } + + // Faces + OSDArray faces = map["facelist"] as OSDArray; + if (faces != null) + { + Faces = new Face[faces.Count]; + for (int i = 0; i < faces.Count; i++) + { + Face face = new Face(); + face.Deserialize(faces[i] as OSDMap); + Faces[i] = face; + } + } + else + { + Faces = new Face[0]; + } + + // Shape + OSDMap shape = map["shape"] as OSDMap; + OSDMap path = shape["path"] as OSDMap; + PathBegin = (float)path["begin"].AsReal(); + PathCurve = path["curve"].AsInteger(); + PathEnd = (float)path["end"].AsReal(); + RadiusOffset = (float)path["radius_offset"].AsReal(); + Revolutions = (float)path["revolutions"].AsReal(); + ScaleX = (float)path["scale_x"].AsReal(); + ScaleY = (float)path["scale_y"].AsReal(); + ShearX = (float)path["shear_x"].AsReal(); + ShearY = (float)path["shear_y"].AsReal(); + Skew = (float)path["skew"].AsReal(); + TaperX = (float)path["taper_x"].AsReal(); + TaperY = (float)path["taper_y"].AsReal(); + Twist = (float)path["twist"].AsReal(); + TwistBegin = (float)path["twist_begin"].AsReal(); + + OSDMap profile = shape["profile"] as OSDMap; + ProfileBegin = (float)profile["begin"].AsReal(); + ProfileCurve = profile["curve"].AsInteger(); + ProfileEnd = (float)profile["end"].AsReal(); + ProfileHollow = (float)profile["hollow"].AsReal(); + + OSDMap sculpt = shape["sculpt"] as OSDMap; + if (sculpt != null) + { + SculptID = sculpt["id"].AsUUID(); + SculptType = (SculptType)sculpt["type"].AsInteger(); + } + else + { + SculptID = UUID.Zero; + SculptType = 0; + } + } + } + + public Object[] Objects; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + OSDArray array = new OSDArray(); + + if (Objects != null) + { + for (int i = 0; i < Objects.Length; i++) + array.Add(Objects[i].Serialize()); + } + + map["objects"] = array; + return map; + } + + public void Deserialize(OSDMap map) + { + OSDArray array = map["objects"] as OSDArray; + + if (array != null) + { + Objects = new Object[array.Count]; + + for (int i = 0; i < array.Count; i++) + { + Object obj = new Object(); + OSDMap objMap = array[i] as OSDMap; + + if (objMap != null) + obj.Deserialize(objMap); + + Objects[i] = obj; + } + } + else + { + Objects = new Object[0]; + } + } + } + + /// + /// Event Queue message describing physics engine attributes of a list of objects + /// Sim sends these when object is selected + /// + public class ObjectPhysicsPropertiesMessage : IMessage + { + /// Array with the list of physics properties + public Primitive.PhysicsProperties[] ObjectPhysicsProperties; + + /// + /// Serializes the message + /// + /// Serialized OSD + public OSDMap Serialize() + { + OSDMap ret = new OSDMap(); + OSDArray array = new OSDArray(); + + for (int i = 0; i < ObjectPhysicsProperties.Length; i++) + { + array.Add(ObjectPhysicsProperties[i].GetOSD()); + } + + ret["ObjectData"] = array; + return ret; + + } + + /// + /// Deseializes the message + /// + /// Incoming data to deserialize + public void Deserialize(OSDMap map) + { + OSDArray array = map["ObjectData"] as OSDArray; + if (array != null) + { + ObjectPhysicsProperties = new Primitive.PhysicsProperties[array.Count]; + + for (int i = 0; i < array.Count; i++) + { + ObjectPhysicsProperties[i] = Primitive.PhysicsProperties.FromOSD(array[i]); + } + } + else + { + ObjectPhysicsProperties = new Primitive.PhysicsProperties[0]; + } + } + } + + public class RenderMaterialsMessage : IMessage + { + public OSD MaterialData; + + public void Deserialize(OSDMap map) + { + try + { + using (MemoryStream input = new MemoryStream(map["Zipped"].AsBinary())) + { + using (MemoryStream output = new MemoryStream()) + { + using (ZOutputStream zout = new ZOutputStream(output)) + { + byte[] buffer = new byte[2048]; + int len; + while ((len = input.Read(buffer, 0, buffer.Length)) > 0) + { + zout.Write(buffer, 0, len); + } + zout.Flush(); + output.Seek(0, SeekOrigin.Begin); + MaterialData = OSDParser.DeserializeLLSDBinary(output); + } + } + } + } + catch (Exception ex) + { + Logger.Log("Failed to decode RenderMaterials message:", Helpers.LogLevel.Warning, ex); + MaterialData = new OSDMap(); + } + } + + public OSDMap Serialize() + { + return new OSDMap(); + } + + + } + + + #endregion Object Messages + + #region Object Media Messages + /// + /// A message sent from the viewer to the simulator which + /// specifies that the user has changed current URL + /// of the specific media on a prim face + /// + public class ObjectMediaNavigateMessage : IMessage + { + /// + /// New URL + /// + public string URL; + + /// + /// Prim UUID where navigation occured + /// + public UUID PrimID; + + /// + /// Face index + /// + public int Face; + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(3); + + map["current_url"] = OSD.FromString(URL); + map["object_id"] = OSD.FromUUID(PrimID); + map["texture_index"] = OSD.FromInteger(Face); + + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + URL = map["current_url"].AsString(); + PrimID = map["object_id"].AsUUID(); + Face = map["texture_index"].AsInteger(); + } + } + + + /// Base class used for the ObjectMedia message + [Serializable] + public abstract class ObjectMediaBlock + { + public abstract OSDMap Serialize(); + public abstract void Deserialize(OSDMap map); + } + + /// + /// Message used to retrive prim media data + /// + public class ObjectMediaRequest : ObjectMediaBlock + { + /// + /// Prim UUID + /// + public UUID PrimID; + + /// + /// Requested operation, either GET or UPDATE + /// + public string Verb = "GET"; // "GET" or "UPDATE" + + /// + /// Serialize object + /// + /// Serialized object as OSDMap + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["object_id"] = OSD.FromUUID(PrimID); + map["verb"] = OSD.FromString(Verb); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + PrimID = map["object_id"].AsUUID(); + Verb = map["verb"].AsString(); + } + } + + + /// + /// Message used to update prim media data + /// + public class ObjectMediaResponse : ObjectMediaBlock + { + /// + /// Prim UUID + /// + public UUID PrimID; + + /// + /// Array of media entries indexed by face number + /// + public MediaEntry[] FaceMedia; + + /// + /// Media version string + /// + public string Version; // String in this format: x-mv:0000000016/00000000-0000-0000-0000-000000000000 + + /// + /// Serialize object + /// + /// Serialized object as OSDMap + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["object_id"] = OSD.FromUUID(PrimID); + + if (FaceMedia == null) + { + map["object_media_data"] = new OSDArray(); + } + else + { + OSDArray mediaData = new OSDArray(FaceMedia.Length); + + for (int i = 0; i < FaceMedia.Length; i++) + { + if (FaceMedia[i] == null) + mediaData.Add(new OSD()); + else + mediaData.Add(FaceMedia[i].GetOSD()); + } + + map["object_media_data"] = mediaData; + } + + map["object_media_version"] = OSD.FromString(Version); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + PrimID = map["object_id"].AsUUID(); + + if (map["object_media_data"].Type == OSDType.Array) + { + OSDArray mediaData = (OSDArray)map["object_media_data"]; + if (mediaData.Count > 0) + { + FaceMedia = new MediaEntry[mediaData.Count]; + for (int i = 0; i < mediaData.Count; i++) + { + if (mediaData[i].Type == OSDType.Map) + { + FaceMedia[i] = MediaEntry.FromOSD(mediaData[i]); + } + } + } + } + Version = map["object_media_version"].AsString(); + } + } + + + /// + /// Message used to update prim media data + /// + public class ObjectMediaUpdate : ObjectMediaBlock + { + /// + /// Prim UUID + /// + public UUID PrimID; + + /// + /// Array of media entries indexed by face number + /// + public MediaEntry[] FaceMedia; + + /// + /// Requested operation, either GET or UPDATE + /// + public string Verb = "UPDATE"; // "GET" or "UPDATE" + + /// + /// Serialize object + /// + /// Serialized object as OSDMap + public override OSDMap Serialize() + { + OSDMap map = new OSDMap(2); + map["object_id"] = OSD.FromUUID(PrimID); + + if (FaceMedia == null) + { + map["object_media_data"] = new OSDArray(); + } + else + { + OSDArray mediaData = new OSDArray(FaceMedia.Length); + + for (int i = 0; i < FaceMedia.Length; i++) + { + if (FaceMedia[i] == null) + mediaData.Add(new OSD()); + else + mediaData.Add(FaceMedia[i].GetOSD()); + } + + map["object_media_data"] = mediaData; + } + + map["verb"] = OSD.FromString(Verb); + return map; + } + + /// + /// Deserialize the message + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + PrimID = map["object_id"].AsUUID(); + + if (map["object_media_data"].Type == OSDType.Array) + { + OSDArray mediaData = (OSDArray)map["object_media_data"]; + if (mediaData.Count > 0) + { + FaceMedia = new MediaEntry[mediaData.Count]; + for (int i = 0; i < mediaData.Count; i++) + { + if (mediaData[i].Type == OSDType.Map) + { + FaceMedia[i] = MediaEntry.FromOSD(mediaData[i]); + } + } + } + } + Verb = map["verb"].AsString(); + } + } + + /// + /// Message for setting or getting per face MediaEntry + /// + [Serializable] + public class ObjectMediaMessage : IMessage + { + /// The request or response details block + public ObjectMediaBlock Request; + + /// + /// Serialize the object + /// + /// An containing the objects data + public OSDMap Serialize() + { + return Request.Serialize(); + } + + /// + /// Deserialize the message + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("verb")) + { + if (map["verb"].AsString() == "GET") + Request = new ObjectMediaRequest(); + else if (map["verb"].AsString() == "UPDATE") + Request = new ObjectMediaUpdate(); + } + else if (map.ContainsKey("object_media_version")) + Request = new ObjectMediaResponse(); + else + Logger.Log("Unable to deserialize ObjectMedia: No message handler exists for method: " + map.AsString(), Helpers.LogLevel.Warning); + + if (Request != null) + Request.Deserialize(map); + } + } + #endregion Object Media Messages + + #region Resource usage + /// Details about object resource usage + public class ObjectResourcesDetail + { + /// Object UUID + public UUID ID; + /// Object name + public string Name; + /// Indicates if object is group owned + public bool GroupOwned; + /// Locatio of the object + public Vector3d Location; + /// Object owner + public UUID OwnerID; + /// Resource usage, keys are resource names, values are resource usage for that specific resource + public Dictionary Resources; + + /// + /// Deserializes object from OSD + /// + /// An containing the data + public virtual void Deserialize(OSDMap obj) + { + ID = obj["id"].AsUUID(); + Name = obj["name"].AsString(); + Location = obj["location"].AsVector3d(); + GroupOwned = obj["is_group_owned"].AsBoolean(); + OwnerID = obj["owner_id"].AsUUID(); + OSDMap resources = (OSDMap)obj["resources"]; + Resources = new Dictionary(resources.Keys.Count); + foreach (KeyValuePair kvp in resources) + { + Resources.Add(kvp.Key, kvp.Value.AsInteger()); + } + } + + /// + /// Makes an instance based on deserialized data + /// + /// serialized data + /// Instance containg deserialized data + public static ObjectResourcesDetail FromOSD(OSD osd) + { + ObjectResourcesDetail res = new ObjectResourcesDetail(); + res.Deserialize((OSDMap)osd); + return res; + } + } + + /// Details about parcel resource usage + public class ParcelResourcesDetail + { + /// Parcel UUID + public UUID ID; + /// Parcel local ID + public int LocalID; + /// Parcel name + public string Name; + /// Indicates if parcel is group owned + public bool GroupOwned; + /// Parcel owner + public UUID OwnerID; + /// Array of containing per object resource usage + public ObjectResourcesDetail[] Objects; + + /// + /// Deserializes object from OSD + /// + /// An containing the data + public virtual void Deserialize(OSDMap map) + { + ID = map["id"].AsUUID(); + LocalID = map["local_id"].AsInteger(); + Name = map["name"].AsString(); + GroupOwned = map["is_group_owned"].AsBoolean(); + OwnerID = map["owner_id"].AsUUID(); + + OSDArray objectsOSD = (OSDArray)map["objects"]; + Objects = new ObjectResourcesDetail[objectsOSD.Count]; + + for (int i = 0; i < objectsOSD.Count; i++) + { + Objects[i] = ObjectResourcesDetail.FromOSD(objectsOSD[i]); + } + } + + /// + /// Makes an instance based on deserialized data + /// + /// serialized data + /// Instance containg deserialized data + public static ParcelResourcesDetail FromOSD(OSD osd) + { + ParcelResourcesDetail res = new ParcelResourcesDetail(); + res.Deserialize((OSDMap)osd); + return res; + } + } + + /// Resource usage base class, both agent and parcel resource + /// usage contains summary information + public abstract class BaseResourcesInfo : IMessage + { + /// Summary of available resources, keys are resource names, + /// values are resource usage for that specific resource + public Dictionary SummaryAvailable; + /// Summary resource usage, keys are resource names, + /// values are resource usage for that specific resource + public Dictionary SummaryUsed; + + /// + /// Serializes object + /// + /// serialized data + public virtual OSDMap Serialize() + { + throw new NotImplementedException(); + } + + /// + /// Deserializes object from OSD + /// + /// An containing the data + public virtual void Deserialize(OSDMap map) + { + SummaryAvailable = new Dictionary(); + SummaryUsed = new Dictionary(); + + OSDMap summary = (OSDMap)map["summary"]; + OSDArray available = (OSDArray)summary["available"]; + OSDArray used = (OSDArray)summary["used"]; + + for (int i = 0; i < available.Count; i++) + { + OSDMap limit = (OSDMap)available[i]; + SummaryAvailable.Add(limit["type"].AsString(), limit["amount"].AsInteger()); + } + + for (int i = 0; i < used.Count; i++) + { + OSDMap limit = (OSDMap)used[i]; + SummaryUsed.Add(limit["type"].AsString(), limit["amount"].AsInteger()); + } + } + } + + /// Agent resource usage + public class AttachmentResourcesMessage : BaseResourcesInfo + { + /// Per attachment point object resource usage + public Dictionary Attachments; + + /// + /// Deserializes object from OSD + /// + /// An containing the data + public override void Deserialize(OSDMap osd) + { + base.Deserialize(osd); + OSDArray attachments = (OSDArray)((OSDMap)osd)["attachments"]; + Attachments = new Dictionary(); + + for (int i = 0; i < attachments.Count; i++) + { + OSDMap attachment = (OSDMap)attachments[i]; + AttachmentPoint pt = Utils.StringToAttachmentPoint(attachment["location"].AsString()); + + OSDArray objectsOSD = (OSDArray)attachment["objects"]; + ObjectResourcesDetail[] objects = new ObjectResourcesDetail[objectsOSD.Count]; + + for (int j = 0; j < objects.Length; j++) + { + objects[j] = ObjectResourcesDetail.FromOSD(objectsOSD[j]); + } + + Attachments.Add(pt, objects); + } + } + + /// + /// Makes an instance based on deserialized data + /// + /// serialized data + /// Instance containg deserialized data + public static AttachmentResourcesMessage FromOSD(OSD osd) + { + AttachmentResourcesMessage res = new AttachmentResourcesMessage(); + res.Deserialize((OSDMap)osd); + return res; + } + + /// + /// Detects which class handles deserialization of this message + /// + /// An containing the data + /// Object capable of decoding this message + public static IMessage GetMessageHandler(OSDMap map) + { + if (map == null) + { + return null; + } + else + { + return new AttachmentResourcesMessage(); + } + } + } + + /// Request message for parcel resource usage + public class LandResourcesRequest : IMessage + { + /// UUID of the parel to request resource usage info + public UUID ParcelID; + + /// + /// Serializes object + /// + /// serialized data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + map["parcel_id"] = OSD.FromUUID(ParcelID); + return map; + } + + /// + /// Deserializes object from OSD + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + ParcelID = map["parcel_id"].AsUUID(); + } + } + + /// Response message for parcel resource usage + public class LandResourcesMessage : IMessage + { + /// URL where parcel resource usage details can be retrieved + public Uri ScriptResourceDetails; + /// URL where parcel resource usage summary can be retrieved + public Uri ScriptResourceSummary; + + /// + /// Serializes object + /// + /// serialized data + public OSDMap Serialize() + { + OSDMap map = new OSDMap(1); + if (ScriptResourceSummary != null) + { + map["ScriptResourceSummary"] = OSD.FromString(ScriptResourceSummary.ToString()); + } + + if (ScriptResourceDetails != null) + { + map["ScriptResourceDetails"] = OSD.FromString(ScriptResourceDetails.ToString()); + } + return map; + } + + /// + /// Deserializes object from OSD + /// + /// An containing the data + public void Deserialize(OSDMap map) + { + if (map.ContainsKey("ScriptResourceSummary")) + { + ScriptResourceSummary = new Uri(map["ScriptResourceSummary"].AsString()); + } + if (map.ContainsKey("ScriptResourceDetails")) + { + ScriptResourceDetails = new Uri(map["ScriptResourceDetails"].AsString()); + } + } + + /// + /// Detects which class handles deserialization of this message + /// + /// An containing the data + /// Object capable of decoding this message + public static IMessage GetMessageHandler(OSDMap map) + { + if (map.ContainsKey("parcel_id")) + { + return new LandResourcesRequest(); + } + else if (map.ContainsKey("ScriptResourceSummary")) + { + return new LandResourcesMessage(); + } + return null; + } + } + + /// Parcel resource usage + public class LandResourcesInfo : BaseResourcesInfo + { + /// Array of containing per percal resource usage + public ParcelResourcesDetail[] Parcels; + + /// + /// Deserializes object from OSD + /// + /// An containing the data + public override void Deserialize(OSDMap map) + { + if (map.ContainsKey("summary")) + { + base.Deserialize(map); + } + else if (map.ContainsKey("parcels")) + { + OSDArray parcelsOSD = (OSDArray)map["parcels"]; + Parcels = new ParcelResourcesDetail[parcelsOSD.Count]; + + for (int i = 0; i < parcelsOSD.Count; i++) + { + Parcels[i] = ParcelResourcesDetail.FromOSD(parcelsOSD[i]); + } + } + } + } + + #endregion Resource usage + + #region Display names + /// + /// Reply to request for bunch if display names + /// + public class GetDisplayNamesMessage : IMessage + { + /// Current display name + public AgentDisplayName[] Agents = new AgentDisplayName[0]; + + /// Following UUIDs failed to return a valid display name + public UUID[] BadIDs = new UUID[0]; + + /// + /// Serializes the message + /// + /// OSD containting the messaage + public OSDMap Serialize() + { + OSDArray agents = new OSDArray(); + + if (Agents != null && Agents.Length > 0) + { + for (int i = 0; i < Agents.Length; i++) + { + agents.Add(Agents[i].GetOSD()); + } + } + + OSDArray badIDs = new OSDArray(); + if (BadIDs != null && BadIDs.Length > 0) + { + for (int i = 0; i < BadIDs.Length; i++) + { + badIDs.Add(new OSDUUID(BadIDs[i])); + } + } + + OSDMap ret = new OSDMap(); + ret["agents"] = agents; + ret["bad_ids"] = badIDs; + return ret; + } + + public void Deserialize(OSDMap map) + { + if (map["agents"].Type == OSDType.Array) + { + OSDArray osdAgents = (OSDArray)map["agents"]; + + if (osdAgents.Count > 0) + { + Agents = new AgentDisplayName[osdAgents.Count]; + + for (int i = 0; i < osdAgents.Count; i++) + { + Agents[i] = AgentDisplayName.FromOSD(osdAgents[i]); + } + } + } + + if (map["bad_ids"].Type == OSDType.Array) + { + OSDArray osdBadIDs = (OSDArray)map["bad_ids"]; + if (osdBadIDs.Count > 0) + { + BadIDs = new UUID[osdBadIDs.Count]; + + for (int i = 0; i < osdBadIDs.Count; i++) + { + BadIDs[i] = osdBadIDs[i]; + } + } + } + } + } + + /// + /// Message sent when requesting change of the display name + /// + public class SetDisplayNameMessage : IMessage + { + /// Current display name + public string OldDisplayName; + + /// Desired new display name + public string NewDisplayName; + + /// + /// Serializes the message + /// + /// OSD containting the messaage + public OSDMap Serialize() + { + OSDArray names = new OSDArray(2) { OldDisplayName, NewDisplayName }; + + OSDMap name = new OSDMap(); + name["display_name"] = names; + return name; + } + + public void Deserialize(OSDMap map) + { + OSDArray names = (OSDArray)map["display_name"]; + OldDisplayName = names[0]; + NewDisplayName = names[1]; + } + } + + /// + /// Message recieved in response to request to change display name + /// + public class SetDisplayNameReplyMessage : IMessage + { + /// New display name + public AgentDisplayName DisplayName; + + /// String message indicating the result of the operation + public string Reason; + + /// Numerical code of the result, 200 indicates success + public int Status; + + /// + /// Serializes the message + /// + /// OSD containting the messaage + public OSDMap Serialize() + { + OSDMap agent = (OSDMap)DisplayName.GetOSD(); + OSDMap ret = new OSDMap(); + ret["content"] = agent; + ret["reason"] = Reason; + ret["status"] = Status; + return ret; + } + + public void Deserialize(OSDMap map) + { + OSDMap agent = (OSDMap)map["content"]; + DisplayName = AgentDisplayName.FromOSD(agent); + Reason = map["reason"]; + Status = map["status"]; + } + } + + /// + /// Message recieved when someone nearby changes their display name + /// + public class DisplayNameUpdateMessage : IMessage + { + /// Previous display name, empty string if default + public string OldDisplayName; + + /// New display name + public AgentDisplayName DisplayName; + + /// + /// Serializes the message + /// + /// OSD containting the messaage + public OSDMap Serialize() + { + OSDMap agent = (OSDMap)DisplayName.GetOSD(); + agent["old_display_name"] = OldDisplayName; + OSDMap ret = new OSDMap(); + ret["agent"] = agent; + return ret; + } + + public void Deserialize(OSDMap map) + { + OSDMap agent = (OSDMap)map["agent"]; + DisplayName = AgentDisplayName.FromOSD(agent); + OldDisplayName = agent["old_display_name"]; + } + } + #endregion Display names +} diff --git a/OpenMetaverse/Messages/MessageEventDecoder.cs b/OpenMetaverse/Messages/MessageEventDecoder.cs new file mode 100644 index 0000000..5b53e19 --- /dev/null +++ b/OpenMetaverse/Messages/MessageEventDecoder.cs @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse.Messages +{ + + public static partial class MessageUtils + { + /// + /// Return a decoded capabilities message as a strongly typed object + /// + /// A string containing the name of the capabilities message key + /// An to decode + /// A strongly typed object containing the decoded information from the capabilities message, or null + /// if no existing Message object exists for the specified event + public static IMessage DecodeEvent(string eventName, OSDMap map) + { + IMessage message = null; + + switch (eventName) + { + case "AgentGroupDataUpdate": message = new AgentGroupDataUpdateMessage(); break; + case "AvatarGroupsReply": message = new AgentGroupDataUpdateMessage(); break; // OpenSim sends the above with the wrong? key + case "ParcelProperties": message = new ParcelPropertiesMessage(); break; + case "ParcelObjectOwnersReply": message = new ParcelObjectOwnersReplyMessage(); break; + case "TeleportFinish": message = new TeleportFinishMessage(); break; + case "EnableSimulator": message = new EnableSimulatorMessage(); break; + case "ParcelPropertiesUpdate": message = new ParcelPropertiesUpdateMessage(); break; + case "EstablishAgentCommunication": message = new EstablishAgentCommunicationMessage(); break; + case "ChatterBoxInvitation": message = new ChatterBoxInvitationMessage(); break; + case "ChatterBoxSessionEventReply": message = new ChatterboxSessionEventReplyMessage(); break; + case "ChatterBoxSessionStartReply": message = new ChatterBoxSessionStartReplyMessage(); break; + case "ChatterBoxSessionAgentListUpdates": message = new ChatterBoxSessionAgentListUpdatesMessage(); break; + case "RequiredVoiceVersion": message = new RequiredVoiceVersionMessage(); break; + case "MapLayer": message = new MapLayerMessage(); break; + case "ChatSessionRequest": message = new ChatSessionRequestMessage(); break; + case "CopyInventoryFromNotecard": message = new CopyInventoryFromNotecardMessage(); break; + case "ProvisionVoiceAccountRequest": message = new ProvisionVoiceAccountRequestMessage(); break; + case "Viewerstats": message = new ViewerStatsMessage(); break; + case "UpdateAgentLanguage": message = new UpdateAgentLanguageMessage(); break; + case "RemoteParcelRequest": message = new RemoteParcelRequestMessage(); break; + case "UpdateScriptTask": message = new UpdateScriptTaskMessage(); break; + case "UpdateScriptAgent": message = new UpdateScriptAgentMessage(); break; + case "SendPostcard": message = new SendPostcardMessage(); break; + case "UpdateGestureAgentInventory": message = new UpdateGestureAgentInventoryMessage(); break; + case "UpdateNotecardAgentInventory": message = new UpdateNotecardAgentInventoryMessage(); break; + case "LandStatReply": message = new LandStatReplyMessage(); break; + case "ParcelVoiceInfoRequest": message = new ParcelVoiceInfoRequestMessage(); break; + case "ViewerStats": message = new ViewerStatsMessage(); break; + case "EventQueueGet": message = new EventQueueGetMessage(); break; + case "CrossedRegion": message = new CrossedRegionMessage(); break; + case "TeleportFailed": message = new TeleportFailedMessage(); break; + case "PlacesReply": message = new PlacesReplyMessage(); break; + case "UpdateAgentInformation": message = new UpdateAgentInformationMessage(); break; + case "DirLandReply": message = new DirLandReplyMessage(); break; + case "ScriptRunningReply": message = new ScriptRunningReplyMessage(); break; + case "SearchStatRequest": message = new SearchStatRequestMessage(); break; + case "AgentDropGroup": message = new AgentDropGroupMessage(); break; + case "AgentStateUpdate": message = new AgentStateUpdateMessage(); break; + case "ForceCloseChatterBoxSession": message = new ForceCloseChatterBoxSessionMessage(); break; + case "UploadBakedTexture": message = new UploadBakedTextureMessage(); break; + case "RegionInfo": message = new RegionInfoMessage(); break; + case "ObjectMediaNavigate": message = new ObjectMediaNavigateMessage(); break; + case "ObjectMedia": message = new ObjectMediaMessage(); break; + case "AttachmentResources": message = AttachmentResourcesMessage.GetMessageHandler(map); break; + case "LandResources": message = LandResourcesMessage.GetMessageHandler(map); break; + case "GetDisplayNames": message = new GetDisplayNamesMessage(); break; + case "SetDisplayName": message = new SetDisplayNameMessage(); break; + case "SetDisplayNameReply": message = new SetDisplayNameReplyMessage(); break; + case "DisplayNameUpdate": message = new DisplayNameUpdateMessage(); break; + //case "ProductInfoRequest": message = new ProductInfoRequestMessage(); break; + case "ObjectPhysicsProperties": message = new ObjectPhysicsPropertiesMessage(); break; + case "BulkUpdateInventory": message = new BulkUpdateInventoryMessage(); break; + case "RenderMaterials": message = new RenderMaterialsMessage(); break; + + // Capabilities TODO: + // DispatchRegionInfo + // EstateChangeInfo + // EventQueueGet + // FetchInventoryDescendents + // GroupProposalBallot + // MapLayerGod + // NewFileAgentInventory + // RequestTextureDownload + // SearchStatRequest + // SearchStatTracking + // SendUserReport + // SendUserReportWithScreenshot + // ServerReleaseNotes + // StartGroupProposal + // UpdateGestureTaskInventory + // UpdateNotecardTaskInventory + // ViewerStartAuction + // UntrustedSimulatorMessage + } + + if (message != null) + { + try + { + message.Deserialize(map); + return message; + } + catch (Exception e) + { + Logger.Log("Exception while trying to Deserialize " + eventName + ":" + e.Message + ": " + e.StackTrace, Helpers.LogLevel.Error); + } + + return null; + } + else + { + return null; + } + } + } +} diff --git a/OpenMetaverse/Messages/Messages.cs b/OpenMetaverse/Messages/Messages.cs new file mode 100644 index 0000000..65c821b --- /dev/null +++ b/OpenMetaverse/Messages/Messages.cs @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Messages +{ + public static partial class MessageUtils + { + public static IPAddress ToIP(OSD osd) + { + byte[] binary = osd.AsBinary(); + if (binary != null && binary.Length == 4) + return new IPAddress(binary); + else + return IPAddress.Any; + } + + public static OSD FromIP(IPAddress address) + { + if (address != null && address != IPAddress.Any) + return OSD.FromBinary(address.GetAddressBytes()); + else + return new OSD(); + } + + public static Dictionary ToDictionaryString(OSD osd) + { + if (osd.Type == OSDType.Map) + { + OSDMap map = (OSDMap)osd; + Dictionary dict = new Dictionary(map.Count); + foreach (KeyValuePair entry in map) + dict.Add(entry.Key, entry.Value.AsString()); + return dict; + } + + return new Dictionary(0); + } + + public static Dictionary ToDictionaryUri(OSD osd) + { + if (osd.Type == OSDType.Map) + { + OSDMap map = (OSDMap)osd; + Dictionary dict = new Dictionary(map.Count); + foreach (KeyValuePair entry in map) + dict.Add(new Uri(entry.Key), entry.Value.AsUri()); + return dict; + } + + return new Dictionary(0); + } + + public static OSDMap FromDictionaryString(Dictionary dict) + { + if (dict != null) + { + OSDMap map = new OSDMap(dict.Count); + foreach (KeyValuePair entry in dict) + map.Add(entry.Key, OSD.FromString(entry.Value)); + return map; + } + + return new OSDMap(0); + } + + public static OSDMap FromDictionaryUri(Dictionary dict) + { + if (dict != null) + { + OSDMap map = new OSDMap(dict.Count); + foreach (KeyValuePair entry in dict) + map.Add(entry.Key.ToString(), OSD.FromUri(entry.Value)); + return map; + } + + return new OSDMap(0); + } + } +} diff --git a/OpenMetaverse/NameValue.cs b/OpenMetaverse/NameValue.cs new file mode 100644 index 0000000..510067c --- /dev/null +++ b/OpenMetaverse/NameValue.cs @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse +{ + /// + /// A Name Value pair with additional settings, used in the protocol + /// primarily to transmit avatar names and active group in object packets + /// + public struct NameValue + { + #region Enums + + /// Type of the value + public enum ValueType + { + /// Unknown + Unknown = -1, + /// String value + String, + /// + F32, + /// + S32, + /// + VEC3, + /// + U32, + /// Deprecated + [Obsolete] + CAMERA, + /// String value, but designated as an asset + Asset, + /// + U64 + } + + /// + /// + /// + public enum ClassType + { + /// + Unknown = -1, + /// + ReadOnly, + /// + ReadWrite, + /// + Callback + } + + /// + /// + /// + public enum SendtoType + { + /// + Unknown = -1, + /// + Sim, + /// + DataSim, + /// + SimViewer, + /// + DataSimViewer + } + + #endregion Enums + + + /// + public string Name; + /// + public ValueType Type; + /// + public ClassType Class; + /// + public SendtoType Sendto; + /// + public object Value; + + + private static readonly string[] TypeStrings = new string[] + { + "STRING", + "F32", + "S32", + "VEC3", + "U32", + "ASSET", + "U64" + }; + private static readonly string[] ClassStrings = new string[] + { + "R", // Read-only + "RW", // Read-write + "CB" // Callback + }; + private static readonly string[] SendtoStrings = new string[] + { + "S", // Sim + "DS", // Data Sim + "SV", // Sim Viewer + "DSV" // Data Sim Viewer + }; + private static readonly char[] Separators = new char[] + { + ' ', + '\n', + '\t', + '\r' + }; + + /// + /// Constructor that takes all the fields as parameters + /// + /// + /// + /// + /// + /// + public NameValue(string name, ValueType valueType, ClassType classType, SendtoType sendtoType, object value) + { + Name = name; + Type = valueType; + Class = classType; + Sendto = sendtoType; + Value = value; + } + + /// + /// Constructor that takes a single line from a NameValue field + /// + /// + public NameValue(string data) + { + int i; + + // Name + i = data.IndexOfAny(Separators); + if (i < 1) + { + Name = String.Empty; + Type = ValueType.Unknown; + Class = ClassType.Unknown; + Sendto = SendtoType.Unknown; + Value = null; + return; + } + Name = data.Substring(0, i); + data = data.Substring(i + 1); + + // Type + i = data.IndexOfAny(Separators); + if (i > 0) + { + Type = GetValueType(data.Substring(0, i)); + data = data.Substring(i + 1); + + // Class + i = data.IndexOfAny(Separators); + if (i > 0) + { + Class = GetClassType(data.Substring(0, i)); + data = data.Substring(i + 1); + + // Sendto + i = data.IndexOfAny(Separators); + if (i > 0) + { + Sendto = GetSendtoType(data.Substring(0, 1)); + data = data.Substring(i + 1); + } + } + } + + // Value + Type = ValueType.String; + Class = ClassType.ReadOnly; + Sendto = SendtoType.Sim; + Value = null; + SetValue(data); + } + + public static string NameValuesToString(NameValue[] values) + { + if (values == null || values.Length == 0) + return String.Empty; + + StringBuilder output = new StringBuilder(); + + for (int i = 0; i < values.Length; i++) + { + NameValue value = values[i]; + + if (value.Value != null) + { + string newLine = (i < values.Length - 1) ? "\n" : String.Empty; + output.AppendFormat("{0} {1} {2} {3} {4}{5}", value.Name, TypeStrings[(int)value.Type], + ClassStrings[(int)value.Class], SendtoStrings[(int)value.Sendto], value.Value.ToString(), newLine); + } + } + + return output.ToString(); + } + + private void SetValue(string value) + { + switch (Type) + { + case ValueType.Asset: + case ValueType.String: + Value = value; + break; + case ValueType.F32: + { + float temp; + Utils.TryParseSingle(value, out temp); + Value = temp; + break; + } + case ValueType.S32: + { + int temp; + Int32.TryParse(value, out temp); + Value = temp; + break; + } + case ValueType.U32: + { + uint temp; + UInt32.TryParse(value, out temp); + Value = temp; + break; + } + case ValueType.U64: + { + ulong temp; + UInt64.TryParse(value, out temp); + Value = temp; + break; + } + case ValueType.VEC3: + { + Vector3 temp; + Vector3.TryParse(value, out temp); + Value = temp; + break; + } + default: + Value = null; + break; + } + } + + private static ValueType GetValueType(string value) + { + ValueType type = ValueType.Unknown; + + for (int i = 0; i < TypeStrings.Length; i++) + { + if (value == TypeStrings[i]) + { + type = (ValueType)i; + break; + } + } + + if (type == ValueType.Unknown) + type = ValueType.String; + + return type; + } + + private static ClassType GetClassType(string value) + { + ClassType type = ClassType.Unknown; + + for (int i = 0; i < ClassStrings.Length; i++) + { + if (value == ClassStrings[i]) + { + type = (ClassType)i; + break; + } + } + + if (type == ClassType.Unknown) + type = ClassType.ReadOnly; + + return type; + } + + private static SendtoType GetSendtoType(string value) + { + SendtoType type = SendtoType.Unknown; + + for (int i = 0; i < SendtoStrings.Length; i++) + { + if (value == SendtoStrings[i]) + { + type = (SendtoType)i; + break; + } + } + + if (type == SendtoType.Unknown) + type = SendtoType.Sim; + + return type; + } + } +} diff --git a/OpenMetaverse/NetworkManager.cs b/OpenMetaverse/NetworkManager.cs new file mode 100644 index 0000000..5654c73 --- /dev/null +++ b/OpenMetaverse/NetworkManager.cs @@ -0,0 +1,1356 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Globalization; +using System.IO; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse +{ + /// + /// NetworkManager is responsible for managing the network layer of + /// OpenMetaverse. It tracks all the server connections, serializes + /// outgoing traffic and deserializes incoming traffic, and provides + /// instances of delegates for network-related events. + /// + public partial class NetworkManager + { + #region Enums + + /// + /// Explains why a simulator or the grid disconnected from us + /// + public enum DisconnectType + { + /// The client requested the logout or simulator disconnect + ClientInitiated, + /// The server notified us that it is disconnecting + ServerInitiated, + /// Either a socket was closed or network traffic timed out + NetworkTimeout, + /// The last active simulator shut down + SimShutdown + } + + #endregion Enums + + #region Structs + + /// + /// Holds a simulator reference and a decoded packet, these structs are put in + /// the packet inbox for event handling + /// + public struct IncomingPacket + { + /// Reference to the simulator that this packet came from + public Simulator Simulator; + /// Packet that needs to be processed + public Packet Packet; + + public IncomingPacket(Simulator simulator, Packet packet) + { + Simulator = simulator; + Packet = packet; + } + } + + /// + /// Holds a simulator reference and a serialized packet, these structs are put in + /// the packet outbox for sending + /// + public class OutgoingPacket + { + /// Reference to the simulator this packet is destined for + public readonly Simulator Simulator; + /// Packet that needs to be sent + public readonly UDPPacketBuffer Buffer; + /// Sequence number of the wrapped packet + public uint SequenceNumber; + /// Number of times this packet has been resent + public int ResendCount; + /// Environment.TickCount when this packet was last sent over the wire + public int TickCount; + /// Type of the packet + public PacketType Type; + + public OutgoingPacket(Simulator simulator, UDPPacketBuffer buffer, PacketType type) + { + Simulator = simulator; + Buffer = buffer; + this.Type = type; + } + } + + #endregion Structs + + #region Delegates + + /// The event subscribers, null of no subscribers + private EventHandler m_PacketSent; + + ///Raises the PacketSent Event + /// A PacketSentEventArgs object containing + /// the data sent from the simulator + protected virtual void OnPacketSent(PacketSentEventArgs e) + { + EventHandler handler = m_PacketSent; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_PacketSentLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler PacketSent + { + add { lock (m_PacketSentLock) { m_PacketSent += value; } } + remove { lock (m_PacketSentLock) { m_PacketSent -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_LoggedOut; + + ///Raises the LoggedOut Event + /// A LoggedOutEventArgs object containing + /// the data sent from the simulator + protected virtual void OnLoggedOut(LoggedOutEventArgs e) + { + EventHandler handler = m_LoggedOut; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_LoggedOutLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler LoggedOut + { + add { lock (m_LoggedOutLock) { m_LoggedOut += value; } } + remove { lock (m_LoggedOutLock) { m_LoggedOut -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_SimConnecting; + + ///Raises the SimConnecting Event + /// A SimConnectingEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSimConnecting(SimConnectingEventArgs e) + { + EventHandler handler = m_SimConnecting; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SimConnectingLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler SimConnecting + { + add { lock (m_SimConnectingLock) { m_SimConnecting += value; } } + remove { lock (m_SimConnectingLock) { m_SimConnecting -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_SimConnected; + + ///Raises the SimConnected Event + /// A SimConnectedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSimConnected(SimConnectedEventArgs e) + { + EventHandler handler = m_SimConnected; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SimConnectedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler SimConnected + { + add { lock (m_SimConnectedLock) { m_SimConnected += value; } } + remove { lock (m_SimConnectedLock) { m_SimConnected -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_SimDisconnected; + + ///Raises the SimDisconnected Event + /// A SimDisconnectedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSimDisconnected(SimDisconnectedEventArgs e) + { + EventHandler handler = m_SimDisconnected; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SimDisconnectedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler SimDisconnected + { + add { lock (m_SimDisconnectedLock) { m_SimDisconnected += value; } } + remove { lock (m_SimDisconnectedLock) { m_SimDisconnected -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_Disconnected; + + ///Raises the Disconnected Event + /// A DisconnectedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnDisconnected(DisconnectedEventArgs e) + { + EventHandler handler = m_Disconnected; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DisconnectedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler Disconnected + { + add { lock (m_DisconnectedLock) { m_Disconnected += value; } } + remove { lock (m_DisconnectedLock) { m_Disconnected -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_SimChanged; + + ///Raises the SimChanged Event + /// A SimChangedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSimChanged(SimChangedEventArgs e) + { + EventHandler handler = m_SimChanged; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SimChangedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler SimChanged + { + add { lock (m_SimChangedLock) { m_SimChanged += value; } } + remove { lock (m_SimChangedLock) { m_SimChanged -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_EventQueueRunning; + + ///Raises the EventQueueRunning Event + /// A EventQueueRunningEventArgs object containing + /// the data sent from the simulator + protected virtual void OnEventQueueRunning(EventQueueRunningEventArgs e) + { + EventHandler handler = m_EventQueueRunning; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EventQueueRunningLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler EventQueueRunning + { + add { lock (m_EventQueueRunningLock) { m_EventQueueRunning += value; } } + remove { lock (m_EventQueueRunningLock) { m_EventQueueRunning -= value; } } + } + + #endregion Delegates + + #region Properties + + /// Unique identifier associated with our connections to + /// simulators + public uint CircuitCode + { + get { return _CircuitCode; } + set { _CircuitCode = value; } + } + /// The simulator that the logged in avatar is currently + /// occupying + public Simulator CurrentSim + { + get { return _CurrentSim; } + set { _CurrentSim = value; } + } + /// Shows whether the network layer is logged in to the + /// grid or not + public bool Connected { get { return connected; } } + /// Number of packets in the incoming queue + public int InboxCount { get { return PacketInbox.Count; } } + /// Number of packets in the outgoing queue + public int OutboxCount { get { return PacketOutbox.Count; } } + + #endregion Properties + + /// All of the simulators we are currently connected to + public List Simulators = new List(); + + /// Handlers for incoming capability events + internal CapsEventDictionary CapsEvents; + /// Handlers for incoming packets + internal PacketEventDictionary PacketEvents; + /// Incoming packets that are awaiting handling + internal BlockingQueue PacketInbox = new BlockingQueue(Settings.PACKET_INBOX_SIZE); + /// Outgoing packets that are awaiting handling + internal BlockingQueue PacketOutbox = new BlockingQueue(Settings.PACKET_INBOX_SIZE); + + private GridClient Client; + private Timer DisconnectTimer; + private uint _CircuitCode; + private Simulator _CurrentSim = null; + private bool connected = false; + + /// + /// Default constructor + /// + /// Reference to the GridClient object + public NetworkManager(GridClient client) + { + Client = client; + + PacketEvents = new PacketEventDictionary(client); + CapsEvents = new CapsEventDictionary(client); + + // Register internal CAPS callbacks + RegisterEventCallback("EnableSimulator", new Caps.EventQueueCallback(EnableSimulatorHandler)); + + // Register the internal callbacks + RegisterCallback(PacketType.RegionHandshake, RegionHandshakeHandler); + RegisterCallback(PacketType.StartPingCheck, StartPingCheckHandler, false); + RegisterCallback(PacketType.DisableSimulator, DisableSimulatorHandler); + RegisterCallback(PacketType.KickUser, KickUserHandler); + RegisterCallback(PacketType.LogoutReply, LogoutReplyHandler); + RegisterCallback(PacketType.CompletePingCheck, CompletePingCheckHandler, false); + RegisterCallback(PacketType.SimStats, SimStatsHandler, false); + + // GLOBAL SETTING: Don't force Expect-100: Continue headers on HTTP POST calls + ServicePointManager.Expect100Continue = false; + } + + /// + /// Register an event handler for a packet. This is a low level event + /// interface and should only be used if you are doing something not + /// supported in the library + /// + /// Packet type to trigger events for + /// Callback to fire when a packet of this type + /// is received + public void RegisterCallback(PacketType type, EventHandler callback) + { + RegisterCallback(type, callback, true); + } + + /// + /// Register an event handler for a packet. This is a low level event + /// interface and should only be used if you are doing something not + /// supported in the library + /// + /// Packet type to trigger events for + /// Callback to fire when a packet of this type + /// is received + /// True if the callback should be ran + /// asynchronously. Only set this to false (synchronous for callbacks + /// that will always complete quickly) + /// If any callback for a packet type is marked as + /// asynchronous, all callbacks for that packet type will be fired + /// asynchronously + public void RegisterCallback(PacketType type, EventHandler callback, bool isAsync) + { + PacketEvents.RegisterEvent(type, callback, isAsync); + } + + /// + /// Unregister an event handler for a packet. This is a low level event + /// interface and should only be used if you are doing something not + /// supported in the library + /// + /// Packet type this callback is registered with + /// Callback to stop firing events for + public void UnregisterCallback(PacketType type, EventHandler callback) + { + PacketEvents.UnregisterEvent(type, callback); + } + + /// + /// Register a CAPS event handler. This is a low level event interface + /// and should only be used if you are doing something not supported in + /// the library + /// + /// Name of the CAPS event to register a handler for + /// Callback to fire when a CAPS event is received + public void RegisterEventCallback(string capsEvent, Caps.EventQueueCallback callback) + { + CapsEvents.RegisterEvent(capsEvent, callback); + } + + /// + /// Unregister a CAPS event handler. This is a low level event interface + /// and should only be used if you are doing something not supported in + /// the library + /// + /// Name of the CAPS event this callback is + /// registered with + /// Callback to stop firing events for + public void UnregisterEventCallback(string capsEvent, Caps.EventQueueCallback callback) + { + CapsEvents.UnregisterEvent(capsEvent, callback); + } + + /// + /// Send a packet to the simulator the avatar is currently occupying + /// + /// Packet to send + public void SendPacket(Packet packet) + { + // try CurrentSim, however directly after login this will + // be null, so if it is, we'll try to find the first simulator + // we're connected to in order to send the packet. + Simulator simulator = CurrentSim; + + if (simulator == null && Client.Network.Simulators.Count >= 1) + { + Logger.DebugLog("CurrentSim object was null, using first found connected simulator", Client); + simulator = Client.Network.Simulators[0]; + } + + if (simulator != null && simulator.Connected) + { + simulator.SendPacket(packet); + } + else + { + //throw new NotConnectedException("Packet received before simulator packet processing threads running, make certain you are completely logged in"); + Logger.Log("Packet received before simulator packet processing threads running, make certain you are completely logged in.", Helpers.LogLevel.Error); + } + } + + /// + /// Send a packet to a specified simulator + /// + /// Packet to send + /// Simulator to send the packet to + public void SendPacket(Packet packet, Simulator simulator) + { + if (simulator != null) + { + simulator.SendPacket(packet); + } + else + { + Logger.Log("Packet received before simulator packet processing threads running, make certain you are completely logged in", Helpers.LogLevel.Error); + } + } + + /// + /// Connect to a simulator + /// + /// IP address to connect to + /// Port to connect to + /// Handle for this simulator, to identify its + /// location in the grid + /// Whether to set CurrentSim to this new + /// connection, use this if the avatar is moving in to this simulator + /// URL of the capabilities server to use for + /// this sim connection + /// A Simulator object on success, otherwise null + public Simulator Connect(IPAddress ip, ushort port, ulong handle, bool setDefault, string seedcaps) + { + IPEndPoint endPoint = new IPEndPoint(ip, (int)port); + return Connect(endPoint, handle, setDefault, seedcaps); + } + + /// + /// Connect to a simulator + /// + /// IP address and port to connect to + /// Handle for this simulator, to identify its + /// location in the grid + /// Whether to set CurrentSim to this new + /// connection, use this if the avatar is moving in to this simulator + /// URL of the capabilities server to use for + /// this sim connection + /// A Simulator object on success, otherwise null + public Simulator Connect(IPEndPoint endPoint, ulong handle, bool setDefault, string seedcaps) + { + Simulator simulator = FindSimulator(endPoint); + + if (simulator == null) + { + // We're not tracking this sim, create a new Simulator object + simulator = new Simulator(Client, endPoint, handle); + + // Immediately add this simulator to the list of current sims. It will be removed if the + // connection fails + lock (Simulators) Simulators.Add(simulator); + } + + if (!simulator.Connected) + { + if (!connected) + { + // Mark that we are connecting/connected to the grid + // + connected = true; + + // Open the queues in case this is a reconnect and they were shut down + PacketInbox.Open(); + PacketOutbox.Open(); + + // Start the packet decoding thread + Thread decodeThread = new Thread(new ThreadStart(IncomingPacketHandler)); + decodeThread.Name = "Incoming UDP packet dispatcher"; + decodeThread.Start(); + + // Start the packet sending thread + Thread sendThread = new Thread(new ThreadStart(OutgoingPacketHandler)); + sendThread.Name = "Outgoing UDP packet dispatcher"; + sendThread.Start(); + } + + // raise the SimConnecting event and allow any event + // subscribers to cancel the connection + if (m_SimConnecting != null) + { + SimConnectingEventArgs args = new SimConnectingEventArgs(simulator); + OnSimConnecting(args); + + if (args.Cancel) + { + // Callback is requesting that we abort this connection + lock (Simulators) + { + Simulators.Remove(simulator); + } + return null; + } + } + + // Attempt to establish a connection to the simulator + if (simulator.Connect(setDefault)) + { + if (DisconnectTimer == null) + { + // Start a timer that checks if we've been disconnected + DisconnectTimer = new Timer(new TimerCallback(DisconnectTimer_Elapsed), null, + Client.Settings.SIMULATOR_TIMEOUT, Client.Settings.SIMULATOR_TIMEOUT); + } + + if (setDefault) + { + SetCurrentSim(simulator, seedcaps); + } + + // Raise the SimConnected event + if (m_SimConnected != null) + { + OnSimConnected(new SimConnectedEventArgs(simulator)); + } + + // If enabled, send an AgentThrottle packet to the server to increase our bandwidth + if (Client.Settings.SEND_AGENT_THROTTLE) + { + Client.Throttle.Set(simulator); + } + + return simulator; + } + else + { + // Connection failed, remove this simulator from our list and destroy it + lock (Simulators) + { + Simulators.Remove(simulator); + } + + return null; + } + } + else if (setDefault) + { + // Move in to this simulator + simulator.handshakeComplete = false; + simulator.UseCircuitCode(true); + Client.Self.CompleteAgentMovement(simulator); + + // We're already connected to this server, but need to set it to the default + SetCurrentSim(simulator, seedcaps); + + // Send an initial AgentUpdate to complete our movement in to the sim + if (Client.Settings.SEND_AGENT_UPDATES) + { + Client.Self.Movement.SendUpdate(true, simulator); + } + + return simulator; + } + else + { + // Already connected to this simulator and wasn't asked to set it as the default, + // just return a reference to the existing object + return simulator; + } + } + + /// + /// Initiate a blocking logout request. This will return when the logout + /// handshake has completed or when Settings.LOGOUT_TIMEOUT + /// has expired and the network layer is manually shut down + /// + public void Logout() + { + AutoResetEvent logoutEvent = new AutoResetEvent(false); + EventHandler callback = delegate(object sender, LoggedOutEventArgs e) { logoutEvent.Set(); }; + + LoggedOut += callback; + + // Send the packet requesting a clean logout + RequestLogout(); + + // Wait for a logout response. If the response is received, shutdown + // will be fired in the callback. Otherwise we fire it manually with + // a NetworkTimeout type + if (!logoutEvent.WaitOne(Client.Settings.LOGOUT_TIMEOUT, false)) + Shutdown(DisconnectType.NetworkTimeout); + + LoggedOut -= callback; + } + + /// + /// Initiate the logout process. Check if logout succeeded with the + /// OnLogoutReply event, and if this does not fire the + /// Shutdown() function needs to be manually called + /// + public void RequestLogout() + { + // No need to run the disconnect timer any more + if (DisconnectTimer != null) + { + DisconnectTimer.Dispose(); + DisconnectTimer = null; + } + + // This will catch a Logout when the client is not logged in + if (CurrentSim == null || !connected) + { + Logger.Log("Ignoring RequestLogout(), client is already logged out", Helpers.LogLevel.Warning, Client); + return; + } + + Logger.Log("Logging out", Helpers.LogLevel.Info, Client); + + // Send a logout request to the current sim + LogoutRequestPacket logout = new LogoutRequestPacket(); + logout.AgentData.AgentID = Client.Self.AgentID; + logout.AgentData.SessionID = Client.Self.SessionID; + SendPacket(logout); + } + + /// + /// Close a connection to the given simulator + /// + /// + /// + public void DisconnectSim(Simulator simulator, bool sendCloseCircuit) + { + if (simulator != null) + { + simulator.Disconnect(sendCloseCircuit); + + // Fire the SimDisconnected event if a handler is registered + if (m_SimDisconnected != null) + { + OnSimDisconnected(new SimDisconnectedEventArgs(simulator, DisconnectType.NetworkTimeout)); + } + + lock (Simulators) Simulators.Remove(simulator); + + if (Simulators.Count == 0) Shutdown(DisconnectType.SimShutdown); + } + else + { + Logger.Log("DisconnectSim() called with a null Simulator reference", Helpers.LogLevel.Warning, Client); + } + } + + + /// + /// Shutdown will disconnect all the sims except for the current sim + /// first, and then kill the connection to CurrentSim. This should only + /// be called if the logout process times out on RequestLogout + /// + /// Type of shutdown + public void Shutdown(DisconnectType type) + { + Shutdown(type, type.ToString()); + } + + /// + /// Shutdown will disconnect all the sims except for the current sim + /// first, and then kill the connection to CurrentSim. This should only + /// be called if the logout process times out on RequestLogout + /// + /// Type of shutdown + /// Shutdown message + public void Shutdown(DisconnectType type, string message) + { + Logger.Log("NetworkManager shutdown initiated", Helpers.LogLevel.Info, Client); + + // Send a CloseCircuit packet to simulators if we are initiating the disconnect + bool sendCloseCircuit = (type == DisconnectType.ClientInitiated || type == DisconnectType.NetworkTimeout); + + lock (Simulators) + { + // Disconnect all simulators except the current one + for (int i = 0; i < Simulators.Count; i++) + { + if (Simulators[i] != null && Simulators[i] != CurrentSim) + { + Simulators[i].Disconnect(sendCloseCircuit); + + // Fire the SimDisconnected event if a handler is registered + if (m_SimDisconnected != null) + { + OnSimDisconnected(new SimDisconnectedEventArgs(Simulators[i], type)); + } + } + } + + Simulators.Clear(); + } + + if (CurrentSim != null) + { + // Kill the connection to the curent simulator + CurrentSim.Disconnect(sendCloseCircuit); + + // Fire the SimDisconnected event if a handler is registered + if (m_SimDisconnected != null) + { + OnSimDisconnected(new SimDisconnectedEventArgs(CurrentSim, type)); + } + } + + // Clear out all of the packets that never had time to process + PacketInbox.Close(); + PacketOutbox.Close(); + + connected = false; + + // Fire the disconnected callback + if (m_Disconnected != null) + { + OnDisconnected(new DisconnectedEventArgs(type, message)); + } + } + + /// + /// Searches through the list of currently connected simulators to find + /// one attached to the given IPEndPoint + /// + /// IPEndPoint of the Simulator to search for + /// A Simulator reference on success, otherwise null + public Simulator FindSimulator(IPEndPoint endPoint) + { + lock (Simulators) + { + for (int i = 0; i < Simulators.Count; i++) + { + if (Simulators[i].IPEndPoint.Equals(endPoint)) + return Simulators[i]; + } + } + + return null; + } + + internal void RaisePacketSentEvent(byte[] data, int bytesSent, Simulator simulator) + { + if (m_PacketSent != null) + { + OnPacketSent(new PacketSentEventArgs(data, bytesSent, simulator)); + } + } + + /// + /// Fire an event when an event queue connects for capabilities + /// + /// Simulator the event queue is attached to + internal void RaiseConnectedEvent(Simulator simulator) + { + if (m_EventQueueRunning != null) + { + OnEventQueueRunning(new EventQueueRunningEventArgs(simulator)); + } + } + + private void OutgoingPacketHandler() + { + OutgoingPacket outgoingPacket = null; + Simulator simulator; + + // FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP! + System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); + + while (connected) + { + if (PacketOutbox.Dequeue(100, ref outgoingPacket)) + { + simulator = outgoingPacket.Simulator; + + // Very primitive rate limiting, keeps a fixed buffer of time between each packet + stopwatch.Stop(); + if (stopwatch.ElapsedMilliseconds < 10) + { + //Logger.DebugLog(String.Format("Rate limiting, last packet was {0}ms ago", ms)); + Thread.Sleep(10 - (int)stopwatch.ElapsedMilliseconds); + } + + simulator.SendPacketFinal(outgoingPacket); + stopwatch.Start(); + } + } + } + + private void IncomingPacketHandler() + { + IncomingPacket incomingPacket = new IncomingPacket(); + Packet packet = null; + Simulator simulator = null; + + while (connected) + { + // Reset packet to null for the check below + packet = null; + + if (PacketInbox.Dequeue(100, ref incomingPacket)) + { + packet = incomingPacket.Packet; + simulator = incomingPacket.Simulator; + + if (packet != null) + { + // Skip blacklisted packets + if (UDPBlacklist.Contains(packet.Type.ToString())) + { + Logger.Log(String.Format("Discarding Blacklisted packet {0} from {1}", + packet.Type, simulator.IPEndPoint), Helpers.LogLevel.Warning); + return; + } + + // Fire the callback(s), if any + PacketEvents.RaiseEvent(packet.Type, packet, simulator); + } + } + } + } + + private void SetCurrentSim(Simulator simulator, string seedcaps) + { + if (simulator != CurrentSim) + { + Simulator oldSim = CurrentSim; + lock (Simulators) CurrentSim = simulator; // CurrentSim is synchronized against Simulators + + simulator.SetSeedCaps(seedcaps); + + // If the current simulator changed fire the callback + if (m_SimChanged != null && simulator != oldSim) + { + OnSimChanged(new SimChangedEventArgs(oldSim)); + } + } + } + + #region Timers + + private void DisconnectTimer_Elapsed(object obj) + { + if (!connected || CurrentSim == null) + { + if (DisconnectTimer != null) + { + DisconnectTimer.Dispose(); + DisconnectTimer = null; + } + connected = false; + } + else if (CurrentSim.DisconnectCandidate) + { + // The currently occupied simulator hasn't sent us any traffic in a while, shutdown + Logger.Log("Network timeout for the current simulator (" + + CurrentSim.ToString() + "), logging out", Helpers.LogLevel.Warning, Client); + + if (DisconnectTimer != null) + { + DisconnectTimer.Dispose(); + DisconnectTimer = null; + } + + connected = false; + + // Shutdown the network layer + Shutdown(DisconnectType.NetworkTimeout); + } + else + { + // Mark the current simulator as potentially disconnected each time this timer fires. + // If the timer is fired again before any packets are received, an actual disconnect + // sequence will be triggered + CurrentSim.DisconnectCandidate = true; + } + } + + #endregion Timers + + #region Packet Callbacks + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void LogoutReplyHandler(object sender, PacketReceivedEventArgs e) + { + LogoutReplyPacket logout = (LogoutReplyPacket)e.Packet; + + if ((logout.AgentData.SessionID == Client.Self.SessionID) && (logout.AgentData.AgentID == Client.Self.AgentID)) + { + Logger.DebugLog("Logout reply received", Client); + + // Deal with callbacks, if any + if (m_LoggedOut != null) + { + List itemIDs = new List(); + + foreach (LogoutReplyPacket.InventoryDataBlock InventoryData in logout.InventoryData) + { + itemIDs.Add(InventoryData.ItemID); + } + + OnLoggedOut(new LoggedOutEventArgs(itemIDs)); + } + + // If we are receiving a LogoutReply packet assume this is a client initiated shutdown + Shutdown(DisconnectType.ClientInitiated); + } + else + { + Logger.Log("Invalid Session or Agent ID received in Logout Reply... ignoring", Helpers.LogLevel.Warning, Client); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void StartPingCheckHandler(object sender, PacketReceivedEventArgs e) + { + StartPingCheckPacket incomingPing = (StartPingCheckPacket)e.Packet; + CompletePingCheckPacket ping = new CompletePingCheckPacket(); + ping.PingID.PingID = incomingPing.PingID.PingID; + ping.Header.Reliable = false; + // TODO: We can use OldestUnacked to correct transmission errors + // I don't think that's right. As far as I can tell, the Viewer + // only uses this to prune its duplicate-checking buffer. -bushing + + SendPacket(ping, e.Simulator); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void CompletePingCheckHandler(object sender, PacketReceivedEventArgs e) + { + CompletePingCheckPacket pong = (CompletePingCheckPacket)e.Packet; + //String retval = "Pong2: " + (Environment.TickCount - e.Simulator.Stats.LastPingSent); + //if ((pong.PingID.PingID - e.Simulator.Stats.LastPingID + 1) != 0) + // retval += " (gap of " + (pong.PingID.PingID - e.Simulator.Stats.LastPingID + 1) + ")"; + + e.Simulator.Stats.LastLag = Environment.TickCount - e.Simulator.Stats.LastPingSent; + e.Simulator.Stats.ReceivedPongs++; + // Client.Log(retval, Helpers.LogLevel.Info); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void SimStatsHandler(object sender, PacketReceivedEventArgs e) + { + if (!Client.Settings.ENABLE_SIMSTATS) + { + return; + } + SimStatsPacket stats = (SimStatsPacket)e.Packet; + for (int i = 0; i < stats.Stat.Length; i++) + { + SimStatsPacket.StatBlock s = stats.Stat[i]; + switch (s.StatID) + { + case 0: + e.Simulator.Stats.Dilation = s.StatValue; + break; + case 1: + e.Simulator.Stats.FPS = Convert.ToInt32(s.StatValue); + break; + case 2: + e.Simulator.Stats.PhysicsFPS = s.StatValue; + break; + case 3: + e.Simulator.Stats.AgentUpdates = s.StatValue; + break; + case 4: + e.Simulator.Stats.FrameTime = s.StatValue; + break; + case 5: + e.Simulator.Stats.NetTime = s.StatValue; + break; + case 6: + e.Simulator.Stats.OtherTime = s.StatValue; + break; + case 7: + e.Simulator.Stats.PhysicsTime = s.StatValue; + break; + case 8: + e.Simulator.Stats.AgentTime = s.StatValue; + break; + case 9: + e.Simulator.Stats.ImageTime = s.StatValue; + break; + case 10: + e.Simulator.Stats.ScriptTime = s.StatValue; + break; + case 11: + e.Simulator.Stats.Objects = Convert.ToInt32(s.StatValue); + break; + case 12: + e.Simulator.Stats.ScriptedObjects = Convert.ToInt32(s.StatValue); + break; + case 13: + e.Simulator.Stats.Agents = Convert.ToInt32(s.StatValue); + break; + case 14: + e.Simulator.Stats.ChildAgents = Convert.ToInt32(s.StatValue); + break; + case 15: + e.Simulator.Stats.ActiveScripts = Convert.ToInt32(s.StatValue); + break; + case 16: + e.Simulator.Stats.LSLIPS = Convert.ToInt32(s.StatValue); + break; + case 17: + e.Simulator.Stats.INPPS = Convert.ToInt32(s.StatValue); + break; + case 18: + e.Simulator.Stats.OUTPPS = Convert.ToInt32(s.StatValue); + break; + case 19: + e.Simulator.Stats.PendingDownloads = Convert.ToInt32(s.StatValue); + break; + case 20: + e.Simulator.Stats.PendingUploads = Convert.ToInt32(s.StatValue); + break; + case 21: + e.Simulator.Stats.VirtualSize = Convert.ToInt32(s.StatValue); + break; + case 22: + e.Simulator.Stats.ResidentSize = Convert.ToInt32(s.StatValue); + break; + case 23: + e.Simulator.Stats.PendingLocalUploads = Convert.ToInt32(s.StatValue); + break; + case 24: + e.Simulator.Stats.UnackedBytes = Convert.ToInt32(s.StatValue); + break; + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void RegionHandshakeHandler(object sender, PacketReceivedEventArgs e) + { + RegionHandshakePacket handshake = (RegionHandshakePacket)e.Packet; + Simulator simulator = e.Simulator; + e.Simulator.ID = handshake.RegionInfo.CacheID; + + simulator.IsEstateManager = handshake.RegionInfo.IsEstateManager; + simulator.Name = Utils.BytesToString(handshake.RegionInfo.SimName); + simulator.SimOwner = handshake.RegionInfo.SimOwner; + simulator.TerrainBase0 = handshake.RegionInfo.TerrainBase0; + simulator.TerrainBase1 = handshake.RegionInfo.TerrainBase1; + simulator.TerrainBase2 = handshake.RegionInfo.TerrainBase2; + simulator.TerrainBase3 = handshake.RegionInfo.TerrainBase3; + simulator.TerrainDetail0 = handshake.RegionInfo.TerrainDetail0; + simulator.TerrainDetail1 = handshake.RegionInfo.TerrainDetail1; + simulator.TerrainDetail2 = handshake.RegionInfo.TerrainDetail2; + simulator.TerrainDetail3 = handshake.RegionInfo.TerrainDetail3; + simulator.TerrainHeightRange00 = handshake.RegionInfo.TerrainHeightRange00; + simulator.TerrainHeightRange01 = handshake.RegionInfo.TerrainHeightRange01; + simulator.TerrainHeightRange10 = handshake.RegionInfo.TerrainHeightRange10; + simulator.TerrainHeightRange11 = handshake.RegionInfo.TerrainHeightRange11; + simulator.TerrainStartHeight00 = handshake.RegionInfo.TerrainStartHeight00; + simulator.TerrainStartHeight01 = handshake.RegionInfo.TerrainStartHeight01; + simulator.TerrainStartHeight10 = handshake.RegionInfo.TerrainStartHeight10; + simulator.TerrainStartHeight11 = handshake.RegionInfo.TerrainStartHeight11; + simulator.WaterHeight = handshake.RegionInfo.WaterHeight; + simulator.Flags = (RegionFlags)handshake.RegionInfo.RegionFlags; + simulator.BillableFactor = handshake.RegionInfo.BillableFactor; + simulator.Access = (SimAccess)handshake.RegionInfo.SimAccess; + + simulator.RegionID = handshake.RegionInfo2.RegionID; + simulator.ColoLocation = Utils.BytesToString(handshake.RegionInfo3.ColoName); + simulator.CPUClass = handshake.RegionInfo3.CPUClassID; + simulator.CPURatio = handshake.RegionInfo3.CPURatio; + simulator.ProductName = Utils.BytesToString(handshake.RegionInfo3.ProductName); + simulator.ProductSku = Utils.BytesToString(handshake.RegionInfo3.ProductSKU); + + if (handshake.RegionInfo4 != null && handshake.RegionInfo4.Length > 0) + { + simulator.Protocols = (RegionProtocols)handshake.RegionInfo4[0].RegionProtocols; + // Yes, overwrite region flags if we have extended version of them + simulator.Flags = (RegionFlags)handshake.RegionInfo4[0].RegionFlagsExtended; + } + + // Send a RegionHandshakeReply + RegionHandshakeReplyPacket reply = new RegionHandshakeReplyPacket(); + reply.AgentData.AgentID = Client.Self.AgentID; + reply.AgentData.SessionID = Client.Self.SessionID; + reply.RegionInfo.Flags = (uint)RegionProtocols.SelfAppearanceSupport; + SendPacket(reply, simulator); + + // We're officially connected to this sim + simulator.connected = true; + simulator.handshakeComplete = true; + simulator.ConnectedEvent.Set(); + } + + protected void EnableSimulatorHandler(string capsKey, IMessage message, Simulator simulator) + { + if (!Client.Settings.MULTIPLE_SIMS) return; + + EnableSimulatorMessage msg = (EnableSimulatorMessage)message; + + for (int i = 0; i < msg.Simulators.Length; i++) + { + IPAddress ip = msg.Simulators[i].IP; + ushort port = (ushort)msg.Simulators[i].Port; + ulong handle = msg.Simulators[i].RegionHandle; + + IPEndPoint endPoint = new IPEndPoint(ip, port); + + if (FindSimulator(endPoint) != null) return; + + if (Connect(ip, port, handle, false, null) == null) + { + Logger.Log("Unabled to connect to new sim " + ip + ":" + port, + Helpers.LogLevel.Error, Client); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void DisableSimulatorHandler(object sender, PacketReceivedEventArgs e) + { + DisconnectSim(e.Simulator, false); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void KickUserHandler(object sender, PacketReceivedEventArgs e) + { + string message = Utils.BytesToString(((KickUserPacket)e.Packet).UserInfo.Reason); + + // Shutdown the network layer + Shutdown(DisconnectType.ServerInitiated, message); + } + + #endregion Packet Callbacks + } + #region EventArgs + + public class PacketReceivedEventArgs : EventArgs + { + private readonly Packet m_Packet; + private readonly Simulator m_Simulator; + + public Packet Packet { get { return m_Packet; } } + public Simulator Simulator { get { return m_Simulator; } } + + public PacketReceivedEventArgs(Packet packet, Simulator simulator) + { + this.m_Packet = packet; + this.m_Simulator = simulator; + } + } + + public class LoggedOutEventArgs : EventArgs + { + private readonly List m_InventoryItems; + public List InventoryItems; + + public LoggedOutEventArgs(List inventoryItems) + { + this.m_InventoryItems = inventoryItems; + } + } + + public class PacketSentEventArgs : EventArgs + { + private readonly byte[] m_Data; + private readonly int m_SentBytes; + private readonly Simulator m_Simulator; + + public byte[] Data { get { return m_Data; } } + public int SentBytes { get { return m_SentBytes; } } + public Simulator Simulator { get { return m_Simulator; } } + + public PacketSentEventArgs(byte[] data, int bytesSent, Simulator simulator) + { + this.m_Data = data; + this.m_SentBytes = bytesSent; + this.m_Simulator = simulator; + } + } + + public class SimConnectingEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private bool m_Cancel; + + public Simulator Simulator { get { return m_Simulator; } } + + public bool Cancel + { + get { return m_Cancel; } + set { m_Cancel = value; } + } + + public SimConnectingEventArgs(Simulator simulator) + { + this.m_Simulator = simulator; + this.m_Cancel = false; + } + } + + public class SimConnectedEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + public Simulator Simulator { get { return m_Simulator; } } + + public SimConnectedEventArgs(Simulator simulator) + { + this.m_Simulator = simulator; + } + } + + public class SimDisconnectedEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly NetworkManager.DisconnectType m_Reason; + + public Simulator Simulator { get { return m_Simulator; } } + public NetworkManager.DisconnectType Reason { get { return m_Reason; } } + + public SimDisconnectedEventArgs(Simulator simulator, NetworkManager.DisconnectType reason) + { + this.m_Simulator = simulator; + this.m_Reason = reason; + } + } + + public class DisconnectedEventArgs : EventArgs + { + private readonly NetworkManager.DisconnectType m_Reason; + private readonly String m_Message; + + public NetworkManager.DisconnectType Reason { get { return m_Reason; } } + public String Message { get { return m_Message; } } + + public DisconnectedEventArgs(NetworkManager.DisconnectType reason, String message) + { + this.m_Reason = reason; + this.m_Message = message; + } + } + + public class SimChangedEventArgs : EventArgs + { + private readonly Simulator m_PreviousSimulator; + + public Simulator PreviousSimulator { get { return m_PreviousSimulator; } } + + public SimChangedEventArgs(Simulator previousSimulator) + { + this.m_PreviousSimulator = previousSimulator; + } + } + + public class EventQueueRunningEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + + public Simulator Simulator { get { return m_Simulator; } } + + public EventQueueRunningEventArgs(Simulator simulator) + { + this.m_Simulator = simulator; + } + } + #endregion +} diff --git a/OpenMetaverse/ObjectManager.cs b/OpenMetaverse/ObjectManager.cs new file mode 100644 index 0000000..a76b803 --- /dev/null +++ b/OpenMetaverse/ObjectManager.cs @@ -0,0 +1,3814 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse.Packets; +using OpenMetaverse.Http; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// + /// + public enum ReportType : uint + { + /// No report + None = 0, + /// Unknown report type + Unknown = 1, + /// Bug report + Bug = 2, + /// Complaint report + Complaint = 3, + /// Customer service report + CustomerServiceRequest = 4 + } + + /// + /// Bitflag field for ObjectUpdateCompressed data blocks, describing + /// which options are present for each object + /// + [Flags] + public enum CompressedFlags : uint + { + None = 0x00, + /// Unknown + ScratchPad = 0x01, + /// Whether the object has a TreeSpecies + Tree = 0x02, + /// Whether the object has floating text ala llSetText + HasText = 0x04, + /// Whether the object has an active particle system + HasParticles = 0x08, + /// Whether the object has sound attached to it + HasSound = 0x10, + /// Whether the object is attached to a root object or not + HasParent = 0x20, + /// Whether the object has texture animation settings + TextureAnimation = 0x40, + /// Whether the object has an angular velocity + HasAngularVelocity = 0x80, + /// Whether the object has a name value pairs string + HasNameValues = 0x100, + /// Whether the object has a Media URL set + MediaURL = 0x200 + } + + /// + /// Specific Flags for MultipleObjectUpdate requests + /// + [Flags] + public enum UpdateType : uint + { + /// None + None = 0x00, + /// Change position of prims + Position = 0x01, + /// Change rotation of prims + Rotation = 0x02, + /// Change size of prims + Scale = 0x04, + /// Perform operation on link set + Linked = 0x08, + /// Scale prims uniformly, same as selecing ctrl+shift in the + /// viewer. Used in conjunction with Scale + Uniform = 0x10 + } + + /// + /// Special values in PayPriceReply. If the price is not one of these + /// literal value of the price should be use + /// + public enum PayPriceType : int + { + /// + /// Indicates that this pay option should be hidden + /// + Hide = -1, + + /// + /// Indicates that this pay option should have the default value + /// + Default = -2 + } + + #endregion Enums + + #region Structs + + /// + /// Contains the variables sent in an object update packet for objects. + /// Used to track position and movement of prims and avatars + /// + public struct ObjectMovementUpdate + { + /// + public bool Avatar; + /// + public Vector4 CollisionPlane; + /// + public byte State; + /// + public uint LocalID; + /// + public Vector3 Position; + /// + public Vector3 Velocity; + /// + public Vector3 Acceleration; + /// + public Quaternion Rotation; + /// + public Vector3 AngularVelocity; + /// + public Primitive.TextureEntry Textures; + } + + #endregion Structs + + /// + /// Handles all network traffic related to prims and avatar positions and + /// movement. + /// + public class ObjectManager + { + public const float HAVOK_TIMESTEP = 1.0f / 45.0f; + + #region Delegates + + #region ObjectUpdate event + /// The event subscribers, null of no subscribers + private EventHandler m_ObjectUpdate; + + /// Thread sync lock object + private readonly object m_ObjectUpdateLock = new object(); + + /// Raised when the simulator sends us data containing + /// A , Foliage or Attachment + /// + /// + public event EventHandler ObjectUpdate + { + add { lock (m_ObjectUpdateLock) { m_ObjectUpdate += value; } } + remove { lock (m_ObjectUpdateLock) { m_ObjectUpdate -= value; } } + } + #endregion ObjectUpdate event + + #region ObjectProperties event + /// The event subscribers, null of no subscribers + private EventHandler m_ObjectProperties; + + ///Raises the ObjectProperties Event + /// A ObjectPropertiesEventArgs object containing + /// the data sent from the simulator + protected virtual void OnObjectProperties(ObjectPropertiesEventArgs e) + { + EventHandler handler = m_ObjectProperties; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ObjectPropertiesLock = new object(); + + /// Raised when the simulator sends us data containing + /// additional information + /// + /// + public event EventHandler ObjectProperties + { + add { lock (m_ObjectPropertiesLock) { m_ObjectProperties += value; } } + remove { lock (m_ObjectPropertiesLock) { m_ObjectProperties -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_ObjectPropertiesUpdated; + + ///Raises the ObjectPropertiesUpdated Event + /// A ObjectPropertiesUpdatedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnObjectPropertiesUpdated(ObjectPropertiesUpdatedEventArgs e) + { + EventHandler handler = m_ObjectPropertiesUpdated; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ObjectPropertiesUpdatedLock = new object(); + + /// Raised when the simulator sends us data containing + /// Primitive.ObjectProperties for an object we are currently tracking + public event EventHandler ObjectPropertiesUpdated + { + add { lock (m_ObjectPropertiesUpdatedLock) { m_ObjectPropertiesUpdated += value; } } + remove { lock (m_ObjectPropertiesUpdatedLock) { m_ObjectPropertiesUpdated -= value; } } + } + #endregion ObjectProperties event + + #region ObjectPropertiesFamily event + /// The event subscribers, null of no subscribers + private EventHandler m_ObjectPropertiesFamily; + + ///Raises the ObjectPropertiesFamily Event + /// A ObjectPropertiesFamilyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnObjectPropertiesFamily(ObjectPropertiesFamilyEventArgs e) + { + EventHandler handler = m_ObjectPropertiesFamily; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ObjectPropertiesFamilyLock = new object(); + + /// Raised when the simulator sends us data containing + /// additional and details + /// + public event EventHandler ObjectPropertiesFamily + { + add { lock (m_ObjectPropertiesFamilyLock) { m_ObjectPropertiesFamily += value; } } + remove { lock (m_ObjectPropertiesFamilyLock) { m_ObjectPropertiesFamily -= value; } } + } + #endregion ObjectPropertiesFamily + + #region AvatarUpdate event + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarUpdate; + private EventHandler m_ParticleUpdate; + + ///Raises the AvatarUpdate Event + /// A AvatarUpdateEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarUpdate(AvatarUpdateEventArgs e) + { + EventHandler handler = m_AvatarUpdate; + if (handler != null) + handler(this, e); + } + /// + /// Raises the ParticleUpdate Event + /// + /// A ParticleUpdateEventArgs object containing + /// the data sent from the simulator + protected virtual void OnParticleUpdate(ParticleUpdateEventArgs e) { + EventHandler handler = m_ParticleUpdate; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarUpdateLock = new object(); + + private readonly object m_ParticleUpdateLock = new object(); + + /// Raised when the simulator sends us data containing + /// updated information for an + public event EventHandler AvatarUpdate + { + add { lock (m_AvatarUpdateLock) { m_AvatarUpdate += value; } } + remove { lock (m_AvatarUpdateLock) { m_AvatarUpdate -= value; } } + } + #endregion AvatarUpdate event + + #region TerseObjectUpdate event + public event EventHandler ParticleUpdate { + add { lock (m_ParticleUpdateLock) { m_ParticleUpdate += value; } } + remove { lock (m_ParticleUpdateLock) { m_ParticleUpdate -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_TerseObjectUpdate; + + /// Thread sync lock object + private readonly object m_TerseObjectUpdateLock = new object(); + + /// Raised when the simulator sends us data containing + /// and movement changes + public event EventHandler TerseObjectUpdate + { + add { lock (m_TerseObjectUpdateLock) { m_TerseObjectUpdate += value; } } + remove { lock (m_TerseObjectUpdateLock) { m_TerseObjectUpdate -= value; } } + } + #endregion TerseObjectUpdate event + + #region ObjectDataBlockUpdate event + /// The event subscribers, null of no subscribers + private EventHandler m_ObjectDataBlockUpdate; + + ///Raises the ObjectDataBlockUpdate Event + /// A ObjectDataBlockUpdateEventArgs object containing + /// the data sent from the simulator + protected virtual void OnObjectDataBlockUpdate(ObjectDataBlockUpdateEventArgs e) + { + EventHandler handler = m_ObjectDataBlockUpdate; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ObjectDataBlockUpdateLock = new object(); + + /// Raised when the simulator sends us data containing + /// updates to an Objects DataBlock + public event EventHandler ObjectDataBlockUpdate + { + add { lock (m_ObjectDataBlockUpdateLock) { m_ObjectDataBlockUpdate += value; } } + remove { lock (m_ObjectDataBlockUpdateLock) { m_ObjectDataBlockUpdate -= value; } } + } + #endregion ObjectDataBlockUpdate event + + #region KillObject event + /// The event subscribers, null of no subscribers + private EventHandler m_KillObject; + + ///Raises the KillObject Event + /// A KillObjectEventArgs object containing + /// the data sent from the simulator + protected virtual void OnKillObject(KillObjectEventArgs e) + { + EventHandler handler = m_KillObject; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_KillObjectLock = new object(); + + /// Raised when the simulator informs us an + /// or is no longer within view + public event EventHandler KillObject + { + add { lock (m_KillObjectLock) { m_KillObject += value; } } + remove { lock (m_KillObjectLock) { m_KillObject -= value; } } + } + #endregion KillObject event + + #region KillObjects event + /// The event subscribers, null of no subscribers + private EventHandler m_KillObjects; + + ///Raises the KillObjects Event + /// A KillObjectsEventArgs object containing + /// the data sent from the simulator + protected virtual void OnKillObjects(KillObjectsEventArgs e) + { + EventHandler handler = m_KillObjects; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_KillObjectsLock = new object(); + + /// Raised when the simulator informs us when a group of + /// or is no longer within view + public event EventHandler KillObjects + { + add { lock (m_KillObjectsLock) { m_KillObjects += value; } } + remove { lock (m_KillObjectsLock) { m_KillObjects -= value; } } + } + #endregion KillObjects event + + #region AvatarSitChanged event + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarSitChanged; + + ///Raises the AvatarSitChanged Event + /// A AvatarSitChangedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarSitChanged(AvatarSitChangedEventArgs e) + { + EventHandler handler = m_AvatarSitChanged; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarSitChangedLock = new object(); + + /// Raised when the simulator sends us data containing + /// updated sit information for our + public event EventHandler AvatarSitChanged + { + add { lock (m_AvatarSitChangedLock) { m_AvatarSitChanged += value; } } + remove { lock (m_AvatarSitChangedLock) { m_AvatarSitChanged -= value; } } + } + #endregion AvatarSitChanged event + + #region PayPriceReply event + /// The event subscribers, null of no subscribers + private EventHandler m_PayPriceReply; + + ///Raises the PayPriceReply Event + /// A PayPriceReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnPayPriceReply(PayPriceReplyEventArgs e) + { + EventHandler handler = m_PayPriceReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_PayPriceReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// purchase price information for a + public event EventHandler PayPriceReply + { + add { lock (m_PayPriceReplyLock) { m_PayPriceReply += value; } } + remove { lock (m_PayPriceReplyLock) { m_PayPriceReply -= value; } } + } + #endregion PayPriceReply + + #region PhysicsProperties event + /// + /// Callback for getting object media data via CAP + /// + /// Indicates if the operation was succesfull + /// Object media version string + /// Array indexed on prim face of media entry data + public delegate void ObjectMediaCallback(bool success, string version, MediaEntry[] faceMedia); + + /// The event subscribers, null of no subscribers + private EventHandler m_PhysicsProperties; + + ///Raises the PhysicsProperties Event + /// A PhysicsPropertiesEventArgs object containing + /// the data sent from the simulator + protected virtual void OnPhysicsProperties(PhysicsPropertiesEventArgs e) + { + EventHandler handler = m_PhysicsProperties; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_PhysicsPropertiesLock = new object(); + + /// Raised when the simulator sends us data containing + /// additional information + /// + /// + public event EventHandler PhysicsProperties + { + add { lock (m_PhysicsPropertiesLock) { m_PhysicsProperties += value; } } + remove { lock (m_PhysicsPropertiesLock) { m_PhysicsProperties -= value; } } + } + #endregion PhysicsProperties event + + #endregion Delegates + + /// Reference to the GridClient object + protected GridClient Client; + /// Does periodic dead reckoning calculation to convert + /// velocity and acceleration to new positions for objects + private Timer InterpolationTimer; + + /// + /// Construct a new instance of the ObjectManager class + /// + /// A reference to the instance + public ObjectManager(GridClient client) + { + Client = client; + + Client.Network.RegisterCallback(PacketType.ObjectUpdate, ObjectUpdateHandler, false); + Client.Network.RegisterCallback(PacketType.ImprovedTerseObjectUpdate, ImprovedTerseObjectUpdateHandler, false); + Client.Network.RegisterCallback(PacketType.ObjectUpdateCompressed, ObjectUpdateCompressedHandler); + Client.Network.RegisterCallback(PacketType.ObjectUpdateCached, ObjectUpdateCachedHandler); + Client.Network.RegisterCallback(PacketType.KillObject, KillObjectHandler); + Client.Network.RegisterCallback(PacketType.ObjectPropertiesFamily, ObjectPropertiesFamilyHandler); + Client.Network.RegisterCallback(PacketType.ObjectProperties, ObjectPropertiesHandler); + Client.Network.RegisterCallback(PacketType.PayPriceReply, PayPriceReplyHandler); + Client.Network.RegisterEventCallback("ObjectPhysicsProperties", ObjectPhysicsPropertiesHandler); + } + + #region Internal event handlers + + private void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message) + { + if (InterpolationTimer != null) + { + InterpolationTimer.Dispose(); + InterpolationTimer = null; + } + } + + private void Network_OnConnected(object sender) + { + if (Client.Settings.USE_INTERPOLATION_TIMER) + { + InterpolationTimer = new Timer(InterpolationTimer_Elapsed, null, Settings.INTERPOLATION_INTERVAL, Timeout.Infinite); + } + } + + #endregion Internal event handlers + + #region Public Methods + + /// + /// Request information for a single object from a + /// you are currently connected to + /// + /// The the object is located + /// The Local ID of the object + public void RequestObject(Simulator simulator, uint localID) + { + RequestMultipleObjectsPacket request = new RequestMultipleObjectsPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.ObjectData = new RequestMultipleObjectsPacket.ObjectDataBlock[1]; + request.ObjectData[0] = new RequestMultipleObjectsPacket.ObjectDataBlock(); + request.ObjectData[0].ID = localID; + request.ObjectData[0].CacheMissType = 0; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Request information for multiple objects contained in + /// the same simulator + /// + /// The the objects are located + /// An array containing the Local IDs of the objects + public void RequestObjects(Simulator simulator, List localIDs) + { + RequestMultipleObjectsPacket request = new RequestMultipleObjectsPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.ObjectData = new RequestMultipleObjectsPacket.ObjectDataBlock[localIDs.Count]; + + for (int i = 0; i < localIDs.Count; i++) + { + request.ObjectData[i] = new RequestMultipleObjectsPacket.ObjectDataBlock(); + request.ObjectData[i].ID = localIDs[i]; + request.ObjectData[i].CacheMissType = 0; + } + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Attempt to purchase an original object, a copy, or the contents of + /// an object + /// + /// The the object is located + /// The Local ID of the object + /// Whether the original, a copy, or the object + /// contents are on sale. This is used for verification, if the this + /// sale type is not valid for the object the purchase will fail + /// Price of the object. This is used for + /// verification, if it does not match the actual price the purchase + /// will fail + /// Group ID that will be associated with the new + /// purchase + /// Inventory folder UUID where the object or objects + /// purchased should be placed + /// + /// + /// BuyObject(Client.Network.CurrentSim, 500, SaleType.Copy, + /// 100, UUID.Zero, Client.Self.InventoryRootFolderUUID); + /// + /// + public void BuyObject(Simulator simulator, uint localID, SaleType saleType, int price, UUID groupID, + UUID categoryID) + { + ObjectBuyPacket buy = new ObjectBuyPacket(); + + buy.AgentData.AgentID = Client.Self.AgentID; + buy.AgentData.SessionID = Client.Self.SessionID; + buy.AgentData.GroupID = groupID; + buy.AgentData.CategoryID = categoryID; + + buy.ObjectData = new ObjectBuyPacket.ObjectDataBlock[1]; + buy.ObjectData[0] = new ObjectBuyPacket.ObjectDataBlock(); + buy.ObjectData[0].ObjectLocalID = localID; + buy.ObjectData[0].SaleType = (byte)saleType; + buy.ObjectData[0].SalePrice = price; + + Client.Network.SendPacket(buy, simulator); + } + + /// + /// Request prices that should be displayed in pay dialog. This will triggger the simulator + /// to send us back a PayPriceReply which can be handled by OnPayPriceReply event + /// + /// The the object is located + /// The ID of the object + /// The result is raised in the event + public void RequestPayPrice(Simulator simulator, UUID objectID) + { + RequestPayPricePacket payPriceRequest = new RequestPayPricePacket(); + + payPriceRequest.ObjectData = new RequestPayPricePacket.ObjectDataBlock(); + payPriceRequest.ObjectData.ObjectID = objectID; + + Client.Network.SendPacket(payPriceRequest, simulator); + } + + /// + /// Select a single object. This will cause the to send us + /// an which will raise the event + /// + /// The the object is located + /// The Local ID of the object + /// + public void SelectObject(Simulator simulator, uint localID) + { + SelectObject(simulator, localID, true); + } + + /// + /// Select a single object. This will cause the to send us + /// an which will raise the event + /// + /// The the object is located + /// The Local ID of the object + /// if true, a call to is + /// made immediately following the request + /// + public void SelectObject(Simulator simulator, uint localID, bool automaticDeselect) + { + ObjectSelectPacket select = new ObjectSelectPacket(); + + select.AgentData.AgentID = Client.Self.AgentID; + select.AgentData.SessionID = Client.Self.SessionID; + + select.ObjectData = new ObjectSelectPacket.ObjectDataBlock[1]; + select.ObjectData[0] = new ObjectSelectPacket.ObjectDataBlock(); + select.ObjectData[0].ObjectLocalID = localID; + + Client.Network.SendPacket(select, simulator); + + if (automaticDeselect) + { + DeselectObject(simulator, localID); + } + } + + /// + /// Select multiple objects. This will cause the to send us + /// an which will raise the event + /// + /// The the objects are located + /// An array containing the Local IDs of the objects + /// Should objects be deselected immediately after selection + /// + public void SelectObjects(Simulator simulator, uint[] localIDs, bool automaticDeselect) + { + ObjectSelectPacket select = new ObjectSelectPacket(); + + select.AgentData.AgentID = Client.Self.AgentID; + select.AgentData.SessionID = Client.Self.SessionID; + + select.ObjectData = new ObjectSelectPacket.ObjectDataBlock[localIDs.Length]; + + for (int i = 0; i < localIDs.Length; i++) + { + select.ObjectData[i] = new ObjectSelectPacket.ObjectDataBlock(); + select.ObjectData[i].ObjectLocalID = localIDs[i]; + } + + Client.Network.SendPacket(select, simulator); + + if (automaticDeselect) + { + DeselectObjects(simulator, localIDs); + } + } + + /// + /// Select multiple objects. This will cause the to send us + /// an which will raise the event + /// + /// The the objects are located + /// An array containing the Local IDs of the objects + /// + public void SelectObjects(Simulator simulator, uint[] localIDs) + { + SelectObjects(simulator, localIDs, true); + } + + /// + /// Update the properties of an object + /// + /// The the object is located + /// The Local ID of the object + /// true to turn the objects physical property on + /// true to turn the objects temporary property on + /// true to turn the objects phantom property on + /// true to turn the objects cast shadows property on + public void SetFlags(Simulator simulator, uint localID, bool physical, bool temporary, bool phantom, bool castsShadow) + { + SetFlags(simulator, localID, physical, temporary, phantom, castsShadow, PhysicsShapeType.Prim, 1000f, 0.6f, 0.5f, 1f); + } + + /// + /// Update the properties of an object + /// + /// The the object is located + /// The Local ID of the object + /// true to turn the objects physical property on + /// true to turn the objects temporary property on + /// true to turn the objects phantom property on + /// true to turn the objects cast shadows property on + /// Type of the represetnation prim will have in the physics engine + /// Density - normal value 1000 + /// Friction - normal value 0.6 + /// Restitution - standard value 0.5 + /// Gravity multiplier - standar value 1.0 + public void SetFlags(Simulator simulator, uint localID, bool physical, bool temporary, bool phantom, bool castsShadow, + PhysicsShapeType physicsType, float density, float friction, float restitution, float gravityMultiplier) + { + ObjectFlagUpdatePacket flags = new ObjectFlagUpdatePacket(); + flags.AgentData.AgentID = Client.Self.AgentID; + flags.AgentData.SessionID = Client.Self.SessionID; + flags.AgentData.ObjectLocalID = localID; + flags.AgentData.UsePhysics = physical; + flags.AgentData.IsTemporary = temporary; + flags.AgentData.IsPhantom = phantom; + flags.AgentData.CastsShadows = castsShadow; + + flags.ExtraPhysics = new ObjectFlagUpdatePacket.ExtraPhysicsBlock[1]; + flags.ExtraPhysics[0] = new ObjectFlagUpdatePacket.ExtraPhysicsBlock(); + flags.ExtraPhysics[0].PhysicsShapeType = (byte)physicsType; + flags.ExtraPhysics[0].Density = density; + flags.ExtraPhysics[0].Friction = friction; + flags.ExtraPhysics[0].Restitution = restitution; + flags.ExtraPhysics[0].GravityMultiplier = gravityMultiplier; + + Client.Network.SendPacket(flags, simulator); + } + + /// + /// Sets the sale properties of a single object + /// + /// The the object is located + /// The Local ID of the object + /// One of the options from the enum + /// The price of the object + public void SetSaleInfo(Simulator simulator, uint localID, SaleType saleType, int price) + { + ObjectSaleInfoPacket sale = new ObjectSaleInfoPacket(); + sale.AgentData.AgentID = Client.Self.AgentID; + sale.AgentData.SessionID = Client.Self.SessionID; + sale.ObjectData = new ObjectSaleInfoPacket.ObjectDataBlock[1]; + sale.ObjectData[0] = new ObjectSaleInfoPacket.ObjectDataBlock(); + sale.ObjectData[0].LocalID = localID; + sale.ObjectData[0].SalePrice = price; + sale.ObjectData[0].SaleType = (byte)saleType; + + Client.Network.SendPacket(sale, simulator); + } + + /// + /// Sets the sale properties of multiple objects + /// + /// The the objects are located + /// An array containing the Local IDs of the objects + /// One of the options from the enum + /// The price of the object + public void SetSaleInfo(Simulator simulator, List localIDs, SaleType saleType, int price) + { + ObjectSaleInfoPacket sale = new ObjectSaleInfoPacket(); + sale.AgentData.AgentID = Client.Self.AgentID; + sale.AgentData.SessionID = Client.Self.SessionID; + sale.ObjectData = new ObjectSaleInfoPacket.ObjectDataBlock[localIDs.Count]; + + for (int i = 0; i < localIDs.Count; i++) + { + sale.ObjectData[i] = new ObjectSaleInfoPacket.ObjectDataBlock(); + sale.ObjectData[i].LocalID = localIDs[i]; + sale.ObjectData[i].SalePrice = price; + sale.ObjectData[i].SaleType = (byte)saleType; + } + + Client.Network.SendPacket(sale, simulator); + } + + /// + /// Deselect a single object + /// + /// The the object is located + /// The Local ID of the object + public void DeselectObject(Simulator simulator, uint localID) + { + ObjectDeselectPacket deselect = new ObjectDeselectPacket(); + + deselect.AgentData.AgentID = Client.Self.AgentID; + deselect.AgentData.SessionID = Client.Self.SessionID; + + deselect.ObjectData = new ObjectDeselectPacket.ObjectDataBlock[1]; + deselect.ObjectData[0] = new ObjectDeselectPacket.ObjectDataBlock(); + deselect.ObjectData[0].ObjectLocalID = localID; + + Client.Network.SendPacket(deselect, simulator); + } + + /// + /// Deselect multiple objects. + /// + /// The the objects are located + /// An array containing the Local IDs of the objects + public void DeselectObjects(Simulator simulator, uint[] localIDs) + { + ObjectDeselectPacket deselect = new ObjectDeselectPacket(); + + deselect.AgentData.AgentID = Client.Self.AgentID; + deselect.AgentData.SessionID = Client.Self.SessionID; + + deselect.ObjectData = new ObjectDeselectPacket.ObjectDataBlock[localIDs.Length]; + + for (int i = 0; i < localIDs.Length; i++) + { + deselect.ObjectData[i] = new ObjectDeselectPacket.ObjectDataBlock(); + deselect.ObjectData[i].ObjectLocalID = localIDs[i]; + } + + Client.Network.SendPacket(deselect, simulator); + } + + /// + /// Perform a click action on an object + /// + /// The the object is located + /// The Local ID of the object + public void ClickObject(Simulator simulator, uint localID) + { + ClickObject(simulator, localID, Vector3.Zero, Vector3.Zero, 0, Vector3.Zero, Vector3.Zero, Vector3.Zero); + } + + /// + /// Perform a click action (Grab) on a single object + /// + /// The the object is located + /// The Local ID of the object + /// The texture coordinates to touch + /// The surface coordinates to touch + /// The face of the position to touch + /// The region coordinates of the position to touch + /// The surface normal of the position to touch (A normal is a vector perpindicular to the surface) + /// The surface binormal of the position to touch (A binormal is a vector tangen to the surface + /// pointing along the U direction of the tangent space + public void ClickObject(Simulator simulator, uint localID, Vector3 uvCoord, Vector3 stCoord, int faceIndex, Vector3 position, + Vector3 normal, Vector3 binormal) + { + ObjectGrabPacket grab = new ObjectGrabPacket(); + grab.AgentData.AgentID = Client.Self.AgentID; + grab.AgentData.SessionID = Client.Self.SessionID; + grab.ObjectData.GrabOffset = Vector3.Zero; + grab.ObjectData.LocalID = localID; + grab.SurfaceInfo = new ObjectGrabPacket.SurfaceInfoBlock[1]; + grab.SurfaceInfo[0] = new ObjectGrabPacket.SurfaceInfoBlock(); + grab.SurfaceInfo[0].UVCoord = uvCoord; + grab.SurfaceInfo[0].STCoord = stCoord; + grab.SurfaceInfo[0].FaceIndex = faceIndex; + grab.SurfaceInfo[0].Position = position; + grab.SurfaceInfo[0].Normal = normal; + grab.SurfaceInfo[0].Binormal = binormal; + + Client.Network.SendPacket(grab, simulator); + + // TODO: If these hit the server out of order the click will fail + // and we'll be grabbing the object + Thread.Sleep(50); + + ObjectDeGrabPacket degrab = new ObjectDeGrabPacket(); + degrab.AgentData.AgentID = Client.Self.AgentID; + degrab.AgentData.SessionID = Client.Self.SessionID; + degrab.ObjectData.LocalID = localID; + degrab.SurfaceInfo = new ObjectDeGrabPacket.SurfaceInfoBlock[1]; + degrab.SurfaceInfo[0] = new ObjectDeGrabPacket.SurfaceInfoBlock(); + degrab.SurfaceInfo[0].UVCoord = uvCoord; + degrab.SurfaceInfo[0].STCoord = stCoord; + degrab.SurfaceInfo[0].FaceIndex = faceIndex; + degrab.SurfaceInfo[0].Position = position; + degrab.SurfaceInfo[0].Normal = normal; + degrab.SurfaceInfo[0].Binormal = binormal; + + Client.Network.SendPacket(degrab, simulator); + } + + /// + /// Create (rez) a new prim object in a simulator + /// + /// A reference to the object to place the object in + /// Data describing the prim object to rez + /// Group ID that this prim will be set to, or UUID.Zero if you + /// do not want the object to be associated with a specific group + /// An approximation of the position at which to rez the prim + /// Scale vector to size this prim + /// Rotation quaternion to rotate this prim + /// Due to the way client prim rezzing is done on the server, + /// the requested position for an object is only close to where the prim + /// actually ends up. If you desire exact placement you'll need to + /// follow up by moving the object after it has been created. This + /// function will not set textures, light and flexible data, or other + /// extended primitive properties + public void AddPrim(Simulator simulator, Primitive.ConstructionData prim, UUID groupID, Vector3 position, + Vector3 scale, Quaternion rotation) + { + AddPrim(simulator, prim, groupID, position, scale, rotation, PrimFlags.CreateSelected); + } + + /// + /// Create (rez) a new prim object in a simulator + /// + /// A reference to the object to place the object in + /// Data describing the prim object to rez + /// Group ID that this prim will be set to, or UUID.Zero if you + /// do not want the object to be associated with a specific group + /// An approximation of the position at which to rez the prim + /// Scale vector to size this prim + /// Rotation quaternion to rotate this prim + /// Specify the + /// Due to the way client prim rezzing is done on the server, + /// the requested position for an object is only close to where the prim + /// actually ends up. If you desire exact placement you'll need to + /// follow up by moving the object after it has been created. This + /// function will not set textures, light and flexible data, or other + /// extended primitive properties + public void AddPrim(Simulator simulator, Primitive.ConstructionData prim, UUID groupID, Vector3 position, + Vector3 scale, Quaternion rotation, PrimFlags createFlags) + { + ObjectAddPacket packet = new ObjectAddPacket(); + + packet.AgentData.AgentID = Client.Self.AgentID; + packet.AgentData.SessionID = Client.Self.SessionID; + packet.AgentData.GroupID = groupID; + + packet.ObjectData.State = prim.State; + packet.ObjectData.AddFlags = (uint)createFlags; + packet.ObjectData.PCode = (byte)PCode.Prim; + + packet.ObjectData.Material = (byte)prim.Material; + packet.ObjectData.Scale = scale; + packet.ObjectData.Rotation = rotation; + + packet.ObjectData.PathCurve = (byte)prim.PathCurve; + packet.ObjectData.PathBegin = Primitive.PackBeginCut(prim.PathBegin); + packet.ObjectData.PathEnd = Primitive.PackEndCut(prim.PathEnd); + packet.ObjectData.PathRadiusOffset = Primitive.PackPathTwist(prim.PathRadiusOffset); + packet.ObjectData.PathRevolutions = Primitive.PackPathRevolutions(prim.PathRevolutions); + packet.ObjectData.PathScaleX = Primitive.PackPathScale(prim.PathScaleX); + packet.ObjectData.PathScaleY = Primitive.PackPathScale(prim.PathScaleY); + packet.ObjectData.PathShearX = (byte)Primitive.PackPathShear(prim.PathShearX); + packet.ObjectData.PathShearY = (byte)Primitive.PackPathShear(prim.PathShearY); + packet.ObjectData.PathSkew = Primitive.PackPathTwist(prim.PathSkew); + packet.ObjectData.PathTaperX = Primitive.PackPathTaper(prim.PathTaperX); + packet.ObjectData.PathTaperY = Primitive.PackPathTaper(prim.PathTaperY); + packet.ObjectData.PathTwist = Primitive.PackPathTwist(prim.PathTwist); + packet.ObjectData.PathTwistBegin = Primitive.PackPathTwist(prim.PathTwistBegin); + + packet.ObjectData.ProfileCurve = prim.profileCurve; + packet.ObjectData.ProfileBegin = Primitive.PackBeginCut(prim.ProfileBegin); + packet.ObjectData.ProfileEnd = Primitive.PackEndCut(prim.ProfileEnd); + packet.ObjectData.ProfileHollow = Primitive.PackProfileHollow(prim.ProfileHollow); + + packet.ObjectData.RayStart = position; + packet.ObjectData.RayEnd = position; + packet.ObjectData.RayEndIsIntersection = 0; + packet.ObjectData.RayTargetID = UUID.Zero; + packet.ObjectData.BypassRaycast = 1; + + Client.Network.SendPacket(packet, simulator); + } + + /// + /// Rez a Linden tree + /// + /// A reference to the object where the object resides + /// The size of the tree + /// The rotation of the tree + /// The position of the tree + /// The Type of tree + /// The of the group to set the tree to, + /// or UUID.Zero if no group is to be set + /// true to use the "new" Linden trees, false to use the old + public void AddTree(Simulator simulator, Vector3 scale, Quaternion rotation, Vector3 position, + Tree treeType, UUID groupOwner, bool newTree) + { + ObjectAddPacket add = new ObjectAddPacket(); + + add.AgentData.AgentID = Client.Self.AgentID; + add.AgentData.SessionID = Client.Self.SessionID; + add.AgentData.GroupID = groupOwner; + add.ObjectData.BypassRaycast = 1; + add.ObjectData.Material = 3; + add.ObjectData.PathCurve = 16; + add.ObjectData.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree; + add.ObjectData.RayEnd = position; + add.ObjectData.RayStart = position; + add.ObjectData.RayTargetID = UUID.Zero; + add.ObjectData.Rotation = rotation; + add.ObjectData.Scale = scale; + add.ObjectData.State = (byte)treeType; + + Client.Network.SendPacket(add, simulator); + } + + /// + /// Rez grass and ground cover + /// + /// A reference to the object where the object resides + /// The size of the grass + /// The rotation of the grass + /// The position of the grass + /// The type of grass from the enum + /// The of the group to set the tree to, + /// or UUID.Zero if no group is to be set + public void AddGrass(Simulator simulator, Vector3 scale, Quaternion rotation, Vector3 position, + Grass grassType, UUID groupOwner) + { + ObjectAddPacket add = new ObjectAddPacket(); + + add.AgentData.AgentID = Client.Self.AgentID; + add.AgentData.SessionID = Client.Self.SessionID; + add.AgentData.GroupID = groupOwner; + add.ObjectData.BypassRaycast = 1; + add.ObjectData.Material = 3; + add.ObjectData.PathCurve = 16; + add.ObjectData.PCode = (byte)PCode.Grass; + add.ObjectData.RayEnd = position; + add.ObjectData.RayStart = position; + add.ObjectData.RayTargetID = UUID.Zero; + add.ObjectData.Rotation = rotation; + add.ObjectData.Scale = scale; + add.ObjectData.State = (byte)grassType; + + Client.Network.SendPacket(add, simulator); + } + + /// + /// Set the textures to apply to the faces of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The texture data to apply + public void SetTextures(Simulator simulator, uint localID, Primitive.TextureEntry textures) + { + SetTextures(simulator, localID, textures, String.Empty); + } + + /// + /// Set the textures to apply to the faces of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The texture data to apply + /// A media URL (not used) + public void SetTextures(Simulator simulator, uint localID, Primitive.TextureEntry textures, string mediaUrl) + { + ObjectImagePacket image = new ObjectImagePacket(); + + image.AgentData.AgentID = Client.Self.AgentID; + image.AgentData.SessionID = Client.Self.SessionID; + image.ObjectData = new ObjectImagePacket.ObjectDataBlock[1]; + image.ObjectData[0] = new ObjectImagePacket.ObjectDataBlock(); + image.ObjectData[0].ObjectLocalID = localID; + image.ObjectData[0].TextureEntry = textures.GetBytes(); + image.ObjectData[0].MediaURL = Utils.StringToBytes(mediaUrl); + + Client.Network.SendPacket(image, simulator); + } + + /// + /// Set the Light data on an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// A object containing the data to set + public void SetLight(Simulator simulator, uint localID, Primitive.LightData light) + { + ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket(); + + extra.AgentData.AgentID = Client.Self.AgentID; + extra.AgentData.SessionID = Client.Self.SessionID; + extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1]; + extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock(); + extra.ObjectData[0].ObjectLocalID = localID; + extra.ObjectData[0].ParamType = (byte)ExtraParamType.Light; + if (light.Intensity == 0.0f) + { + // Disables the light if intensity is 0 + extra.ObjectData[0].ParamInUse = false; + } + else + { + extra.ObjectData[0].ParamInUse = true; + } + extra.ObjectData[0].ParamData = light.GetBytes(); + extra.ObjectData[0].ParamSize = (uint)extra.ObjectData[0].ParamData.Length; + + Client.Network.SendPacket(extra, simulator); + } + + /// + /// Set the flexible data on an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// A object containing the data to set + public void SetFlexible(Simulator simulator, uint localID, Primitive.FlexibleData flexible) + { + ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket(); + + extra.AgentData.AgentID = Client.Self.AgentID; + extra.AgentData.SessionID = Client.Self.SessionID; + extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1]; + extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock(); + extra.ObjectData[0].ObjectLocalID = localID; + extra.ObjectData[0].ParamType = (byte)ExtraParamType.Flexible; + extra.ObjectData[0].ParamInUse = true; + extra.ObjectData[0].ParamData = flexible.GetBytes(); + extra.ObjectData[0].ParamSize = (uint)extra.ObjectData[0].ParamData.Length; + + Client.Network.SendPacket(extra, simulator); + } + + /// + /// Set the sculptie texture and data on an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// A object containing the data to set + public void SetSculpt(Simulator simulator, uint localID, Primitive.SculptData sculpt) + { + ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket(); + + extra.AgentData.AgentID = Client.Self.AgentID; + extra.AgentData.SessionID = Client.Self.SessionID; + + extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1]; + extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock(); + extra.ObjectData[0].ObjectLocalID = localID; + extra.ObjectData[0].ParamType = (byte)ExtraParamType.Sculpt; + extra.ObjectData[0].ParamInUse = true; + extra.ObjectData[0].ParamData = sculpt.GetBytes(); + extra.ObjectData[0].ParamSize = (uint)extra.ObjectData[0].ParamData.Length; + + Client.Network.SendPacket(extra, simulator); + + // Not sure why, but if you don't send this the sculpted prim disappears + ObjectShapePacket shape = new ObjectShapePacket(); + + shape.AgentData.AgentID = Client.Self.AgentID; + shape.AgentData.SessionID = Client.Self.SessionID; + + shape.ObjectData = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock[1]; + shape.ObjectData[0] = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock(); + shape.ObjectData[0].ObjectLocalID = localID; + shape.ObjectData[0].PathScaleX = 100; + shape.ObjectData[0].PathScaleY = 150; + shape.ObjectData[0].PathCurve = 32; + + Client.Network.SendPacket(shape, simulator); + } + + /// + /// Unset additional primitive parameters on an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The extra parameters to set + public void SetExtraParamOff(Simulator simulator, uint localID, ExtraParamType type) + { + ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket(); + + extra.AgentData.AgentID = Client.Self.AgentID; + extra.AgentData.SessionID = Client.Self.SessionID; + extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1]; + extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock(); + extra.ObjectData[0].ObjectLocalID = localID; + extra.ObjectData[0].ParamType = (byte)type; + extra.ObjectData[0].ParamInUse = false; + extra.ObjectData[0].ParamData = Utils.EmptyBytes; + extra.ObjectData[0].ParamSize = 0; + + Client.Network.SendPacket(extra, simulator); + } + + /// + /// Link multiple prims into a linkset + /// + /// A reference to the object where the objects reside + /// An array which contains the IDs of the objects to link + /// The last object in the array will be the root object of the linkset TODO: Is this true? + public void LinkPrims(Simulator simulator, List localIDs) + { + ObjectLinkPacket packet = new ObjectLinkPacket(); + + packet.AgentData.AgentID = Client.Self.AgentID; + packet.AgentData.SessionID = Client.Self.SessionID; + + packet.ObjectData = new ObjectLinkPacket.ObjectDataBlock[localIDs.Count]; + + for (int i = 0; i < localIDs.Count; i++) + { + packet.ObjectData[i] = new ObjectLinkPacket.ObjectDataBlock(); + packet.ObjectData[i].ObjectLocalID = localIDs[i]; + } + + Client.Network.SendPacket(packet, simulator); + } + + /// + /// Delink/Unlink multiple prims from a linkset + /// + /// A reference to the object where the objects reside + /// An array which contains the IDs of the objects to delink + public void DelinkPrims(Simulator simulator, List localIDs) + { + ObjectDelinkPacket packet = new ObjectDelinkPacket(); + + packet.AgentData.AgentID = Client.Self.AgentID; + packet.AgentData.SessionID = Client.Self.SessionID; + + packet.ObjectData = new ObjectDelinkPacket.ObjectDataBlock[localIDs.Count]; + + int i = 0; + foreach (uint localID in localIDs) + { + packet.ObjectData[i] = new ObjectDelinkPacket.ObjectDataBlock(); + packet.ObjectData[i].ObjectLocalID = localID; + + i++; + } + + Client.Network.SendPacket(packet, simulator); + } + + /// + /// Change the rotation of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The new rotation of the object + public void SetRotation(Simulator simulator, uint localID, Quaternion rotation) + { + ObjectRotationPacket objRotPacket = new ObjectRotationPacket(); + objRotPacket.AgentData.AgentID = Client.Self.AgentID; + objRotPacket.AgentData.SessionID = Client.Self.SessionID; + + objRotPacket.ObjectData = new ObjectRotationPacket.ObjectDataBlock[1]; + + objRotPacket.ObjectData[0] = new ObjectRotationPacket.ObjectDataBlock(); + objRotPacket.ObjectData[0].ObjectLocalID = localID; + objRotPacket.ObjectData[0].Rotation = rotation; + Client.Network.SendPacket(objRotPacket, simulator); + } + + /// + /// Set the name of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// A string containing the new name of the object + public void SetName(Simulator simulator, uint localID, string name) + { + SetNames(simulator, new uint[] { localID }, new string[] { name }); + } + + /// + /// Set the name of multiple objects + /// + /// A reference to the object where the objects reside + /// An array which contains the IDs of the objects to change the name of + /// An array which contains the new names of the objects + public void SetNames(Simulator simulator, uint[] localIDs, string[] names) + { + ObjectNamePacket namePacket = new ObjectNamePacket(); + namePacket.AgentData.AgentID = Client.Self.AgentID; + namePacket.AgentData.SessionID = Client.Self.SessionID; + + namePacket.ObjectData = new ObjectNamePacket.ObjectDataBlock[localIDs.Length]; + + for (int i = 0; i < localIDs.Length; ++i) + { + namePacket.ObjectData[i] = new ObjectNamePacket.ObjectDataBlock(); + namePacket.ObjectData[i].LocalID = localIDs[i]; + namePacket.ObjectData[i].Name = Utils.StringToBytes(names[i]); + } + + Client.Network.SendPacket(namePacket, simulator); + } + + /// + /// Set the description of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// A string containing the new description of the object + public void SetDescription(Simulator simulator, uint localID, string description) + { + SetDescriptions(simulator, new uint[] { localID }, new string[] { description }); + } + + /// + /// Set the descriptions of multiple objects + /// + /// A reference to the object where the objects reside + /// An array which contains the IDs of the objects to change the description of + /// An array which contains the new descriptions of the objects + public void SetDescriptions(Simulator simulator, uint[] localIDs, string[] descriptions) + { + ObjectDescriptionPacket descPacket = new ObjectDescriptionPacket(); + descPacket.AgentData.AgentID = Client.Self.AgentID; + descPacket.AgentData.SessionID = Client.Self.SessionID; + + descPacket.ObjectData = new ObjectDescriptionPacket.ObjectDataBlock[localIDs.Length]; + + for (int i = 0; i < localIDs.Length; ++i) + { + descPacket.ObjectData[i] = new ObjectDescriptionPacket.ObjectDataBlock(); + descPacket.ObjectData[i].LocalID = localIDs[i]; + descPacket.ObjectData[i].Description = Utils.StringToBytes(descriptions[i]); + } + + Client.Network.SendPacket(descPacket, simulator); + } + + /// + /// Attach an object to this avatar + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The point on the avatar the object will be attached + /// The rotation of the attached object + public void AttachObject(Simulator simulator, uint localID, AttachmentPoint attachPoint, Quaternion rotation) + { + ObjectAttachPacket attach = new ObjectAttachPacket(); + attach.AgentData.AgentID = Client.Self.AgentID; + attach.AgentData.SessionID = Client.Self.SessionID; + attach.AgentData.AttachmentPoint = (byte)attachPoint; + + attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; + attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); + attach.ObjectData[0].ObjectLocalID = localID; + attach.ObjectData[0].Rotation = rotation; + + Client.Network.SendPacket(attach, simulator); + } + + /// + /// Drop an attached object from this avatar + /// + /// A reference to the + /// object where the objects reside. This will always be the simulator the avatar is currently in + /// + /// The object's ID which is local to the simulator the object is in + public void DropObject(Simulator simulator, uint localID) + { + ObjectDropPacket dropit = new ObjectDropPacket(); + dropit.AgentData.AgentID = Client.Self.AgentID; + dropit.AgentData.SessionID = Client.Self.SessionID; + dropit.ObjectData = new ObjectDropPacket.ObjectDataBlock[1]; + dropit.ObjectData[0] = new ObjectDropPacket.ObjectDataBlock(); + dropit.ObjectData[0].ObjectLocalID = localID; + + Client.Network.SendPacket(dropit, simulator); + } + + /// + /// Detach an object from yourself + /// + /// A reference to the + /// object where the objects reside + /// + /// This will always be the simulator the avatar is currently in + /// + /// An array which contains the IDs of the objects to detach + public void DetachObjects(Simulator simulator, List localIDs) + { + ObjectDetachPacket detach = new ObjectDetachPacket(); + detach.AgentData.AgentID = Client.Self.AgentID; + detach.AgentData.SessionID = Client.Self.SessionID; + detach.ObjectData = new ObjectDetachPacket.ObjectDataBlock[localIDs.Count]; + + for (int i = 0; i < localIDs.Count; i++) + { + detach.ObjectData[i] = new ObjectDetachPacket.ObjectDataBlock(); + detach.ObjectData[i].ObjectLocalID = localIDs[i]; + } + + Client.Network.SendPacket(detach, simulator); + } + + /// + /// Change the position of an object, Will change position of entire linkset + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The new position of the object + public void SetPosition(Simulator simulator, uint localID, Vector3 position) + { + UpdateObject(simulator, localID, position, UpdateType.Position | UpdateType.Linked); + } + + /// + /// Change the position of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The new position of the object + /// if true, will change position of (this) child prim only, not entire linkset + public void SetPosition(Simulator simulator, uint localID, Vector3 position, bool childOnly) + { + UpdateType type = UpdateType.Position; + + if (!childOnly) + type |= UpdateType.Linked; + + UpdateObject(simulator, localID, position, type); + } + + /// + /// Change the Scale (size) of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The new scale of the object + /// If true, will change scale of this prim only, not entire linkset + /// True to resize prims uniformly + public void SetScale(Simulator simulator, uint localID, Vector3 scale, bool childOnly, bool uniform) + { + UpdateType type = UpdateType.Scale; + + if (!childOnly) + type |= UpdateType.Linked; + + if (uniform) + type |= UpdateType.Uniform; + + UpdateObject(simulator, localID, scale, type); + } + + /// + /// Change the Rotation of an object that is either a child or a whole linkset + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The new scale of the object + /// If true, will change rotation of this prim only, not entire linkset + public void SetRotation(Simulator simulator, uint localID, Quaternion quat, bool childOnly) + { + UpdateType type = UpdateType.Rotation; + + if (!childOnly) + type |= UpdateType.Linked; + + MultipleObjectUpdatePacket multiObjectUpdate = new MultipleObjectUpdatePacket(); + multiObjectUpdate.AgentData.AgentID = Client.Self.AgentID; + multiObjectUpdate.AgentData.SessionID = Client.Self.SessionID; + + multiObjectUpdate.ObjectData = new MultipleObjectUpdatePacket.ObjectDataBlock[1]; + + multiObjectUpdate.ObjectData[0] = new MultipleObjectUpdatePacket.ObjectDataBlock(); + multiObjectUpdate.ObjectData[0].Type = (byte)type; + multiObjectUpdate.ObjectData[0].ObjectLocalID = localID; + multiObjectUpdate.ObjectData[0].Data = quat.GetBytes(); + + Client.Network.SendPacket(multiObjectUpdate, simulator); + } + + /// + /// Send a Multiple Object Update packet to change the size, scale or rotation of a primitive + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The new rotation, size, or position of the target object + /// The flags from the Enum + public void UpdateObject(Simulator simulator, uint localID, Vector3 data, UpdateType type) + { + MultipleObjectUpdatePacket multiObjectUpdate = new MultipleObjectUpdatePacket(); + multiObjectUpdate.AgentData.AgentID = Client.Self.AgentID; + multiObjectUpdate.AgentData.SessionID = Client.Self.SessionID; + + multiObjectUpdate.ObjectData = new MultipleObjectUpdatePacket.ObjectDataBlock[1]; + + multiObjectUpdate.ObjectData[0] = new MultipleObjectUpdatePacket.ObjectDataBlock(); + multiObjectUpdate.ObjectData[0].Type = (byte)type; + multiObjectUpdate.ObjectData[0].ObjectLocalID = localID; + multiObjectUpdate.ObjectData[0].Data = data.GetBytes(); + + Client.Network.SendPacket(multiObjectUpdate, simulator); + } + + /// + /// Deed an object (prim) to a group, Object must be shared with group which + /// can be accomplished with SetPermissions() + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The of the group to deed the object to + public void DeedObject(Simulator simulator, uint localID, UUID groupOwner) + { + ObjectOwnerPacket objDeedPacket = new ObjectOwnerPacket(); + objDeedPacket.AgentData.AgentID = Client.Self.AgentID; + objDeedPacket.AgentData.SessionID = Client.Self.SessionID; + + // Can only be use in God mode + objDeedPacket.HeaderData.Override = false; + objDeedPacket.HeaderData.OwnerID = UUID.Zero; + objDeedPacket.HeaderData.GroupID = groupOwner; + + objDeedPacket.ObjectData = new ObjectOwnerPacket.ObjectDataBlock[1]; + objDeedPacket.ObjectData[0] = new ObjectOwnerPacket.ObjectDataBlock(); + + objDeedPacket.ObjectData[0].ObjectLocalID = localID; + + Client.Network.SendPacket(objDeedPacket, simulator); + } + + /// + /// Deed multiple objects (prims) to a group, Objects must be shared with group which + /// can be accomplished with SetPermissions() + /// + /// A reference to the object where the object resides + /// An array which contains the IDs of the objects to deed + /// The of the group to deed the object to + public void DeedObjects(Simulator simulator, List localIDs, UUID groupOwner) + { + ObjectOwnerPacket packet = new ObjectOwnerPacket(); + packet.AgentData.AgentID = Client.Self.AgentID; + packet.AgentData.SessionID = Client.Self.SessionID; + + // Can only be use in God mode + packet.HeaderData.Override = false; + packet.HeaderData.OwnerID = UUID.Zero; + packet.HeaderData.GroupID = groupOwner; + + packet.ObjectData = new ObjectOwnerPacket.ObjectDataBlock[localIDs.Count]; + + for (int i = 0; i < localIDs.Count; i++) + { + packet.ObjectData[i] = new ObjectOwnerPacket.ObjectDataBlock(); + packet.ObjectData[i].ObjectLocalID = localIDs[i]; + } + Client.Network.SendPacket(packet, simulator); + } + + /// + /// Set the permissions on multiple objects + /// + /// A reference to the object where the objects reside + /// An array which contains the IDs of the objects to set the permissions on + /// The new Who mask to set + /// Which permission to modify + /// The new state of permission + public void SetPermissions(Simulator simulator, List localIDs, PermissionWho who, + PermissionMask permissions, bool set) + { + ObjectPermissionsPacket packet = new ObjectPermissionsPacket(); + + packet.AgentData.AgentID = Client.Self.AgentID; + packet.AgentData.SessionID = Client.Self.SessionID; + + // Override can only be used by gods + packet.HeaderData.Override = false; + + packet.ObjectData = new ObjectPermissionsPacket.ObjectDataBlock[localIDs.Count]; + + for (int i = 0; i < localIDs.Count; i++) + { + packet.ObjectData[i] = new ObjectPermissionsPacket.ObjectDataBlock(); + + packet.ObjectData[i].ObjectLocalID = localIDs[i]; + packet.ObjectData[i].Field = (byte)who; + packet.ObjectData[i].Mask = (uint)permissions; + packet.ObjectData[i].Set = Convert.ToByte(set); + } + + Client.Network.SendPacket(packet, simulator); + } + + /// + /// Request additional properties for an object + /// + /// A reference to the object where the object resides + /// + public void RequestObjectPropertiesFamily(Simulator simulator, UUID objectID) + { + RequestObjectPropertiesFamily(simulator, objectID, true); + } + + /// + /// Request additional properties for an object + /// + /// A reference to the object where the object resides + /// Absolute UUID of the object + /// Whether to require server acknowledgement of this request + public void RequestObjectPropertiesFamily(Simulator simulator, UUID objectID, bool reliable) + { + RequestObjectPropertiesFamilyPacket properties = new RequestObjectPropertiesFamilyPacket(); + properties.AgentData.AgentID = Client.Self.AgentID; + properties.AgentData.SessionID = Client.Self.SessionID; + properties.ObjectData.ObjectID = objectID; + // TODO: RequestFlags is typically only for bug report submissions, but we might be able to + // use it to pass an arbitrary uint back to the callback + properties.ObjectData.RequestFlags = 0; + + properties.Header.Reliable = reliable; + + Client.Network.SendPacket(properties, simulator); + } + + /// + /// Set the ownership of a list of objects to the specified group + /// + /// A reference to the object where the objects reside + /// An array which contains the IDs of the objects to set the group id on + /// The Groups ID + public void SetObjectsGroup(Simulator simulator, List localIds, UUID groupID) + { + ObjectGroupPacket packet = new ObjectGroupPacket(); + packet.AgentData.AgentID = Client.Self.AgentID; + packet.AgentData.GroupID = groupID; + packet.AgentData.SessionID = Client.Self.SessionID; + + packet.ObjectData = new ObjectGroupPacket.ObjectDataBlock[localIds.Count]; + for (int i = 0; i < localIds.Count; i++) + { + packet.ObjectData[i] = new ObjectGroupPacket.ObjectDataBlock(); + packet.ObjectData[i].ObjectLocalID = localIds[i]; + } + + Client.Network.SendPacket(packet, simulator); + } + + /// + /// Update current URL of the previously set prim media + /// + /// UUID of the prim + /// Set current URL to this + /// Prim face number + /// Simulator in which prim is located + public void NavigateObjectMedia(UUID primID, int face, string newURL, Simulator sim) + { + Uri url; + if (sim.Caps != null && null != (url = sim.Caps.CapabilityURI("ObjectMediaNavigate"))) + { + ObjectMediaNavigateMessage req = new ObjectMediaNavigateMessage(); + req.PrimID = primID; + req.URL = newURL; + req.Face = face; + + CapsClient request = new CapsClient(url); + request.OnComplete += (CapsClient client, OSD result, Exception error) => + { + if (error != null) + { + Logger.Log("ObjectMediaNavigate: " + error.Message, Helpers.LogLevel.Error, Client); + } + }; + + request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + Logger.Log("ObjectMediaNavigate capability not available", Helpers.LogLevel.Error, Client); + } + } + + /// + /// Set object media + /// + /// UUID of the prim + /// Array the length of prims number of faces. Null on face indexes where there is + /// no media, on faces which contain the media + /// Simulatior in which prim is located + public void UpdateObjectMedia(UUID primID, MediaEntry[] faceMedia, Simulator sim) + { + Uri url; + if (sim.Caps != null && null != (url = sim.Caps.CapabilityURI("ObjectMedia"))) + { + ObjectMediaUpdate req = new ObjectMediaUpdate(); + req.PrimID = primID; + req.FaceMedia = faceMedia; + req.Verb = "UPDATE"; + + CapsClient request = new CapsClient(url); + request.OnComplete += (CapsClient client, OSD result, Exception error) => + { + if (error != null) + { + Logger.Log("ObjectMediaUpdate: " + error.Message, Helpers.LogLevel.Error, Client); + } + }; + request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + Logger.Log("ObjectMedia capability not available", Helpers.LogLevel.Error, Client); + } + } + + /// + /// Retrieve information about object media + /// + /// UUID of the primitive + /// Simulator where prim is located + /// Call this callback when done + public void RequestObjectMedia(UUID primID, Simulator sim, ObjectMediaCallback callback) + { + Uri url; + if (sim.Caps != null && null != (url = sim.Caps.CapabilityURI("ObjectMedia"))) + { + ObjectMediaRequest req = new ObjectMediaRequest(); + req.PrimID = primID; + req.Verb = "GET"; + + CapsClient request = new CapsClient(url); + request.OnComplete += (CapsClient client, OSD result, Exception error) => + { + if (result == null) + { + Logger.Log("Failed retrieving ObjectMedia data", Helpers.LogLevel.Error, Client); + try { callback(false, string.Empty, null); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } + return; + } + + ObjectMediaMessage msg = new ObjectMediaMessage(); + msg.Deserialize((OSDMap)result); + + if (msg.Request is ObjectMediaResponse) + { + ObjectMediaResponse response = (ObjectMediaResponse)msg.Request; + + if (Client.Settings.OBJECT_TRACKING) + { + Primitive prim = sim.ObjectsPrimitives.Find((Primitive p) => { return p.ID == primID; }); + if (prim != null) + { + prim.MediaVersion = response.Version; + prim.FaceMedia = response.FaceMedia; + } + } + + try { callback(true, response.Version, response.FaceMedia); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } + } + else + { + try { callback(false, string.Empty, null); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } + } + }; + + request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + else + { + Logger.Log("ObjectMedia capability not available", Helpers.LogLevel.Error, Client); + try { callback(false, string.Empty, null); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } + } + } + #endregion + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ObjectUpdateHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ObjectUpdatePacket update = (ObjectUpdatePacket)packet; + UpdateDilation(e.Simulator, update.RegionData.TimeDilation); + + for (int b = 0; b < update.ObjectData.Length; b++) + { + ObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[b]; + + ObjectMovementUpdate objectupdate = new ObjectMovementUpdate(); + //Vector4 collisionPlane = Vector4.Zero; + //Vector3 position; + //Vector3 velocity; + //Vector3 acceleration; + //Quaternion rotation; + //Vector3 angularVelocity; + NameValue[] nameValues; + bool attachment = false; + PCode pcode = (PCode)block.PCode; + + #region Relevance check + + // Check if we are interested in this object + if (!Client.Settings.ALWAYS_DECODE_OBJECTS) + { + switch (pcode) + { + case PCode.Grass: + case PCode.Tree: + case PCode.NewTree: + case PCode.Prim: + if (m_ObjectUpdate == null) continue; + break; + case PCode.Avatar: + // Make an exception for updates about our own agent + if (block.FullID != Client.Self.AgentID && m_AvatarUpdate == null) continue; + break; + case PCode.ParticleSystem: + continue; // TODO: Do something with these + } + } + + #endregion Relevance check + + #region NameValue parsing + + string nameValue = Utils.BytesToString(block.NameValue); + if (nameValue.Length > 0) + { + string[] lines = nameValue.Split('\n'); + nameValues = new NameValue[lines.Length]; + + for (int i = 0; i < lines.Length; i++) + { + if (!String.IsNullOrEmpty(lines[i])) + { + NameValue nv = new NameValue(lines[i]); + if (nv.Name == "AttachItemID") attachment = true; + nameValues[i] = nv; + } + } + } + else + { + nameValues = new NameValue[0]; + } + + #endregion NameValue parsing + + #region Decode Object (primitive) parameters + Primitive.ConstructionData data = new Primitive.ConstructionData(); + data.State = block.State; + data.Material = (Material)block.Material; + data.PathCurve = (PathCurve)block.PathCurve; + data.profileCurve = block.ProfileCurve; + data.PathBegin = Primitive.UnpackBeginCut(block.PathBegin); + data.PathEnd = Primitive.UnpackEndCut(block.PathEnd); + data.PathScaleX = Primitive.UnpackPathScale(block.PathScaleX); + data.PathScaleY = Primitive.UnpackPathScale(block.PathScaleY); + data.PathShearX = Primitive.UnpackPathShear((sbyte)block.PathShearX); + data.PathShearY = Primitive.UnpackPathShear((sbyte)block.PathShearY); + data.PathTwist = Primitive.UnpackPathTwist(block.PathTwist); + data.PathTwistBegin = Primitive.UnpackPathTwist(block.PathTwistBegin); + data.PathRadiusOffset = Primitive.UnpackPathTwist(block.PathRadiusOffset); + data.PathTaperX = Primitive.UnpackPathTaper(block.PathTaperX); + data.PathTaperY = Primitive.UnpackPathTaper(block.PathTaperY); + data.PathRevolutions = Primitive.UnpackPathRevolutions(block.PathRevolutions); + data.PathSkew = Primitive.UnpackPathTwist(block.PathSkew); + data.ProfileBegin = Primitive.UnpackBeginCut(block.ProfileBegin); + data.ProfileEnd = Primitive.UnpackEndCut(block.ProfileEnd); + data.ProfileHollow = Primitive.UnpackProfileHollow(block.ProfileHollow); + data.PCode = pcode; + #endregion + + #region Decode Additional packed parameters in ObjectData + int pos = 0; + switch (block.ObjectData.Length) + { + case 76: + // Collision normal for avatar + objectupdate.CollisionPlane = new Vector4(block.ObjectData, pos); + pos += 16; + + goto case 60; + case 60: + // Position + objectupdate.Position = new Vector3(block.ObjectData, pos); + pos += 12; + // Velocity + objectupdate.Velocity = new Vector3(block.ObjectData, pos); + pos += 12; + // Acceleration + objectupdate.Acceleration = new Vector3(block.ObjectData, pos); + pos += 12; + // Rotation (theta) + objectupdate.Rotation = new Quaternion(block.ObjectData, pos, true); + pos += 12; + // Angular velocity (omega) + objectupdate.AngularVelocity = new Vector3(block.ObjectData, pos); + pos += 12; + + break; + case 48: + // Collision normal for avatar + objectupdate.CollisionPlane = new Vector4(block.ObjectData, pos); + pos += 16; + + goto case 32; + case 32: + // The data is an array of unsigned shorts + + // Position + objectupdate.Position = new Vector3( + Utils.UInt16ToFloat(block.ObjectData, pos, -0.5f * 256.0f, 1.5f * 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 2, -0.5f * 256.0f, 1.5f * 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 3.0f * 256.0f)); + pos += 6; + // Velocity + objectupdate.Velocity = new Vector3( + Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); + pos += 6; + // Acceleration + objectupdate.Acceleration = new Vector3( + Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); + pos += 6; + // Rotation (theta) + objectupdate.Rotation = new Quaternion( + Utils.UInt16ToFloat(block.ObjectData, pos, -1.0f, 1.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 4, -1.0f, 1.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 6, -1.0f, 1.0f)); + pos += 8; + // Angular velocity (omega) + objectupdate.AngularVelocity = new Vector3( + Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), + Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); + pos += 6; + + break; + case 16: + // The data is an array of single bytes (8-bit numbers) + + // Position + objectupdate.Position = new Vector3( + Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); + pos += 3; + // Velocity + objectupdate.Velocity = new Vector3( + Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); + pos += 3; + // Accleration + objectupdate.Acceleration = new Vector3( + Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); + pos += 3; + // Rotation + objectupdate.Rotation = new Quaternion( + Utils.ByteToFloat(block.ObjectData, pos, -1.0f, 1.0f), + Utils.ByteToFloat(block.ObjectData, pos + 1, -1.0f, 1.0f), + Utils.ByteToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), + Utils.ByteToFloat(block.ObjectData, pos + 3, -1.0f, 1.0f)); + pos += 4; + // Angular Velocity + objectupdate.AngularVelocity = new Vector3( + Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), + Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); + pos += 3; + + break; + default: + Logger.Log("Got an ObjectUpdate block with ObjectUpdate field length of " + + block.ObjectData.Length, Helpers.LogLevel.Warning, Client); + + continue; + } + #endregion + + // Determine the object type and create the appropriate class + switch (pcode) + { + #region Prim and Foliage + case PCode.Grass: + case PCode.Tree: + case PCode.NewTree: + case PCode.Prim: + + bool isNewObject; + lock (simulator.ObjectsPrimitives.Dictionary) + isNewObject = !simulator.ObjectsPrimitives.ContainsKey(block.ID); + + Primitive prim = GetPrimitive(simulator, block.ID, block.FullID); + + // Textures + objectupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, + block.TextureEntry.Length); + + OnObjectDataBlockUpdate(new ObjectDataBlockUpdateEventArgs(simulator, prim, data, block, objectupdate, nameValues)); + + #region Update Prim Info with decoded data + prim.Flags = (PrimFlags)block.UpdateFlags; + + if ((prim.Flags & PrimFlags.ZlibCompressed) != 0) + { + Logger.Log("Got a ZlibCompressed ObjectUpdate, implement me!", + Helpers.LogLevel.Warning, Client); + continue; + } + + // Automatically request ObjectProperties for prim if it was rezzed selected. + if ((prim.Flags & PrimFlags.CreateSelected) != 0) + { + SelectObject(simulator, prim.LocalID); + } + + prim.NameValues = nameValues; + prim.LocalID = block.ID; + prim.ID = block.FullID; + prim.ParentID = block.ParentID; + prim.RegionHandle = update.RegionData.RegionHandle; + prim.Scale = block.Scale; + prim.ClickAction = (ClickAction)block.ClickAction; + prim.OwnerID = block.OwnerID; + prim.MediaURL = Utils.BytesToString(block.MediaURL); + prim.Text = Utils.BytesToString(block.Text); + prim.TextColor = new Color4(block.TextColor, 0, false, true); + prim.IsAttachment = attachment; + + // Sound information + prim.Sound = block.Sound; + prim.SoundFlags = (SoundFlags)block.Flags; + prim.SoundGain = block.Gain; + prim.SoundRadius = block.Radius; + + // Joint information + prim.Joint = (JointType)block.JointType; + prim.JointPivot = block.JointPivot; + prim.JointAxisOrAnchor = block.JointAxisOrAnchor; + + // Object parameters + prim.PrimData = data; + + // Textures, texture animations, particle system, and extra params + prim.Textures = objectupdate.Textures; + + prim.TextureAnim = new Primitive.TextureAnimation(block.TextureAnim, 0); + prim.ParticleSys = new Primitive.ParticleSystem(block.PSBlock, 0); + prim.SetExtraParamsFromBytes(block.ExtraParams, 0); + + // PCode-specific data + switch (pcode) + { + case PCode.Grass: + case PCode.Tree: + case PCode.NewTree: + if (block.Data.Length == 1) + prim.TreeSpecies = (Tree)block.Data[0]; + else + Logger.Log("Got a foliage update with an invalid TreeSpecies field", Helpers.LogLevel.Warning); + // prim.ScratchPad = Utils.EmptyBytes; + // break; + //default: + // prim.ScratchPad = new byte[block.Data.Length]; + // if (block.Data.Length > 0) + // Buffer.BlockCopy(block.Data, 0, prim.ScratchPad, 0, prim.ScratchPad.Length); + break; + } + prim.ScratchPad = Utils.EmptyBytes; + + // Packed parameters + prim.CollisionPlane = objectupdate.CollisionPlane; + prim.Position = objectupdate.Position; + prim.Velocity = objectupdate.Velocity; + prim.Acceleration = objectupdate.Acceleration; + prim.Rotation = objectupdate.Rotation; + prim.AngularVelocity = objectupdate.AngularVelocity; + #endregion + + EventHandler handler = m_ObjectUpdate; + if (handler != null) + { + WorkPool.QueueUserWorkItem(delegate(object o) + { handler(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNewObject, attachment)); }); + } + //OnParticleUpdate handler replacing decode particles, PCode.Particle system appears to be deprecated this is a fix + if (prim.ParticleSys.PartMaxAge != 0) { + OnParticleUpdate(new ParticleUpdateEventArgs(simulator, prim.ParticleSys, prim)); + } + + break; + #endregion Prim and Foliage + #region Avatar + case PCode.Avatar: + + bool isNewAvatar; + lock (simulator.ObjectsAvatars.Dictionary) + isNewAvatar = !simulator.ObjectsAvatars.ContainsKey(block.ID); + + // Update some internals if this is our avatar + if (block.FullID == Client.Self.AgentID && simulator == Client.Network.CurrentSim) + { + #region Update Client.Self + + // We need the local ID to recognize terse updates for our agent + Client.Self.localID = block.ID; + + // Packed parameters + Client.Self.collisionPlane = objectupdate.CollisionPlane; + Client.Self.relativePosition = objectupdate.Position; + Client.Self.velocity = objectupdate.Velocity; + Client.Self.acceleration = objectupdate.Acceleration; + Client.Self.relativeRotation = objectupdate.Rotation; + Client.Self.angularVelocity = objectupdate.AngularVelocity; + + #endregion + } + + #region Create an Avatar from the decoded data + + Avatar avatar = GetAvatar(simulator, block.ID, block.FullID); + + objectupdate.Avatar = true; + // Textures + objectupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, + block.TextureEntry.Length); + + OnObjectDataBlockUpdate(new ObjectDataBlockUpdateEventArgs(simulator, avatar, data, block, objectupdate, nameValues)); + + uint oldSeatID = avatar.ParentID; + + avatar.ID = block.FullID; + avatar.LocalID = block.ID; + avatar.Scale = block.Scale; + avatar.CollisionPlane = objectupdate.CollisionPlane; + avatar.Position = objectupdate.Position; + avatar.Velocity = objectupdate.Velocity; + avatar.Acceleration = objectupdate.Acceleration; + avatar.Rotation = objectupdate.Rotation; + avatar.AngularVelocity = objectupdate.AngularVelocity; + avatar.NameValues = nameValues; + avatar.PrimData = data; + if (block.Data.Length > 0) + { + Logger.Log("Unexpected Data field for an avatar update, length " + block.Data.Length, Helpers.LogLevel.Warning); + } + avatar.ParentID = block.ParentID; + avatar.RegionHandle = update.RegionData.RegionHandle; + + SetAvatarSittingOn(simulator, avatar, block.ParentID, oldSeatID); + + // Textures + avatar.Textures = objectupdate.Textures; + + #endregion Create an Avatar from the decoded data + + OnAvatarUpdate(new AvatarUpdateEventArgs(simulator, avatar, update.RegionData.TimeDilation, isNewAvatar)); + + break; + #endregion Avatar + case PCode.ParticleSystem: + DecodeParticleUpdate(block); + break; + default: + Logger.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString(), Client); + break; + } + } + } + + protected void DecodeParticleUpdate(ObjectUpdatePacket.ObjectDataBlock block) + { + // TODO: Handle ParticleSystem ObjectUpdate blocks + // float bounce_b + // Vector4 scale_range + // Vector4 alpha_range + // Vector3 vel_offset + // float dist_begin_fadeout + // float dist_end_fadeout + // UUID image_uuid + // long flags + // byte createme + // Vector3 diff_eq_alpha + // Vector3 diff_eq_scale + // byte max_particles + // byte initial_particles + // float kill_plane_z + // Vector3 kill_plane_normal + // float bounce_plane_z + // Vector3 bounce_plane_normal + // float spawn_range + // float spawn_frequency + // float spawn_frequency_range + // Vector3 spawn_direction + // float spawn_direction_range + // float spawn_velocity + // float spawn_velocity_range + // float speed_limit + // float wind_weight + // Vector3 current_gravity + // float gravity_weight + // float global_lifetime + // float individual_lifetime + // float individual_lifetime_range + // float alpha_decay + // float scale_decay + // float distance_death + // float damp_motion_factor + // Vector3 wind_diffusion_factor + } + + /// + /// A terse object update, used when a transformation matrix or + /// velocity/acceleration for an object changes but nothing else + /// (scale/position/rotation/acceleration/velocity) + /// + /// The sender + /// The EventArgs object containing the packet data + protected void ImprovedTerseObjectUpdateHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)packet; + UpdateDilation(simulator, terse.RegionData.TimeDilation); + + for (int i = 0; i < terse.ObjectData.Length; i++) + { + ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = terse.ObjectData[i]; + + try + { + int pos = 4; + uint localid = Utils.BytesToUInt(block.Data, 0); + + // Check if we are interested in this update + if (!Client.Settings.ALWAYS_DECODE_OBJECTS + && localid != Client.Self.localID + && m_TerseObjectUpdate == null) + { + continue; + } + + #region Decode update data + + ObjectMovementUpdate update = new ObjectMovementUpdate(); + + // LocalID + update.LocalID = localid; + // State + update.State = block.Data[pos++]; + // Avatar boolean + update.Avatar = (block.Data[pos++] != 0); + // Collision normal for avatar + if (update.Avatar) + { + update.CollisionPlane = new Vector4(block.Data, pos); + pos += 16; + } + // Position + update.Position = new Vector3(block.Data, pos); + pos += 12; + // Velocity + update.Velocity = new Vector3( + Utils.UInt16ToFloat(block.Data, pos, -128.0f, 128.0f), + Utils.UInt16ToFloat(block.Data, pos + 2, -128.0f, 128.0f), + Utils.UInt16ToFloat(block.Data, pos + 4, -128.0f, 128.0f)); + pos += 6; + // Acceleration + update.Acceleration = new Vector3( + Utils.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f), + Utils.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f), + Utils.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f)); + pos += 6; + // Rotation (theta) + update.Rotation = new Quaternion( + Utils.UInt16ToFloat(block.Data, pos, -1.0f, 1.0f), + Utils.UInt16ToFloat(block.Data, pos + 2, -1.0f, 1.0f), + Utils.UInt16ToFloat(block.Data, pos + 4, -1.0f, 1.0f), + Utils.UInt16ToFloat(block.Data, pos + 6, -1.0f, 1.0f)); + pos += 8; + // Angular velocity (omega) + update.AngularVelocity = new Vector3( + Utils.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f), + Utils.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f), + Utils.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f)); + pos += 6; + + // Textures + // FIXME: Why are we ignoring the first four bytes here? + if (block.TextureEntry.Length != 0) + update.Textures = new Primitive.TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4); + + #endregion Decode update data + + Primitive obj = !Client.Settings.OBJECT_TRACKING ? null : (update.Avatar) ? + (Primitive)GetAvatar(simulator, update.LocalID, UUID.Zero) : + (Primitive)GetPrimitive(simulator, update.LocalID, UUID.Zero); + + // Fire the pre-emptive notice (before we stomp the object) + EventHandler handler = m_TerseObjectUpdate; + if (handler != null) + { + WorkPool.QueueUserWorkItem(delegate(object o) + { handler(this, new TerseObjectUpdateEventArgs(simulator, obj, update, terse.RegionData.TimeDilation)); }); + } + + #region Update Client.Self + if (update.LocalID == Client.Self.localID) + { + Client.Self.collisionPlane = update.CollisionPlane; + Client.Self.relativePosition = update.Position; + Client.Self.velocity = update.Velocity; + Client.Self.acceleration = update.Acceleration; + Client.Self.relativeRotation = update.Rotation; + Client.Self.angularVelocity = update.AngularVelocity; + } + #endregion Update Client.Self + if (Client.Settings.OBJECT_TRACKING && obj != null) + { + obj.Position = update.Position; + obj.Rotation = update.Rotation; + obj.Velocity = update.Velocity; + obj.CollisionPlane = update.CollisionPlane; + obj.Acceleration = update.Acceleration; + obj.AngularVelocity = update.AngularVelocity; + obj.PrimData.State = update.State; + if (update.Textures != null) + obj.Textures = update.Textures; + } + + } + catch (Exception ex) + { + Logger.Log(ex.Message, Helpers.LogLevel.Warning, Client, ex); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ObjectUpdateCompressedHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ObjectUpdateCompressedPacket update = (ObjectUpdateCompressedPacket)packet; + + for (int b = 0; b < update.ObjectData.Length; b++) + { + ObjectUpdateCompressedPacket.ObjectDataBlock block = update.ObjectData[b]; + int i = 0; + + try + { + // UUID + UUID FullID = new UUID(block.Data, 0); + i += 16; + // Local ID + uint LocalID = (uint)(block.Data[i++] + (block.Data[i++] << 8) + + (block.Data[i++] << 16) + (block.Data[i++] << 24)); + // PCode + PCode pcode = (PCode)block.Data[i++]; + + #region Relevance check + + if (!Client.Settings.ALWAYS_DECODE_OBJECTS) + { + switch (pcode) + { + case PCode.Grass: + case PCode.Tree: + case PCode.NewTree: + case PCode.Prim: + if (m_ObjectUpdate == null) continue; + break; + } + } + + #endregion Relevance check + + bool isNew; + lock (simulator.ObjectsPrimitives.Dictionary) + isNew = !simulator.ObjectsPrimitives.ContainsKey(LocalID); + + Primitive prim = GetPrimitive(simulator, LocalID, FullID); + + prim.LocalID = LocalID; + prim.ID = FullID; + prim.Flags = (PrimFlags)block.UpdateFlags; + prim.PrimData.PCode = pcode; + + #region Decode block and update Prim + + // State + prim.PrimData.State = block.Data[i++]; + // CRC + i += 4; + // Material + prim.PrimData.Material = (Material)block.Data[i++]; + // Click action + prim.ClickAction = (ClickAction)block.Data[i++]; + // Scale + prim.Scale = new Vector3(block.Data, i); + i += 12; + // Position + prim.Position = new Vector3(block.Data, i); + i += 12; + // Rotation + prim.Rotation = new Quaternion(block.Data, i, true); + i += 12; + // Compressed flags + CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block.Data, i); + i += 4; + + prim.OwnerID = new UUID(block.Data, i); + i += 16; + + // Angular velocity + if ((flags & CompressedFlags.HasAngularVelocity) != 0) + { + prim.AngularVelocity = new Vector3(block.Data, i); + i += 12; + } + + // Parent ID + if ((flags & CompressedFlags.HasParent) != 0) + { + prim.ParentID = (uint)(block.Data[i++] + (block.Data[i++] << 8) + + (block.Data[i++] << 16) + (block.Data[i++] << 24)); + } + else + { + prim.ParentID = 0; + } + + // Tree data + if ((flags & CompressedFlags.Tree) != 0) + { + prim.TreeSpecies = (Tree)block.Data[i++]; + //prim.ScratchPad = Utils.EmptyBytes; + } + // Scratch pad + else if ((flags & CompressedFlags.ScratchPad) != 0) + { + prim.TreeSpecies = (Tree)0; + + int size = block.Data[i++]; + //prim.ScratchPad = new byte[size]; + //Buffer.BlockCopy(block.Data, i, prim.ScratchPad, 0, size); + i += size; + } + prim.ScratchPad = Utils.EmptyBytes; + + // Floating text + if ((flags & CompressedFlags.HasText) != 0) + { + string text = String.Empty; + while (block.Data[i] != 0) + { + text += (char)block.Data[i]; + i++; + } + i++; + + // Floating text + prim.Text = text; + + // Text color + prim.TextColor = new Color4(block.Data, i, false); + i += 4; + } + else + { + prim.Text = String.Empty; + } + + // Media URL + if ((flags & CompressedFlags.MediaURL) != 0) + { + string text = String.Empty; + while (block.Data[i] != 0) + { + text += (char)block.Data[i]; + i++; + } + i++; + + prim.MediaURL = text; + } + + // Particle system + if ((flags & CompressedFlags.HasParticles) != 0) + { + prim.ParticleSys = new Primitive.ParticleSystem(block.Data, i); + i += 86; + } + + // Extra parameters + i += prim.SetExtraParamsFromBytes(block.Data, i); + + //Sound data + if ((flags & CompressedFlags.HasSound) != 0) + { + prim.Sound = new UUID(block.Data, i); + i += 16; + + prim.SoundGain = Utils.BytesToFloat(block.Data, i); + i += 4; + prim.SoundFlags = (SoundFlags)block.Data[i++]; + prim.SoundRadius = Utils.BytesToFloat(block.Data, i); + i += 4; + } + + // Name values + if ((flags & CompressedFlags.HasNameValues) != 0) + { + string text = String.Empty; + while (block.Data[i] != 0) + { + text += (char)block.Data[i]; + i++; + } + i++; + + // Parse the name values + if (text.Length > 0) + { + string[] lines = text.Split('\n'); + prim.NameValues = new NameValue[lines.Length]; + + for (int j = 0; j < lines.Length; j++) + { + if (!String.IsNullOrEmpty(lines[j])) + { + NameValue nv = new NameValue(lines[j]); + prim.NameValues[j] = nv; + } + } + } + } + + prim.PrimData.PathCurve = (PathCurve)block.Data[i++]; + ushort pathBegin = Utils.BytesToUInt16(block.Data, i); i += 2; + prim.PrimData.PathBegin = Primitive.UnpackBeginCut(pathBegin); + ushort pathEnd = Utils.BytesToUInt16(block.Data, i); i += 2; + prim.PrimData.PathEnd = Primitive.UnpackEndCut(pathEnd); + prim.PrimData.PathScaleX = Primitive.UnpackPathScale(block.Data[i++]); + prim.PrimData.PathScaleY = Primitive.UnpackPathScale(block.Data[i++]); + prim.PrimData.PathShearX = Primitive.UnpackPathShear((sbyte)block.Data[i++]); + prim.PrimData.PathShearY = Primitive.UnpackPathShear((sbyte)block.Data[i++]); + prim.PrimData.PathTwist = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); + prim.PrimData.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); + prim.PrimData.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); + prim.PrimData.PathTaperX = Primitive.UnpackPathTaper((sbyte)block.Data[i++]); + prim.PrimData.PathTaperY = Primitive.UnpackPathTaper((sbyte)block.Data[i++]); + prim.PrimData.PathRevolutions = Primitive.UnpackPathRevolutions(block.Data[i++]); + prim.PrimData.PathSkew = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); + + prim.PrimData.profileCurve = block.Data[i++]; + ushort profileBegin = Utils.BytesToUInt16(block.Data, i); i += 2; + prim.PrimData.ProfileBegin = Primitive.UnpackBeginCut(profileBegin); + ushort profileEnd = Utils.BytesToUInt16(block.Data, i); i += 2; + prim.PrimData.ProfileEnd = Primitive.UnpackEndCut(profileEnd); + ushort profileHollow = Utils.BytesToUInt16(block.Data, i); i += 2; + prim.PrimData.ProfileHollow = Primitive.UnpackProfileHollow(profileHollow); + + // TextureEntry + int textureEntryLength = (int)Utils.BytesToUInt(block.Data, i); + i += 4; + prim.Textures = new Primitive.TextureEntry(block.Data, i, textureEntryLength); + i += textureEntryLength; + + // Texture animation + if ((flags & CompressedFlags.TextureAnimation) != 0) + { + //int textureAnimLength = (int)Utils.BytesToUIntBig(block.Data, i); + i += 4; + prim.TextureAnim = new Primitive.TextureAnimation(block.Data, i); + } + + #endregion + + prim.IsAttachment = (flags & CompressedFlags.HasNameValues) != 0 && prim.ParentID != 0; + + #region Raise Events + + EventHandler handler = m_ObjectUpdate; + if (handler != null) + handler(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNew, prim.IsAttachment)); + + #endregion + } + catch (IndexOutOfRangeException ex) + { + Logger.Log("Error decoding an ObjectUpdateCompressed packet", Helpers.LogLevel.Warning, Client, ex); + Logger.Log(block, Helpers.LogLevel.Warning); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ObjectUpdateCachedHandler(object sender, PacketReceivedEventArgs e) + { + if (Client.Settings.ALWAYS_REQUEST_OBJECTS) + { + bool cachedPrimitives = Client.Settings.CACHE_PRIMITIVES; + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ObjectUpdateCachedPacket update = (ObjectUpdateCachedPacket)packet; + List ids = new List(update.ObjectData.Length); + + // Object caching is implemented when Client.Settings.PRIMITIVES_FACTORY is True, otherwise request updates for all of these objects + for (int i = 0; i < update.ObjectData.Length; i++) + { + uint localID = update.ObjectData[i].ID; + + if (cachedPrimitives) + { + if (!simulator.DataPool.NeedsRequest(localID)) + { + continue; + } + } + ids.Add(localID); + } + RequestObjects(simulator, ids); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void KillObjectHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + KillObjectPacket kill = (KillObjectPacket)packet; + + // Notify first, so that handler has a chance to get a + // reference from the ObjectTracker to the object being killed + uint[] killed = new uint[kill.ObjectData.Length]; + for (int i = 0; i < kill.ObjectData.Length; i++) + { + OnKillObject(new KillObjectEventArgs(simulator, kill.ObjectData[i].ID)); + killed[i] = kill.ObjectData[i].ID; + } + OnKillObjects(new KillObjectsEventArgs(e.Simulator, killed)); + + + lock (simulator.ObjectsPrimitives.Dictionary) + { + List removeAvatars = new List(); + List removePrims = new List(); + + if (Client.Settings.OBJECT_TRACKING) + { + uint localID; + for (int i = 0; i < kill.ObjectData.Length; i++) + { + localID = kill.ObjectData[i].ID; + + if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(localID)) + removePrims.Add(localID); + + foreach (KeyValuePair prim in simulator.ObjectsPrimitives.Dictionary) + { + if (prim.Value.ParentID == localID) + { + OnKillObject(new KillObjectEventArgs(simulator, prim.Key)); + removePrims.Add(prim.Key); + } + } + } + } + + if (Client.Settings.AVATAR_TRACKING) + { + lock (simulator.ObjectsAvatars.Dictionary) + { + uint localID; + for (int i = 0; i < kill.ObjectData.Length; i++) + { + localID = kill.ObjectData[i].ID; + + if (simulator.ObjectsAvatars.Dictionary.ContainsKey(localID)) + removeAvatars.Add(localID); + + List rootPrims = new List(); + + foreach (KeyValuePair prim in simulator.ObjectsPrimitives.Dictionary) + { + if (prim.Value.ParentID == localID) + { + OnKillObject(new KillObjectEventArgs(simulator, prim.Key)); + removePrims.Add(prim.Key); + rootPrims.Add(prim.Key); + } + } + + foreach (KeyValuePair prim in simulator.ObjectsPrimitives.Dictionary) + { + if (rootPrims.Contains(prim.Value.ParentID)) + { + OnKillObject(new KillObjectEventArgs(simulator, prim.Key)); + removePrims.Add(prim.Key); + } + } + } + + //Do the actual removing outside of the loops but still inside the lock. + //This safely prevents the collection from being modified during a loop. + foreach (uint removeID in removeAvatars) + simulator.ObjectsAvatars.Dictionary.Remove(removeID); + } + } + + if (Client.Settings.CACHE_PRIMITIVES) + { + simulator.DataPool.ReleasePrims(removePrims); + } + foreach (uint removeID in removePrims) + simulator.ObjectsPrimitives.Dictionary.Remove(removeID); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ObjectPropertiesHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ObjectPropertiesPacket op = (ObjectPropertiesPacket)packet; + ObjectPropertiesPacket.ObjectDataBlock[] datablocks = op.ObjectData; + + for (int i = 0; i < datablocks.Length; ++i) + { + ObjectPropertiesPacket.ObjectDataBlock objectData = datablocks[i]; + Primitive.ObjectProperties props = new Primitive.ObjectProperties(); + + props.ObjectID = objectData.ObjectID; + props.AggregatePerms = objectData.AggregatePerms; + props.AggregatePermTextures = objectData.AggregatePermTextures; + props.AggregatePermTexturesOwner = objectData.AggregatePermTexturesOwner; + props.Permissions = new Permissions(objectData.BaseMask, objectData.EveryoneMask, objectData.GroupMask, + objectData.NextOwnerMask, objectData.OwnerMask); + props.Category = (ObjectCategory)objectData.Category; + props.CreationDate = Utils.UnixTimeToDateTime((uint)objectData.CreationDate); + props.CreatorID = objectData.CreatorID; + props.Description = Utils.BytesToString(objectData.Description); + props.FolderID = objectData.FolderID; + props.FromTaskID = objectData.FromTaskID; + props.GroupID = objectData.GroupID; + props.InventorySerial = objectData.InventorySerial; + props.ItemID = objectData.ItemID; + props.LastOwnerID = objectData.LastOwnerID; + props.Name = Utils.BytesToString(objectData.Name); + props.OwnerID = objectData.OwnerID; + props.OwnershipCost = objectData.OwnershipCost; + props.SalePrice = objectData.SalePrice; + props.SaleType = (SaleType)objectData.SaleType; + props.SitName = Utils.BytesToString(objectData.SitName); + props.TouchName = Utils.BytesToString(objectData.TouchName); + + int numTextures = objectData.TextureID.Length / 16; + props.TextureIDs = new UUID[numTextures]; + for (int j = 0; j < numTextures; ++j) + props.TextureIDs[j] = new UUID(objectData.TextureID, j * 16); + + if (Client.Settings.OBJECT_TRACKING) + { + Primitive findPrim = simulator.ObjectsPrimitives.Find( + delegate(Primitive prim) { return prim.ID == props.ObjectID; }); + + if (findPrim != null) + { + OnObjectPropertiesUpdated(new ObjectPropertiesUpdatedEventArgs(simulator, findPrim, props)); + + lock (simulator.ObjectsPrimitives.Dictionary) + { + if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(findPrim.LocalID)) + simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties = props; + } + } + } + + OnObjectProperties(new ObjectPropertiesEventArgs(simulator, props)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ObjectPropertiesFamilyHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ObjectPropertiesFamilyPacket op = (ObjectPropertiesFamilyPacket)packet; + Primitive.ObjectProperties props = new Primitive.ObjectProperties(); + + ReportType requestType = (ReportType)op.ObjectData.RequestFlags; + + props.ObjectID = op.ObjectData.ObjectID; + props.Category = (ObjectCategory)op.ObjectData.Category; + props.Description = Utils.BytesToString(op.ObjectData.Description); + props.GroupID = op.ObjectData.GroupID; + props.LastOwnerID = op.ObjectData.LastOwnerID; + props.Name = Utils.BytesToString(op.ObjectData.Name); + props.OwnerID = op.ObjectData.OwnerID; + props.OwnershipCost = op.ObjectData.OwnershipCost; + props.SalePrice = op.ObjectData.SalePrice; + props.SaleType = (SaleType)op.ObjectData.SaleType; + props.Permissions.BaseMask = (PermissionMask)op.ObjectData.BaseMask; + props.Permissions.EveryoneMask = (PermissionMask)op.ObjectData.EveryoneMask; + props.Permissions.GroupMask = (PermissionMask)op.ObjectData.GroupMask; + props.Permissions.NextOwnerMask = (PermissionMask)op.ObjectData.NextOwnerMask; + props.Permissions.OwnerMask = (PermissionMask)op.ObjectData.OwnerMask; + + if (Client.Settings.OBJECT_TRACKING) + { + Primitive findPrim = simulator.ObjectsPrimitives.Find( + delegate(Primitive prim) { return prim.ID == op.ObjectData.ObjectID; }); + + if (findPrim != null) + { + lock (simulator.ObjectsPrimitives.Dictionary) + { + if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(findPrim.LocalID)) + { + if (simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties == null) + simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties = new Primitive.ObjectProperties(); + simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties.SetFamilyProperties(props); + } + } + } + } + + OnObjectPropertiesFamily(new ObjectPropertiesFamilyEventArgs(simulator, props, requestType)); + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void PayPriceReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_PayPriceReply != null) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + PayPriceReplyPacket p = (PayPriceReplyPacket)packet; + UUID objectID = p.ObjectData.ObjectID; + int defaultPrice = p.ObjectData.DefaultPayPrice; + int[] buttonPrices = new int[p.ButtonData.Length]; + + for (int i = 0; i < p.ButtonData.Length; i++) + { + buttonPrices[i] = p.ButtonData[i].PayButton; + } + + OnPayPriceReply(new PayPriceReplyEventArgs(simulator, objectID, defaultPrice, buttonPrices)); + } + } + + /// + /// + /// + /// + /// + /// + protected void ObjectPhysicsPropertiesHandler(string capsKey, IMessage message, Simulator simulator) + { + ObjectPhysicsPropertiesMessage msg = (ObjectPhysicsPropertiesMessage)message; + + if (Client.Settings.OBJECT_TRACKING) + { + for (int i = 0; i < msg.ObjectPhysicsProperties.Length; i++) + { + lock (simulator.ObjectsPrimitives.Dictionary) + { + if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(msg.ObjectPhysicsProperties[i].LocalID)) + { + simulator.ObjectsPrimitives.Dictionary[msg.ObjectPhysicsProperties[i].LocalID].PhysicsProps = msg.ObjectPhysicsProperties[i]; + } + } + } + } + + if (m_PhysicsProperties != null) + { + for (int i = 0; i < msg.ObjectPhysicsProperties.Length; i++) + { + OnPhysicsProperties(new PhysicsPropertiesEventArgs(simulator, msg.ObjectPhysicsProperties[i])); + } + } + } + + #endregion Packet Handlers + + #region Utility Functions + + /// + /// Setup construction data for a basic primitive shape + /// + /// Primitive shape to construct + /// Construction data that can be plugged into a + public static Primitive.ConstructionData BuildBasicShape(PrimType type) + { + Primitive.ConstructionData prim = new Primitive.ConstructionData(); + prim.PCode = PCode.Prim; + prim.Material = Material.Wood; + + switch (type) + { + case PrimType.Box: + prim.ProfileCurve = ProfileCurve.Square; + prim.PathCurve = PathCurve.Line; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 1f; + prim.PathScaleY = 1f; + prim.PathRevolutions = 1f; + break; + case PrimType.Cylinder: + prim.ProfileCurve = ProfileCurve.Circle; + prim.PathCurve = PathCurve.Line; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 1f; + prim.PathScaleY = 1f; + prim.PathRevolutions = 1f; + break; + case PrimType.Prism: + prim.ProfileCurve = ProfileCurve.EqualTriangle; + prim.PathCurve = PathCurve.Line; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 0f; + prim.PathScaleY = 0f; + prim.PathRevolutions = 1f; + break; + case PrimType.Ring: + prim.ProfileCurve = ProfileCurve.EqualTriangle; + prim.PathCurve = PathCurve.Circle; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 1f; + prim.PathScaleY = 0.25f; + prim.PathRevolutions = 1f; + break; + case PrimType.Sphere: + prim.ProfileCurve = ProfileCurve.HalfCircle; + prim.PathCurve = PathCurve.Circle; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 1f; + prim.PathScaleY = 1f; + prim.PathRevolutions = 1f; + break; + case PrimType.Torus: + prim.ProfileCurve = ProfileCurve.Circle; + prim.PathCurve = PathCurve.Circle; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 1f; + prim.PathScaleY = 0.25f; + prim.PathRevolutions = 1f; + break; + case PrimType.Tube: + prim.ProfileCurve = ProfileCurve.Square; + prim.PathCurve = PathCurve.Circle; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 1f; + prim.PathScaleY = 0.25f; + prim.PathRevolutions = 1f; + break; + case PrimType.Sculpt: + prim.ProfileCurve = ProfileCurve.Circle; + prim.PathCurve = PathCurve.Circle; + prim.ProfileEnd = 1f; + prim.PathEnd = 1f; + prim.PathScaleX = 1f; + prim.PathScaleY = 0.5f; + prim.PathRevolutions = 1f; + break; + default: + throw new NotSupportedException("Unsupported shape: " + type.ToString()); + } + + return prim; + } + + /// + /// + /// + /// + /// + /// + /// + protected void SetAvatarSittingOn(Simulator sim, Avatar av, uint localid, uint oldSeatID) + { + if (Client.Network.CurrentSim == sim && av.LocalID == Client.Self.localID) + { + Client.Self.sittingOn = localid; + } + + av.ParentID = localid; + + + if (m_AvatarSitChanged != null && oldSeatID != localid) + { + OnAvatarSitChanged(new AvatarSitChangedEventArgs(sim, av, localid, oldSeatID)); + } + } + + /// + /// + /// + /// + /// + protected void UpdateDilation(Simulator s, uint dilation) + { + s.Stats.Dilation = (float)dilation / 65535.0f; + } + + + /// + /// Set the Shape data of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// Data describing the prim shape + public void SetShape(Simulator simulator, uint localID, Primitive.ConstructionData prim) + { + ObjectShapePacket shape = new ObjectShapePacket(); + + shape.AgentData.AgentID = Client.Self.AgentID; + shape.AgentData.SessionID = Client.Self.SessionID; + + shape.ObjectData = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock[1]; + shape.ObjectData[0] = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock(); + + shape.ObjectData[0].ObjectLocalID = localID; + + shape.ObjectData[0].PathCurve = (byte)prim.PathCurve; + shape.ObjectData[0].PathBegin = Primitive.PackBeginCut(prim.PathBegin); + shape.ObjectData[0].PathEnd = Primitive.PackEndCut(prim.PathEnd); + shape.ObjectData[0].PathScaleX = Primitive.PackPathScale(prim.PathScaleX); + shape.ObjectData[0].PathScaleY = Primitive.PackPathScale(prim.PathScaleY); + shape.ObjectData[0].PathShearX = (byte)Primitive.PackPathShear(prim.PathShearX); + shape.ObjectData[0].PathShearY = (byte)Primitive.PackPathShear(prim.PathShearY); + shape.ObjectData[0].PathTwist = Primitive.PackPathTwist(prim.PathTwist); + shape.ObjectData[0].PathTwistBegin = Primitive.PackPathTwist(prim.PathTwistBegin); + shape.ObjectData[0].PathRadiusOffset = Primitive.PackPathTwist(prim.PathRadiusOffset); + shape.ObjectData[0].PathTaperX = Primitive.PackPathTaper(prim.PathTaperX); + shape.ObjectData[0].PathTaperY = Primitive.PackPathTaper(prim.PathTaperY); + shape.ObjectData[0].PathRevolutions = Primitive.PackPathRevolutions(prim.PathRevolutions); + shape.ObjectData[0].PathSkew = Primitive.PackPathTwist(prim.PathSkew); + + shape.ObjectData[0].ProfileCurve = prim.profileCurve; + shape.ObjectData[0].ProfileBegin = Primitive.PackBeginCut(prim.ProfileBegin); + shape.ObjectData[0].ProfileEnd = Primitive.PackEndCut(prim.ProfileEnd); + shape.ObjectData[0].ProfileHollow = Primitive.PackProfileHollow(prim.ProfileHollow); + + Client.Network.SendPacket(shape, simulator); + } + + /// + /// Set the Material data of an object + /// + /// A reference to the object where the object resides + /// The objects ID which is local to the simulator the object is in + /// The new material of the object + public void SetMaterial(Simulator simulator, uint localID, Material material) + { + ObjectMaterialPacket matPacket = new ObjectMaterialPacket(); + + matPacket.AgentData.AgentID = Client.Self.AgentID; + matPacket.AgentData.SessionID = Client.Self.SessionID; + + matPacket.ObjectData = new ObjectMaterialPacket.ObjectDataBlock[1]; + matPacket.ObjectData[0] = new ObjectMaterialPacket.ObjectDataBlock(); + + matPacket.ObjectData[0].ObjectLocalID = localID; + matPacket.ObjectData[0].Material = (byte)material; + + Client.Network.SendPacket(matPacket, simulator); + } + + + #endregion Utility Functions + + #region Object Tracking Link + + /// + /// + /// + /// + /// + /// + /// + protected Primitive GetPrimitive(Simulator simulator, uint localID, UUID fullID) + { + return GetPrimitive(simulator, localID, fullID, true); + } + /// + /// + /// + /// + /// + /// + /// + /// + public Primitive GetPrimitive(Simulator simulator, uint localID, UUID fullID, bool createIfMissing) + { + if (Client.Settings.OBJECT_TRACKING) + { + lock (simulator.ObjectsPrimitives.Dictionary) + { + + Primitive prim; + + if (simulator.ObjectsPrimitives.Dictionary.TryGetValue(localID, out prim)) + { + return prim; + } + else + { + if (!createIfMissing) return null; + if (Client.Settings.CACHE_PRIMITIVES) + { + prim = simulator.DataPool.MakePrimitive(localID); + } + else + { + prim = new Primitive(); + prim.LocalID = localID; + prim.RegionHandle = simulator.Handle; + } + prim.ActiveClients++; + prim.ID = fullID; + + simulator.ObjectsPrimitives.Dictionary[localID] = prim; + + return prim; + } + } + } + else + { + return new Primitive(); + } + } + + /// + /// + /// + /// + /// + /// + /// + protected Avatar GetAvatar(Simulator simulator, uint localID, UUID fullID) + { + if (Client.Settings.AVATAR_TRACKING) + { + lock (simulator.ObjectsAvatars.Dictionary) + { + + Avatar avatar; + + if (simulator.ObjectsAvatars.Dictionary.TryGetValue(localID, out avatar)) + { + return avatar; + } + else + { + avatar = new Avatar(); + avatar.LocalID = localID; + avatar.ID = fullID; + avatar.RegionHandle = simulator.Handle; + + simulator.ObjectsAvatars.Dictionary[localID] = avatar; + + return avatar; + } + } + } + else + { + return new Avatar(); + } + } + + #endregion Object Tracking Link + + protected void InterpolationTimer_Elapsed(object obj) + { + int elapsed = 0; + + if (Client.Network.Connected) + { + int start = Environment.TickCount; + + int interval = Environment.TickCount - Client.Self.lastInterpolation; + float seconds = (float)interval / 1000f; + + // Iterate through all of the simulators + Simulator[] sims = Client.Network.Simulators.ToArray(); + for (int i = 0; i < sims.Length; i++) + { + Simulator sim = sims[i]; + + float adjSeconds = seconds * sim.Stats.Dilation; + + // Iterate through all of this sims avatars + sim.ObjectsAvatars.ForEach( + delegate(Avatar avatar) + { + #region Linear Motion + // Only do movement interpolation (extrapolation) when there is a non-zero velocity but + // no acceleration + if (avatar.Acceleration != Vector3.Zero && avatar.Velocity == Vector3.Zero) + { + avatar.Position += (avatar.Velocity + avatar.Acceleration * + (0.5f * (adjSeconds - HAVOK_TIMESTEP))) * adjSeconds; + avatar.Velocity += avatar.Acceleration * adjSeconds; + } + #endregion Linear Motion + } + ); + + // Iterate through all of this sims primitives + sim.ObjectsPrimitives.ForEach( + delegate(Primitive prim) + { + if (prim.Joint == JointType.Invalid) + { + #region Angular Velocity + Vector3 angVel = prim.AngularVelocity; + float omega = angVel.LengthSquared(); + + if (omega > 0.00001f) + { + omega = (float)Math.Sqrt(omega); + float angle = omega * adjSeconds; + angVel *= 1.0f / omega; + Quaternion dQ = Quaternion.CreateFromAxisAngle(angVel, angle); + + prim.Rotation *= dQ; + } + #endregion Angular Velocity + + #region Linear Motion + // Only do movement interpolation (extrapolation) when there is a non-zero velocity but + // no acceleration + if (prim.Acceleration != Vector3.Zero && prim.Velocity == Vector3.Zero) + { + prim.Position += (prim.Velocity + prim.Acceleration * + (0.5f * (adjSeconds - HAVOK_TIMESTEP))) * adjSeconds; + prim.Velocity += prim.Acceleration * adjSeconds; + } + #endregion Linear Motion + } + else if (prim.Joint == JointType.Hinge) + { + //FIXME: Hinge movement extrapolation + } + else if (prim.Joint == JointType.Point) + { + //FIXME: Point movement extrapolation + } + else + { + Logger.Log("Unhandled joint type " + prim.Joint, Helpers.LogLevel.Warning, Client); + } + } + ); + } + + // Make sure the last interpolated time is always updated + Client.Self.lastInterpolation = Environment.TickCount; + + elapsed = Client.Self.lastInterpolation - start; + } + + // Start the timer again. Use a minimum of a 50ms pause in between calculations + int delay = Math.Max(50, Settings.INTERPOLATION_INTERVAL - elapsed); + if (InterpolationTimer != null) + { + InterpolationTimer.Change(delay, Timeout.Infinite); + } + + } + } + #region EventArgs classes + + /// Provides data for the event + /// The event occurs when the simulator sends + /// an containing a Primitive, Foliage or Attachment data + /// Note 1: The event will not be raised when the object is an Avatar + /// Note 2: It is possible for the to be + /// raised twice for the same object if for example the primitive moved to a new simulator, then returned to the current simulator or + /// if an Avatar crosses the border into a new simulator and returns to the current simulator + /// + /// + /// The following code example uses the , , and + /// properties to display new Primitives and Attachments on the window. + /// + /// // Subscribe to the event that gives us prim and foliage information + /// Client.Objects.ObjectUpdate += Objects_ObjectUpdate; + /// + /// + /// private void Objects_ObjectUpdate(object sender, PrimEventArgs e) + /// { + /// Console.WriteLine("Primitive {0} {1} in {2} is an attachment {3}", e.Prim.ID, e.Prim.LocalID, e.Simulator.Name, e.IsAttachment); + /// } + /// + /// + /// + /// + /// + public class PrimEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly bool m_IsNew; + private readonly bool m_IsAttachment; + private readonly Primitive m_Prim; + private readonly ushort m_TimeDilation; + + /// Get the simulator the originated from + public Simulator Simulator { get { return m_Simulator; } } + /// Get the details + public Primitive Prim { get { return m_Prim; } } + /// true if the did not exist in the dictionary before this update (always true if object tracking has been disabled) + public bool IsNew { get { return m_IsNew; } } + /// true if the is attached to an + public bool IsAttachment { get { return m_IsAttachment; } } + /// Get the simulator Time Dilation + public ushort TimeDilation { get { return m_TimeDilation; } } + + /// + /// Construct a new instance of the PrimEventArgs class + /// + /// The simulator the object originated from + /// The Primitive + /// The simulator time dilation + /// The prim was not in the dictionary before this update + /// true if the primitive represents an attachment to an agent + public PrimEventArgs(Simulator simulator, Primitive prim, ushort timeDilation, bool isNew, bool isAttachment) + { + this.m_Simulator = simulator; + this.m_IsNew = isNew; + this.m_IsAttachment = isAttachment; + this.m_Prim = prim; + this.m_TimeDilation = timeDilation; + } + } + + /// Provides data for the event + /// The event occurs when the simulator sends + /// an containing Avatar data + /// Note 1: The event will not be raised when the object is an Avatar + /// Note 2: It is possible for the to be + /// raised twice for the same avatar if for example the avatar moved to a new simulator, then returned to the current simulator + /// + /// + /// The following code example uses the property to make a request for the top picks + /// using the method in the class to display the names + /// of our own agents picks listings on the window. + /// + /// // subscribe to the AvatarUpdate event to get our information + /// Client.Objects.AvatarUpdate += Objects_AvatarUpdate; + /// Client.Avatars.AvatarPicksReply += Avatars_AvatarPicksReply; + /// + /// private void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e) + /// { + /// // we only want our own data + /// if (e.Avatar.LocalID == Client.Self.LocalID) + /// { + /// // Unsubscribe from the avatar update event to prevent a loop + /// // where we continually request the picks every time we get an update for ourselves + /// Client.Objects.AvatarUpdate -= Objects_AvatarUpdate; + /// // make the top picks request through AvatarManager + /// Client.Avatars.RequestAvatarPicks(e.Avatar.ID); + /// } + /// } + /// + /// private void Avatars_AvatarPicksReply(object sender, AvatarPicksReplyEventArgs e) + /// { + /// // we'll unsubscribe from the AvatarPicksReply event since we now have the data + /// // we were looking for + /// Client.Avatars.AvatarPicksReply -= Avatars_AvatarPicksReply; + /// // loop through the dictionary and extract the names of the top picks from our profile + /// foreach (var pickName in e.Picks.Values) + /// { + /// Console.WriteLine(pickName); + /// } + /// } + /// + /// + /// + /// + public class AvatarUpdateEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly Avatar m_Avatar; + private readonly ushort m_TimeDilation; + private readonly bool m_IsNew; + + /// Get the simulator the object originated from + public Simulator Simulator { get { return m_Simulator; } } + /// Get the data + public Avatar Avatar { get { return m_Avatar; } } + /// Get the simulator time dilation + public ushort TimeDilation { get { return m_TimeDilation; } } + /// true if the did not exist in the dictionary before this update (always true if avatar tracking has been disabled) + public bool IsNew { get { return m_IsNew; } } + + /// + /// Construct a new instance of the AvatarUpdateEventArgs class + /// + /// The simulator the packet originated from + /// The data + /// The simulator time dilation + /// The avatar was not in the dictionary before this update + public AvatarUpdateEventArgs(Simulator simulator, Avatar avatar, ushort timeDilation, bool isNew) + { + this.m_Simulator = simulator; + this.m_Avatar = avatar; + this.m_TimeDilation = timeDilation; + this.m_IsNew = isNew; + } + } + + public class ParticleUpdateEventArgs : EventArgs { + private readonly Simulator m_Simulator; + private readonly Primitive.ParticleSystem m_ParticleSystem; + private readonly Primitive m_Source; + + /// Get the simulator the object originated from + public Simulator Simulator { get { return m_Simulator; } } + /// Get the data + public Primitive.ParticleSystem ParticleSystem { get { return m_ParticleSystem; } } + /// Get source + public Primitive Source { get { return m_Source; } } + + /// + /// Construct a new instance of the ParticleUpdateEventArgs class + /// + /// The simulator the packet originated from + /// The ParticleSystem data + /// The Primitive source + public ParticleUpdateEventArgs(Simulator simulator, Primitive.ParticleSystem particlesystem, Primitive source) { + this.m_Simulator = simulator; + this.m_ParticleSystem = particlesystem; + this.m_Source = source; + } + } + + /// Provides additional primitive data for the event + /// The event occurs when the simulator sends + /// an containing additional details for a Primitive, Foliage data or Attachment data + /// The event is also raised when a request is + /// made. + /// + /// + /// The following code example uses the , and + /// + /// properties to display new attachments and send a request for additional properties containing the name of the + /// attachment then display it on the window. + /// + /// // Subscribe to the event that provides additional primitive details + /// Client.Objects.ObjectProperties += Objects_ObjectProperties; + /// + /// // handle the properties data that arrives + /// private void Objects_ObjectProperties(object sender, ObjectPropertiesEventArgs e) + /// { + /// Console.WriteLine("Primitive Properties: {0} Name is {1}", e.Properties.ObjectID, e.Properties.Name); + /// } + /// + /// + public class ObjectPropertiesEventArgs : EventArgs + { + protected readonly Simulator m_Simulator; + protected readonly Primitive.ObjectProperties m_Properties; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// Get the primitive properties + public Primitive.ObjectProperties Properties { get { return m_Properties; } } + + /// + /// Construct a new instance of the ObjectPropertiesEventArgs class + /// + /// The simulator the object is located + /// The primitive Properties + public ObjectPropertiesEventArgs(Simulator simulator, Primitive.ObjectProperties props) + { + this.m_Simulator = simulator; + this.m_Properties = props; + } + } + + /// Provides additional primitive data for the event + /// The event occurs when the simulator sends + /// an containing additional details for a Primitive or Foliage data that is currently + /// being tracked in the dictionary + /// The event is also raised when a request is + /// made and is enabled + /// + public class ObjectPropertiesUpdatedEventArgs : ObjectPropertiesEventArgs + { + + private readonly Primitive m_Prim; + + /// Get the primitive details + public Primitive Prim { get { return m_Prim; } } + + /// + /// Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class + /// + /// The simulator the object is located + /// The Primitive + /// The primitive Properties + public ObjectPropertiesUpdatedEventArgs(Simulator simulator, Primitive prim, Primitive.ObjectProperties props) : base(simulator, props) + { + this.m_Prim = prim; + } + } + + /// Provides additional primitive data, permissions and sale info for the event + /// The event occurs when the simulator sends + /// an containing additional details for a Primitive, Foliage data or Attachment. This includes + /// Permissions, Sale info, and other basic details on an object + /// The event is also raised when a request is + /// made, the viewer equivalent is hovering the mouse cursor over an object + /// + public class ObjectPropertiesFamilyEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly Primitive.ObjectProperties m_Properties; + private readonly ReportType m_Type; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// + public Primitive.ObjectProperties Properties { get { return m_Properties; } } + /// + public ReportType Type { get { return m_Type; } } + + public ObjectPropertiesFamilyEventArgs(Simulator simulator, Primitive.ObjectProperties props, ReportType type) + { + this.m_Simulator = simulator; + this.m_Properties = props; + this.m_Type = type; + } + } + + /// Provides primitive data containing updated location, velocity, rotation, textures for the event + /// The event occurs when the simulator sends updated location, velocity, rotation, etc + /// + public class TerseObjectUpdateEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly Primitive m_Prim; + private readonly ObjectMovementUpdate m_Update; + private readonly ushort m_TimeDilation; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// Get the primitive details + public Primitive Prim { get { return m_Prim; } } + /// + public ObjectMovementUpdate Update { get { return m_Update; } } + /// + public ushort TimeDilation { get { return m_TimeDilation; } } + + public TerseObjectUpdateEventArgs(Simulator simulator, Primitive prim, ObjectMovementUpdate update, ushort timeDilation) + { + this.m_Simulator = simulator; + this.m_Prim = prim; + this.m_Update = update; + this.m_TimeDilation = timeDilation; + } + } + + /// + /// + /// + public class ObjectDataBlockUpdateEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly Primitive m_Prim; + private readonly Primitive.ConstructionData m_ConstructionData; + private readonly ObjectUpdatePacket.ObjectDataBlock m_Block; + private readonly ObjectMovementUpdate m_Update; + private readonly NameValue[] m_NameValues; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// Get the primitive details + public Primitive Prim { get { return m_Prim; } } + /// + public Primitive.ConstructionData ConstructionData { get { return m_ConstructionData; } } + /// + public ObjectUpdatePacket.ObjectDataBlock Block { get { return m_Block; } } + /// + public ObjectMovementUpdate Update { get { return m_Update; } } + /// + public NameValue[] NameValues { get { return m_NameValues; } } + + public ObjectDataBlockUpdateEventArgs(Simulator simulator, Primitive prim, Primitive.ConstructionData constructionData, + ObjectUpdatePacket.ObjectDataBlock block, ObjectMovementUpdate objectupdate, NameValue[] nameValues) + { + this.m_Simulator = simulator; + this.m_Prim = prim; + this.m_ConstructionData = constructionData; + this.m_Block = block; + this.m_Update = objectupdate; + this.m_NameValues = nameValues; + } + } + + /// Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the + /// event + public class KillObjectEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly uint m_ObjectLocalID; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// The LocalID of the object + public uint ObjectLocalID { get { return m_ObjectLocalID; } } + + public KillObjectEventArgs(Simulator simulator, uint objectID) + { + this.m_Simulator = simulator; + this.m_ObjectLocalID = objectID; + } + } + + /// Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the + /// event + public class KillObjectsEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly uint[] m_ObjectLocalIDs; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// The LocalID of the object + public uint[] ObjectLocalIDs { get { return m_ObjectLocalIDs; } } + + public KillObjectsEventArgs(Simulator simulator, uint[] objectIDs) + { + this.m_Simulator = simulator; + this.m_ObjectLocalIDs = objectIDs; + } + } + + /// + /// Provides updates sit position data + /// + public class AvatarSitChangedEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly Avatar m_Avatar; + private readonly uint m_SittingOn; + private readonly uint m_OldSeat; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// + public Avatar Avatar { get { return m_Avatar; } } + /// + public uint SittingOn { get { return m_SittingOn; } } + /// + public uint OldSeat { get { return m_OldSeat; } } + + public AvatarSitChangedEventArgs(Simulator simulator, Avatar avatar, uint sittingOn, uint oldSeat) + { + this.m_Simulator = simulator; + this.m_Avatar = avatar; + this.m_SittingOn = sittingOn; + this.m_OldSeat = oldSeat; + } + } + + /// + /// + /// + public class PayPriceReplyEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly UUID m_ObjectID; + private readonly int m_DefaultPrice; + private readonly int[] m_ButtonPrices; + + /// Get the simulator the object is located + public Simulator Simulator { get { return m_Simulator; } } + /// + public UUID ObjectID { get { return m_ObjectID; } } + /// + public int DefaultPrice { get { return m_DefaultPrice; } } + /// + public int[] ButtonPrices { get { return m_ButtonPrices; } } + + public PayPriceReplyEventArgs(Simulator simulator, UUID objectID, int defaultPrice, int[] buttonPrices) + { + this.m_Simulator = simulator; + this.m_ObjectID = objectID; + this.m_DefaultPrice = defaultPrice; + this.m_ButtonPrices = buttonPrices; + } + } + + public class ObjectMediaEventArgs : EventArgs + { + /// + /// Indicates if the operation was successful + /// + public bool Success { get; set; } + + /// + /// Media version string + /// + public string Version { get; set; } + + /// + /// Array of media entries indexed by face number + /// + public MediaEntry[] FaceMedia { get; set; } + + public ObjectMediaEventArgs(bool success, string version, MediaEntry[] faceMedia) + { + this.Success = success; + this.Version = version; + this.FaceMedia = faceMedia; + } + } + + /// + /// Set when simulator sends us infomation on primitive's physical properties + /// + public class PhysicsPropertiesEventArgs : EventArgs + { + /// Simulator where the message originated + public Simulator Simulator; + /// Updated physical properties + public Primitive.PhysicsProperties PhysicsProperties; + + /// + /// Constructor + /// + /// Simulator where the message originated + /// Updated physical properties + public PhysicsPropertiesEventArgs(Simulator sim, Primitive.PhysicsProperties props) + { + Simulator = sim; + PhysicsProperties = props; + } + } + + #endregion +} diff --git a/OpenMetaverse/ObjectPool.cs b/OpenMetaverse/ObjectPool.cs new file mode 100644 index 0000000..fe8f4f2 --- /dev/null +++ b/OpenMetaverse/ObjectPool.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Net; + +namespace OpenMetaverse +{ + // this class encapsulates a single packet that + // is either sent or received by a UDP socket + public class UDPPacketBuffer + { + /// Size of the byte array used to store raw packet data + public const int BUFFER_SIZE = 4096; + /// Raw packet data buffer + public readonly byte[] Data; + /// Length of the data to transmit + public int DataLength; + /// EndPoint of the remote host + public EndPoint RemoteEndPoint; + + /// + /// Create an allocated UDP packet buffer for receiving a packet + /// + public UDPPacketBuffer() + { + Data = new byte[UDPPacketBuffer.BUFFER_SIZE]; + // Will be modified later by BeginReceiveFrom() + RemoteEndPoint = new IPEndPoint(Settings.BIND_ADDR, 0); + } + + /// + /// Create an allocated UDP packet buffer for sending a packet + /// + /// EndPoint of the remote host + public UDPPacketBuffer(IPEndPoint endPoint) + { + Data = new byte[UDPPacketBuffer.BUFFER_SIZE]; + RemoteEndPoint = endPoint; + } + + /// + /// Create an allocated UDP packet buffer for sending a packet + /// + /// EndPoint of the remote host + /// Size of the buffer to allocate for packet data + public UDPPacketBuffer(IPEndPoint endPoint, int bufferSize) + { + Data = new byte[bufferSize]; + RemoteEndPoint = endPoint; + } + } + + /// + /// Object pool for packet buffers. This is used to allocate memory for all + /// incoming and outgoing packets, and zerocoding buffers for those packets + /// + public class PacketBufferPool : ObjectPoolBase + { + private IPEndPoint EndPoint; + + /// + /// Initialize the object pool in client mode + /// + /// Server to connect to + /// + /// + public PacketBufferPool(IPEndPoint endPoint, int itemsPerSegment, int minSegments) + : base() + { + EndPoint = endPoint; + Initialize(itemsPerSegment, minSegments, true, 1000 * 60 * 5); + } + + /// + /// Initialize the object pool in server mode + /// + /// + /// + public PacketBufferPool(int itemsPerSegment, int minSegments) + : base() + { + EndPoint = null; + Initialize(itemsPerSegment, minSegments, true, 1000 * 60 * 5); + } + + /// + /// Returns a packet buffer with EndPoint set if the buffer is in + /// client mode, or with EndPoint set to null in server mode + /// + /// Initialized UDPPacketBuffer object + protected override UDPPacketBuffer GetObjectInstance() + { + if (EndPoint != null) + // Client mode + return new UDPPacketBuffer(EndPoint); + else + // Server mode + return new UDPPacketBuffer(); + } + } + + public static class Pool + { + public static PacketBufferPool PoolInstance; + + /// + /// Default constructor + /// + static Pool() + { + PoolInstance = new PacketBufferPool(new IPEndPoint(Settings.BIND_ADDR, 0), 16, 1); + } + + /// + /// Check a packet buffer out of the pool + /// + /// A packet buffer object + public static WrappedObject CheckOut() + { + return PoolInstance.CheckOut(); + } + } +} diff --git a/OpenMetaverse/ObjectPoolBase.cs b/OpenMetaverse/ObjectPoolBase.cs new file mode 100644 index 0000000..4a3a03b --- /dev/null +++ b/OpenMetaverse/ObjectPoolBase.cs @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; + +namespace OpenMetaverse +{ + public sealed class WrappedObject : IDisposable where T : class + { + private T _instance; + internal readonly ObjectPoolSegment _owningSegment; + internal readonly ObjectPoolBase _owningObjectPool; + private bool _disposed = false; + + internal WrappedObject(ObjectPoolBase owningPool, ObjectPoolSegment ownerSegment, T activeInstance) + { + _owningObjectPool = owningPool; + _owningSegment = ownerSegment; + _instance = activeInstance; + } + + ~WrappedObject() + { +#if !PocketPC + // If the AppDomain is being unloaded, or the CLR is + // shutting down, just exit gracefully + if (Environment.HasShutdownStarted) + return; +#endif + + // Object Resurrection in Action! + GC.ReRegisterForFinalize(this); + + // Return this instance back to the owning queue + _owningObjectPool.CheckIn(_owningSegment, _instance); + } + + /// + /// Returns an instance of the class that has been checked out of the Object Pool. + /// + public T Instance + { + get + { + if (_disposed) + throw new ObjectDisposedException("WrappedObject"); + return _instance; + } + } + + /// + /// Checks the instance back into the object pool + /// + public void Dispose() + { + if (_disposed) + return; + + _disposed = true; + _owningObjectPool.CheckIn(_owningSegment, _instance); + GC.SuppressFinalize(this); + } + } + + public abstract class ObjectPoolBase : IDisposable where T : class + { + private int _itemsPerSegment = 32; + private int _minimumSegmentCount = 1; + + // A segment won't be eligible for cleanup unless it's at least this old... + private TimeSpan _minimumAgeToCleanup = new TimeSpan(0, 5, 0); + + // ever increasing segment counter + private int _activeSegment = 0; + + private bool _gc = true; + + private volatile bool _disposed = false; + + private Dictionary> _segments = new Dictionary>(); + private object _syncRoot = new object(); + private object _timerLock = new object(); + + // create a timer that starts in 5 minutes, and gets called every 5 minutes. + System.Threading.Timer _timer; + int _cleanupFrequency; + + /// + /// Creates a new instance of the ObjectPoolBase class. Initialize MUST be called + /// after using this constructor. + /// + protected ObjectPoolBase() + { + } + + /// + /// Creates a new instance of the ObjectPool Base class. + /// + /// The object pool is composed of segments, which + /// are allocated whenever the size of the pool is exceeded. The number of items + /// in a segment should be large enough that allocating a new segmeng is a rare + /// thing. For example, on a server that will have 10k people logged in at once, + /// the receive buffer object pool should have segment sizes of at least 1000 + /// byte arrays per segment. + /// + /// The minimun number of segments that may exist. + /// Perform a full GC.Collect whenever a segment is allocated, and then again after allocation to compact the heap. + /// The frequency which segments are checked to see if they're eligible for cleanup. + protected ObjectPoolBase(int itemsPerSegment, int minimumSegmentCount, bool gcOnPoolGrowth, int cleanupFrequenceMS) + { + Initialize(itemsPerSegment, minimumSegmentCount, gcOnPoolGrowth, cleanupFrequenceMS); + } + + protected void Initialize(int itemsPerSegment, int minimumSegmentCount, bool gcOnPoolGrowth, int cleanupFrequenceMS) + { + _itemsPerSegment = itemsPerSegment; + _minimumSegmentCount = minimumSegmentCount; + _gc = gcOnPoolGrowth; + + // force garbage collection to make sure these new long lived objects + // cause as little fragmentation as possible + if (_gc) + System.GC.Collect(); + + lock (_syncRoot) + { + while (_segments.Count < this.MinimumSegmentCount) + { + ObjectPoolSegment segment = CreateSegment(false); + _segments.Add(segment.SegmentNumber, segment); + } + } + + // This forces a compact, to make sure our objects fill in any holes in the heap. + if (_gc) + { + System.GC.Collect(); + } + + _timer = new Timer(CleanupThreadCallback, null, cleanupFrequenceMS, cleanupFrequenceMS); + } + + /// + /// Forces the segment cleanup algorithm to be run. This method is intended + /// primarly for use from the Unit Test libraries. + /// + internal void ForceCleanup() + { + CleanupThreadCallback(null); + } + + private void CleanupThreadCallback(object state) + { + if (_disposed) + return; + + if (Monitor.TryEnter(_timerLock) == false) + return; + + try + { + lock (_syncRoot) + { + // If we're below, or at, or minimum segment count threshold, + // there's no point in going any further. + if (_segments.Count <= _minimumSegmentCount) + return; + + for (int i = _activeSegment; i > 0; i--) + { + ObjectPoolSegment segment; + if (_segments.TryGetValue(i, out segment) == true) + { + // For the "old" segments that were allocated at startup, this will + // always be false, as their expiration dates are set at infinity. + if (segment.CanBeCleanedUp()) + { + _segments.Remove(i); + segment.Dispose(); + } + } + } + } + } + finally + { + Monitor.Exit(_timerLock); + } + } + + /// + /// Responsible for allocate 1 instance of an object that will be stored in a segment. + /// + /// An instance of whatever objec the pool is pooling. + protected abstract T GetObjectInstance(); + + + private ObjectPoolSegment CreateSegment(bool allowSegmentToBeCleanedUp) + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + if (allowSegmentToBeCleanedUp) + Logger.Log("Creating new object pool segment", Helpers.LogLevel.Info); + + // This method is called inside a lock, so no interlocked stuff required. + int segmentToAdd = _activeSegment; + _activeSegment++; + + Queue buffers = new Queue(); + for (int i = 1; i <= this._itemsPerSegment; i++) + { + T obj = GetObjectInstance(); + buffers.Enqueue(obj); + } + + // certain segments we don't want to ever be cleaned up (the initial segments) + DateTime cleanupTime = (allowSegmentToBeCleanedUp) ? DateTime.Now.Add(this._minimumAgeToCleanup) : DateTime.MaxValue; + ObjectPoolSegment segment = new ObjectPoolSegment(segmentToAdd, buffers, cleanupTime); + + return segment; + } + + + /// + /// Checks in an instance of T owned by the object pool. This method is only intended to be called + /// by the WrappedObject class. + /// + /// The segment from which the instance is checked out. + /// The instance of T to check back into the segment. + internal void CheckIn(ObjectPoolSegment owningSegment, T instance) + { + lock (_syncRoot) + { + owningSegment.CheckInObject(instance); + } + } + + /// + /// Checks an instance of T from the pool. If the pool is not sufficient to + /// allow the checkout, a new segment is created. + /// + /// A WrappedObject around the instance of T. To check + /// the instance back into the segment, be sureto dispose the WrappedObject + /// when finished. + public WrappedObject CheckOut() + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + // It's key that this CheckOut always, always, uses a pooled object + // from the oldest available segment. This will help keep the "newer" + // segments from being used - which in turn, makes them eligible + // for deletion. + + + lock (_syncRoot) + { + ObjectPoolSegment targetSegment = null; + + // find the oldest segment that has items available for checkout + for (int i = 0; i < _activeSegment; i++) + { + ObjectPoolSegment segment; + if (_segments.TryGetValue(i, out segment) == true) + { + if (segment.AvailableItems > 0) + { + targetSegment = segment; + break; + } + } + } + + if (targetSegment == null) + { + // We couldn't find a sigment that had any available space in it, + // so it's time to create a new segment. + + // Before creating the segment, do a GC to make sure the heap + // is compacted. + if (_gc) GC.Collect(); + + targetSegment = CreateSegment(true); + + if (_gc) GC.Collect(); + + _segments.Add(targetSegment.SegmentNumber, targetSegment); + } + + WrappedObject obj = new WrappedObject(this, targetSegment, targetSegment.CheckOutObject()); + return obj; + } + } + + /// + /// The total number of segments created. Intended to be used by the Unit Tests. + /// + public int TotalSegments + { + get + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + lock (_syncRoot) + { + return _segments.Count; + } + } + } + + /// + /// The number of items that are in a segment. Items in a segment + /// are all allocated at the same time, and are hopefully close to + /// each other in the managed heap. + /// + public int ItemsPerSegment + { + get + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + return _itemsPerSegment; + } + } + + /// + /// The minimum number of segments. When segments are reclaimed, + /// this number of segments will always be left alone. These + /// segments are allocated at startup. + /// + public int MinimumSegmentCount + { + get + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + return _minimumSegmentCount; + } + } + + /// + /// The age a segment must be before it's eligible for cleanup. + /// This is used to prevent thrash, and typical values are in + /// the 5 minute range. + /// + public TimeSpan MinimumSegmentAgePriorToCleanup + { + get + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + return _minimumAgeToCleanup; + } + set + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + _minimumAgeToCleanup = value; + } + } + + /// + /// The frequence which the cleanup thread runs. This is typically + /// expected to be in the 5 minute range. + /// + public int CleanupFrequencyMilliseconds + { + get + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + return _cleanupFrequency; + } + set + { + if (_disposed) + throw new ObjectDisposedException("ObjectPoolBase"); + + Interlocked.Exchange(ref _cleanupFrequency, value); + + _timer.Change(_cleanupFrequency, _cleanupFrequency); + } + } + + #region IDisposable Members + + public void Dispose() + { + if (_disposed) + return; + + Dispose(true); + + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + lock (_syncRoot) + { + if (_disposed) + return; + + _timer.Dispose(); + _disposed = true; + + foreach (KeyValuePair> kvp in _segments) + { + try + { + kvp.Value.Dispose(); + } + catch (Exception) { } + } + + _segments.Clear(); + } + } + } + + #endregion + } + + internal class ObjectPoolSegment : IDisposable where T : class + { + private Queue _liveInstances = new Queue(); + private int _segmentNumber; + private int _originalCount; + private bool _isDisposed = false; + private DateTime _eligibleForDeletionAt; + + public int SegmentNumber { get { return _segmentNumber; } } + public int AvailableItems { get { return _liveInstances.Count; } } + public DateTime DateEligibleForDeletion { get { return _eligibleForDeletionAt; } } + + public ObjectPoolSegment(int segmentNumber, Queue liveInstances, DateTime eligibleForDeletionAt) + { + _segmentNumber = segmentNumber; + _liveInstances = liveInstances; + _originalCount = liveInstances.Count; + _eligibleForDeletionAt = eligibleForDeletionAt; + } + + public bool CanBeCleanedUp() + { + if (_isDisposed == true) + throw new ObjectDisposedException("ObjectPoolSegment"); + + return ((_originalCount == _liveInstances.Count) && (DateTime.Now > _eligibleForDeletionAt)); + } + + public void Dispose() + { + if (_isDisposed) + return; + + _isDisposed = true; + + bool shouldDispose = (typeof(T) is IDisposable); + while (_liveInstances.Count != 0) + { + T instance = _liveInstances.Dequeue(); + if (shouldDispose) + { + try + { + (instance as IDisposable).Dispose(); + } + catch (Exception) { } + } + } + } + + internal void CheckInObject(T o) + { + if (_isDisposed == true) + throw new ObjectDisposedException("ObjectPoolSegment"); + + _liveInstances.Enqueue(o); + } + + internal T CheckOutObject() + { + if (_isDisposed == true) + throw new ObjectDisposedException("ObjectPoolSegment"); + + if (0 == _liveInstances.Count) + throw new InvalidOperationException("No Objects Available for Checkout"); + + T o = _liveInstances.Dequeue(); + return o; + } + } +} diff --git a/OpenMetaverse/ObservableDictionary.cs b/OpenMetaverse/ObservableDictionary.cs new file mode 100644 index 0000000..ef6af35 --- /dev/null +++ b/OpenMetaverse/ObservableDictionary.cs @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Collections; + +namespace OpenMetaverse +{ + + /// + /// + /// + public enum DictionaryEventAction + { + /// + /// + /// + Add, + /// + /// + /// + Remove, + /// + /// + /// + Change + } + + /// + /// + /// + /// + /// + public delegate void DictionaryChangeCallback(DictionaryEventAction action, DictionaryEntry entry); + + /// + /// The ObservableDictionary class is used for storing key/value pairs. It has methods for firing + /// events to subscribers when items are added, removed, or changed. + /// + /// Key + /// Value + public class ObservableDictionary + { + #region Observable implementation + /// + /// A dictionary of callbacks to fire when specified action occurs + /// + private Dictionary> Delegates; + + /// + /// Register a callback to be fired when an action occurs + /// + /// The action + /// The callback to fire + public void AddDelegate(DictionaryEventAction action, DictionaryChangeCallback callback) + { + if (Delegates.ContainsKey(action)) + { + Delegates[action].Add(callback); + } + else + { + List callbacks = new List(1); + callbacks.Add(callback); + Delegates.Add(action, callbacks); + } + } + + /// + /// Unregister a callback + /// + /// The action + /// The callback to fire + public void RemoveDelegate(DictionaryEventAction action, DictionaryChangeCallback callback) + { + if (Delegates.ContainsKey(action)) + { + if (Delegates[action].Contains(callback)) + Delegates[action].Remove(callback); + } + } + + /// + /// + /// + /// + /// + private void FireChangeEvent(DictionaryEventAction action, DictionaryEntry entry) + { + + if(Delegates.ContainsKey(action)) + { + foreach(DictionaryChangeCallback handler in Delegates[action]) + { + handler(action, entry); + } + } + } + + #endregion + + /// Internal dictionary that this class wraps around. Do not + /// modify or enumerate the contents of this dictionary without locking + private Dictionary Dictionary; + + /// + /// Gets the number of Key/Value pairs contained in the + /// + public int Count { get { return Dictionary.Count; } } + + /// + /// Initializes a new instance of the Class + /// with the specified key/value, has the default initial capacity. + /// + /// + /// + /// // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value. + /// public ObservableDictionary<string, int> testDict = new ObservableDictionary<string, int>(); + /// + /// + public ObservableDictionary() + { + Dictionary = new Dictionary(); + Delegates = new Dictionary>(); + } + + /// + /// Initializes a new instance of the Class + /// with the specified key/value, With its initial capacity specified. + /// + /// Initial size of dictionary + /// + /// + /// // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value, + /// // initially allocated room for 10 entries. + /// public ObservableDictionary<string, int> testDict = new ObservableDictionary<string, int>(10); + /// + /// + public ObservableDictionary(int capacity) + { + Dictionary = new Dictionary(capacity); + Delegates = new Dictionary>(); + } + + /// + /// Try to get entry from the with specified key + /// + /// Key to use for lookup + /// Value returned + /// if specified key exists, if not found + /// + /// + /// // find your avatar using the Simulator.ObjectsAvatars ObservableDictionary: + /// Avatar av; + /// if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.AgentID, out av)) + /// Console.WriteLine("Found Avatar {0}", av.Name); + /// + /// + /// + public bool TryGetValue(TKey key, out TValue value) + { + return Dictionary.TryGetValue(key, out value); + } + + /// + /// Finds the specified match. + /// + /// The match. + /// Matched value + /// + /// + /// // use a delegate to find a prim in the ObjectsPrimitives ObservableDictionary + /// // with the ID 95683496 + /// uint findID = 95683496; + /// Primitive findPrim = sim.ObjectsPrimitives.Find( + /// delegate(Primitive prim) { return prim.ID == findID; }); + /// + /// + public TValue Find(Predicate match) + { + foreach (TValue value in Dictionary.Values) + { + if (match(value)) + return value; + } + return default(TValue); + } + + /// Find All items in an + /// return matching items. + /// a containing found items. + /// + /// Find All prims within 20 meters and store them in a List + /// + /// int radius = 20; + /// List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( + /// delegate(Primitive prim) { + /// Vector3 pos = prim.Position; + /// return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius)); + /// } + /// ); + /// + /// + public List FindAll(Predicate match) + { + List found = new List(); + + foreach (KeyValuePair kvp in Dictionary) + { + if (match(kvp.Value)) + found.Add(kvp.Value); + } + return found; + } + + /// Find All items in an + /// return matching keys. + /// a containing found keys. + /// + /// Find All keys which also exist in another dictionary + /// + /// List<UUID> matches = myDict.FindAll( + /// delegate(UUID id) { + /// return myOtherDict.ContainsKey(id); + /// } + /// ); + /// + /// + public List FindAll(Predicate match) + { + List found = new List(); + + foreach (KeyValuePair kvp in Dictionary) + { + if (match(kvp.Key)) + found.Add(kvp.Key); + } + + return found; + } + + /// Check if Key exists in Dictionary + /// Key to check for + /// if found, otherwise + public bool ContainsKey(TKey key) + { + return Dictionary.ContainsKey(key); + } + + /// Check if Value exists in Dictionary + /// Value to check for + /// if found, otherwise + public bool ContainsValue(TValue value) + { + return Dictionary.ContainsValue(value); + } + + /// + /// Adds the specified key to the dictionary, dictionary locking is not performed, + /// + /// + /// The key + /// The value + public void Add(TKey key, TValue value) + { + Dictionary.Add(key, value); + FireChangeEvent(DictionaryEventAction.Add, new DictionaryEntry(key, value)); + } + + /// + /// Removes the specified key, dictionary locking is not performed + /// + /// The key. + /// if successful, otherwise + public bool Remove(TKey key) + { + FireChangeEvent(DictionaryEventAction.Remove, new DictionaryEntry(key, Dictionary[key])); + return Dictionary.Remove(key); + } + + /// + /// Indexer for the dictionary + /// + /// The key + /// The value + public TValue this[TKey key] + { + get { return Dictionary[key]; } + set { FireChangeEvent(DictionaryEventAction.Add, new DictionaryEntry(key, value)); + Dictionary[key] = value; } + } + + /// + /// Clear the contents of the dictionary + /// + public void Clear() + { + foreach (KeyValuePair kvp in Dictionary) + FireChangeEvent(DictionaryEventAction.Remove, new DictionaryEntry(kvp.Key, kvp.Value)); + + Dictionary.Clear(); + } + + /// + /// Enumerator for iterating dictionary entries + /// + /// + public System.Collections.IEnumerator GetEnumerator() + { + return Dictionary.GetEnumerator(); + } + } +} diff --git a/OpenMetaverse/OpenMetaverse.dll.build b/OpenMetaverse/OpenMetaverse.dll.build new file mode 100644 index 0000000..0d3fb26 --- /dev/null +++ b/OpenMetaverse/OpenMetaverse.dll.build @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverse/OpenMetaverse.mdp b/OpenMetaverse/OpenMetaverse.mdp new file mode 100644 index 0000000..1dc19c5 --- /dev/null +++ b/OpenMetaverse/OpenMetaverse.mdp @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverse/PacketDecoder.cs b/OpenMetaverse/PacketDecoder.cs new file mode 100644 index 0000000..9419dc2 --- /dev/null +++ b/OpenMetaverse/PacketDecoder.cs @@ -0,0 +1,1799 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace OpenMetaverse.Packets +{ + + public static class PacketDecoder + { + /// + /// A custom decoder callback + /// + /// The key of the object + /// the data to decode + /// A string represending the fieldData + public delegate string CustomPacketDecoder(string fieldName, object fieldData); + + private static Dictionary> Callbacks = new Dictionary>(); + + + static PacketDecoder() + { + AddCallback("Color", DecodeColorField); + AddCallback("TextColor", DecodeColorField); + AddCallback("Timestamp", DecodeTimeStamp); + AddCallback("EstateCovenantReply.Data.CovenantTimestamp", DecodeTimeStamp); + AddCallback("CreationDate", DecodeTimeStamp); + AddCallback("BinaryBucket", DecodeBinaryBucket); + AddCallback("ParcelData.Data", DecodeBinaryToHexString); + AddCallback("LayerData.Data", DecodeBinaryToHexString); + AddCallback("ImageData.Data", DecodeImageData); + AddCallback("TransferData.Data", DecodeBinaryToHexString); + AddCallback("ObjectData.TextureEntry", DecodeTextureEntry); + AddCallback("ImprovedInstantMessage.MessageBlock.Dialog", DecodeDialog); + + // Inventory/Permissions + AddCallback("BaseMask", DecodePermissionMask); + AddCallback("OwnerMask", DecodePermissionMask); + AddCallback("EveryoneMask", DecodePermissionMask); + AddCallback("NextOwnerMask", DecodePermissionMask); + AddCallback("GroupMask", DecodePermissionMask); + + // FetchInventoryDescendents + AddCallback("InventoryData.SortOrder", DecodeInventorySort); + + AddCallback("WearableType", DecodeWearableType); + // + AddCallback("InventoryData.Type", DecodeInventoryType); + AddCallback("InvType", DecodeInventoryInvType); + AddCallback("InventoryData.Flags", DecodeInventoryFlags); + // BulkUpdateInventory + AddCallback("ItemData.Type", DecodeInventoryType); + AddCallback("ItemData.Flags", DecodeInventoryFlags); + + AddCallback("SaleType", DecodeObjectSaleType); + + AddCallback("ScriptControlChange.Data.Controls", DecodeScriptControls); + + AddCallback("RegionFlags", DecodeRegionFlags); + AddCallback("SimAccess", DecodeSimAccess); + AddCallback("ControlFlags", DecodeControlFlags); + + // AgentUpdate + AddCallback("AgentUpdate.AgentData.State", DecodeAgentState); + AddCallback("AgentUpdate.AgentData.Flags", DecodeAgentFlags); + + // ViewerEffect TypeData + AddCallback("ViewerEffect.Effect.TypeData", DecodeViewerEffectTypeData); + AddCallback("ViewerEffect.Effect.Type", DecodeViewerEffectType); + + // Prim/ObjectUpdate decoders + AddCallback("ObjectUpdate.ObjectData.PCode", DecodeObjectPCode); + AddCallback("ObjectUpdate.ObjectData.Material", DecodeObjectMaterial); + AddCallback("ObjectUpdate.ObjectData.ClickAction", DecodeObjectClickAction); + AddCallback("ObjectData.UpdateFlags", DecodeObjectUpdateFlags); + + AddCallback("ObjectUpdate.ObjectData.ObjectData", DecodeObjectData); + AddCallback("TextureAnim", DecodeObjectTextureAnim); + AddCallback("ObjectUpdate.ObjectData.NameValue", DecodeNameValue); + AddCallback("ObjectUpdate.ObjectData.Data", DecodeObjectData); + + AddCallback("ObjectUpdate.ObjectData.PSBlock", DecodeObjectParticleSystem); + AddCallback("ParticleSys", DecodeObjectParticleSystem); + AddCallback("ObjectUpdate.ObjectData.ExtraParams", DecodeObjectExtraParams); + + AddCallback("ImprovedTerseObjectUpdate.ObjectData.Data", DecodeTerseUpdate); + AddCallback("ImprovedTerseObjectUpdate.ObjectData.TextureEntry", DecodeTerseTextureEntry); + + AddCallback("ObjectUpdateCompressed.ObjectData.Data", DecodeObjectCompressedData); + + // ImprovedTerseObjectUpdate & ObjectUpdate AttachmentPoint & ObjectUpdateCompressed + AddCallback("ObjectData.State", DecodeObjectState); + //AddCallback("ObjectUpdateCompressed.ObjectData.State", DecodeObjectState); + //AddCallback("ImprovedTerseObjectUpdate.ObjectData.State", DecodeObjectState); + + + // ChatFromSimulator + AddCallback("ChatData.SourceType", DecodeChatSourceType); + AddCallback("ChatData.ChatType", DecodeChatChatType); + AddCallback("ChatData.Audible", DecodeChatAudible); + AddCallback("AttachedSound.DataBlock.Flags", DecodeAttachedSoundFlags); + + AddCallback("RequestImage.Type", DecodeImageType); + + AddCallback("EstateOwnerMessage.ParamList.Parameter", DecodeEstateParameter); + + AddCallback("Codec", DecodeImageCodec); + AddCallback("Info.TeleportFlags", DecodeTeleportFlags); + + // map + AddCallback("MapBlockRequest.AgentData.Flags", DecodeMapRequestFlags); + AddCallback("MapItemRequest.AgentData.Flags", DecodeMapRequestFlags); + AddCallback("MapBlockReply.Data.Access", DecodeMapAccess); + AddCallback("FolderData.Type", DecodeFolderType); + AddCallback("RequestData.ItemType", DecodeGridItemType); + + // TransferRequest/TransferInfo + AddCallback("TransferInfo.Params", DecodeTransferParams); + AddCallback("TransferInfo.ChannelType", DecodeTransferChannelType); + AddCallback("TransferInfo.SourceType", DecodeTransferSourceType); + AddCallback("TransferInfo.TargetType", DecodeTransferTargetType); + AddCallback("TransferData.ChannelType", DecodeTransferChannelType); + // SendXferPacket + AddCallback("DataPacket.Data", DecodeBinaryToHexString); + // Directory Manager + AddCallback("DirClassifiedQuery.QueryData.QueryFlags", DecodeDirClassifiedQueryFlags); + AddCallback("QueryData.QueryFlags", DecodeDirQueryFlags); + AddCallback("Category", DecodeCategory); + AddCallback("QueryData.SearchType", SearchTypeFlags); + + AddCallback("ClassifiedFlags", DecodeDirClassifiedFlags); + AddCallback("EventFlags", DecodeEventFlags); + + AddCallback("ParcelAccessListRequest.Data.Flags", DecodeParcelACL); + AddCallback("ParcelAccessListReply.Data.Flags", DecodeParcelACL); + //AddCallback("ParcelAccessListReply.List.Flags", DecodeParcelACLReply); + + // AgentAnimation + AddCallback("AnimID", DecodeAnimToConst); + + AddCallback("LayerData.LayerID.Type", DecodeLayerDataType); + + AddCallback("GroupPowers", DecodeGroupPowers); + } + + /// + /// Add a custom decoder callback + /// + /// The key of the field to decode + /// The custom decode handler + public static void AddCallback(string key, CustomPacketDecoder customPacketHandler) + { + if (Callbacks.ContainsKey(key)) + { + lock (Callbacks) + Callbacks[key].Add(customPacketHandler); + } + else + { + lock (Callbacks) + Callbacks.Add(key, new List() { customPacketHandler }); + } + } + + /// + /// Remove a custom decoder callback + /// + /// The key of the field to decode + /// The custom decode handler + public static void RemoveCustomHandler(string key, CustomPacketDecoder customPacketHandler) + { + if (Callbacks.ContainsKey(key)) + lock (Callbacks) + { + if (Callbacks[key].Contains(customPacketHandler)) + Callbacks[key].Remove(customPacketHandler); + } + } + + #region Custom Decoders + + private static string DecodeTerseUpdate(string fieldName, object fieldData) + { + byte[] block = (byte[])fieldData; + int i = 4; + + StringBuilder result = new StringBuilder(); + + // LocalID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "LocalID", + Utils.BytesToUInt(block, 0), + "Uint32"); + + + + // State + byte point = block[i++]; + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "State", + point, + "(" + (AttachmentPoint)point + ")", + "AttachmentPoint"); + + // Avatar boolean + bool isAvatar = (block[i++] != 0); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "IsAvatar", + isAvatar, + "Boolean"); + + // Collision normal for avatar + if (isAvatar) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "CollisionPlane", + new Vector4(block, i), + "Vector4"); + + i += 16; + } + + // Position + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Position", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Velocity + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Velocity", + new Vector3( + Utils.UInt16ToFloat(block, i, -128.0f, 128.0f), + Utils.UInt16ToFloat(block, i + 2, -128.0f, 128.0f), + Utils.UInt16ToFloat(block, i + 4, -128.0f, 128.0f)), + "Vector3"); + i += 6; + + // Acceleration + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Acceleration", + new Vector3( + Utils.UInt16ToFloat(block, i, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)), + "Vector3"); + + i += 6; + // Rotation (theta) + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Rotation", + new Quaternion( + Utils.UInt16ToFloat(block, i, -1.0f, 1.0f), + Utils.UInt16ToFloat(block, i + 2, -1.0f, 1.0f), + Utils.UInt16ToFloat(block, i + 4, -1.0f, 1.0f), + Utils.UInt16ToFloat(block, i + 6, -1.0f, 1.0f)), + "Quaternion"); + i += 8; + // Angular velocity (omega) + result.AppendFormat("{0,30}: {1,-40} [{2}]", + "AngularVelocity", + new Vector3( + Utils.UInt16ToFloat(block, i, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)), + "Vector3"); + //pos += 6; + // TODO: What is in these 6 bytes? + return result.ToString(); + } + + private static string DecodeObjectCompressedData(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + byte[] block = (byte[])fieldData; + int i = 0; + + // UUID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ID", + new UUID(block, 0), + "UUID"); + i += 16; + + // Local ID + uint LocalID = (uint)(block[i++] + (block[i++] << 8) + + (block[i++] << 16) + (block[i++] << 24)); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "LocalID", + LocalID, + "Uint32"); + // PCode + PCode pcode = (PCode)block[i++]; + + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "PCode", + (int)pcode, + "(" + pcode + ")", + "PCode"); + + // State + AttachmentPoint point = (AttachmentPoint)block[i++]; + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "State", + (byte)point, + "(" + point + ")", + "AttachmentPoint"); + + // TODO: CRC + + i += 4; + // Material + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "Material", + block[i], + "(" + (Material)block[i++] + ")", + "Material"); + + // Click action + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "ClickAction", + block[i], + "(" + (ClickAction)block[i++] + ")", + "ClickAction"); + + // Scale + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Scale", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Position + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Position", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Rotation + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Rotation", + new Vector3(block, i), + "Vector3"); + + i += 12; + // Compressed flags + CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block, i); + result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, + "CompressedFlags", + Utils.BytesToUInt(block, i), + "(" + (CompressedFlags)Utils.BytesToUInt(block, i) + ")", + "UInt"); + i += 4; + + // Owners ID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "OwnerID", + new UUID(block, i), + "UUID"); + i += 16; + + // Angular velocity + if ((flags & CompressedFlags.HasAngularVelocity) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "AngularVelocity", + new Vector3(block, i), + "Vector3"); + i += 12; + } + + // Parent ID + if ((flags & CompressedFlags.HasParent) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ParentID", + (uint)(block[i++] + (block[i++] << 8) + + (block[i++] << 16) + (block[i++] << 24)), + "UInt"); + } + + // Tree data + if ((flags & CompressedFlags.Tree) != 0) + { + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "TreeSpecies", + block[i++], + "(" + (Tree)block[i] + ")", + "Tree"); + } + + // Scratch pad + else if ((flags & CompressedFlags.ScratchPad) != 0) + { + int size = block[i++]; + byte[] scratch = new byte[size]; + Buffer.BlockCopy(block, i, scratch, 0, size); + result.AppendFormat("{0,30}: {1,-40} [ScratchPad[]]" + Environment.NewLine, + "ScratchPad", + Utils.BytesToHexString(scratch, String.Format("{0,30}", "Data"))); + i += size; + } + + // Floating text + if ((flags & CompressedFlags.HasText) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + // Floating text + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Text", + text, + "string"); + + // Text color + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "TextColor", + new Color4(block, i, false), + "Color4"); + i += 4; + } + + // Media URL + if ((flags & CompressedFlags.MediaURL) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "MediaURL", + text, + "string"); + } + + // Particle system + if ((flags & CompressedFlags.HasParticles) != 0) + { + Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i); + result.AppendLine(DecodeObjectParticleSystem("ParticleSystem", p)); + i += 86; + } + + // Extra parameters TODO: + Primitive prim = new Primitive(); + i += prim.SetExtraParamsFromBytes(block, i); + + //Sound data + if ((flags & CompressedFlags.HasSound) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundID", + new UUID(block, i), + "UUID"); + i += 16; + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundGain", + Utils.BytesToFloat(block, i), + "Float"); + i += 4; + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "SoundFlags", + block[i++], + "(" + (SoundFlags)block[i] + ")", + "SoundFlags"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundRadius", + Utils.BytesToFloat(block, i), + "Float"); + i += 4; + } + + // Name values + if ((flags & CompressedFlags.HasNameValues) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + // Parse the name values + if (text.Length > 0) + { + string[] lines = text.Split('\n'); + NameValue[] nameValues = new NameValue[lines.Length]; + + for (int j = 0; j < lines.Length; j++) + { + if (!String.IsNullOrEmpty(lines[j])) + { + NameValue nv = new NameValue(lines[j]); + nameValues[j] = nv; + } + } + DecodeNameValue("NameValues", nameValues); + } + } + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "PathCurve", + block[i], + "(" + (PathCurve)block[i++] + ")", + "PathCurve"); + + ushort pathBegin = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathBegin", + Primitive.UnpackBeginCut(pathBegin), + "float"); + + ushort pathEnd = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathEnd", + Primitive.UnpackEndCut(pathEnd), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathScaleX", + Primitive.UnpackPathScale(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathScaleY", + Primitive.UnpackPathScale(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathShearX", + Primitive.UnpackPathShear((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathShearY", + Primitive.UnpackPathShear((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTwist", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTwistBegin", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathRadiusOffset", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTaperX", + Primitive.UnpackPathTaper((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTaperY", + Primitive.UnpackPathTaper((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathRevolutions", + Primitive.UnpackPathRevolutions(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathSkew", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileCurve", + block[i++], + "float"); + + ushort profileBegin = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileBegin", + Primitive.UnpackBeginCut(profileBegin), + "float"); + + ushort profileEnd = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileEnd", + Primitive.UnpackEndCut(profileEnd), + "float"); + + ushort profileHollow = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileHollow", + Primitive.UnpackProfileHollow(profileHollow), + "float"); + + int textureEntryLength = (int)Utils.BytesToUInt(block, i); + i += 4; + //prim.Textures = new Primitive.TextureEntry(block, i, textureEntryLength); + String s = DecodeTextureEntry("TextureEntry", new Primitive.TextureEntry(block, i, textureEntryLength)); + result.AppendLine(s); + i += textureEntryLength; + + // Texture animation + if ((flags & CompressedFlags.TextureAnimation) != 0) + { + i += 4; + string a = DecodeObjectTextureAnim("TextureAnimation", new Primitive.TextureAnimation(block, i)); + result.AppendLine(a); + } + + return result.ToString(); + } + + private static string DecodeObjectData(string fieldName, object fieldData) + { + byte[] data = (byte[])fieldData; + if (data.Length == 1) + { + return String.Format("{0,30}: {1,2} {2,-38} [{3}]", + fieldName + " (Tree Species)", + fieldData, + "(" + (Tree)(byte)fieldData + ")", + fieldData.GetType().Name); + } + else if (data.Length == 60) + { + /* TODO: these are likely useful packed fields, + * need to unpack them */ + return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); + } + else + { + return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); + } + } + + private static string DecodeObjectTextureAnim(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + Primitive.TextureAnimation TextureAnim; + if (fieldData is Primitive.TextureAnimation) + TextureAnim = (Primitive.TextureAnimation)fieldData; + else + TextureAnim = new Primitive.TextureAnimation((byte[])fieldData, 0); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericTypeDecoder(TextureAnim, ref result); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static string DecodeEstateParameter(string fieldName, object fieldData) + { + byte[] bytes = (byte[])fieldData; + + if (bytes.Length == 17) + { + return String.Format("{0,30}: {1,-40} [UUID]", fieldName, new UUID((byte[])fieldData, 0)); + } + else + { + return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, Utils.BytesToString((byte[])fieldData)); + } + } + + private static string DecodeNameValue(string fieldName, object fieldData) + { + string nameValue = Utils.BytesToString((byte[])fieldData); + NameValue[] nameValues = null; + if (nameValue.Length > 0) + { + string[] lines = nameValue.Split('\n'); + nameValues = new NameValue[lines.Length]; + + for (int i = 0; i < lines.Length; i++) + { + if (!String.IsNullOrEmpty(lines[i])) + { + NameValue nv = new NameValue(lines[i]); + nameValues[i] = nv; + } + } + } + + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (nameValues != null) + { + for (int i = 0; i < nameValues.Length; i++) + { + result.AppendFormat( + "{0,30}: Name={1} Value={2} Class={3} Type={4} Sendto={5}" + Environment.NewLine, "NameValue", + nameValues[i].Name, nameValues[i].Value, nameValues[i].Class, nameValues[i].Type, nameValues[i].Sendto); + } + } + result.AppendFormat("{0,30}", ""); + return result.ToString(); + } + + private static string DecodeObjectExtraParams(string fieldName, object fieldData) + { + + byte[] data = (byte[])fieldData; + + int i = 0; + //int totalLength = 1; + + Primitive.FlexibleData Flexible = null; + Primitive.LightData Light = null; + Primitive.SculptData Sculpt = null; + + byte extraParamCount = data[i++]; + + for (int k = 0; k < extraParamCount; k++) + { + ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i); + i += 2; + + uint paramLength = Utils.BytesToUInt(data, i); + i += 4; + + if (type == ExtraParamType.Flexible) + Flexible = new Primitive.FlexibleData(data, i); + else if (type == ExtraParamType.Light) + Light = new Primitive.LightData(data, i); + else if (type == ExtraParamType.Sculpt) + Sculpt = new Primitive.SculptData(data, i); + + i += (int)paramLength; + //totalLength += (int)paramLength + 6; + } + + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + if (Flexible != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Flexible, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (Sculpt != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Sculpt, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (Light != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Light, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + result.AppendFormat("{0,30}", ""); + return result.ToString(); + } + + private static string DecodeObjectParticleSystem(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + Primitive.ParticleSystem ParticleSys; + if (fieldData is Primitive.ParticleSystem) + ParticleSys = (Primitive.ParticleSystem)fieldData; + else + ParticleSys = new Primitive.ParticleSystem((byte[])fieldData, 0); + + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(ParticleSys, ref result); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static void GenericTypeDecoder(object obj, ref StringBuilder result) + { + FieldInfo[] fields = obj.GetType().GetFields(); + + foreach (FieldInfo field in fields) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + field.Name, + field.GetValue(obj), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + field.Name, + field.GetValue(obj), + field.FieldType.Name); + } + } + } + + private static string DecodeObjectPCode(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [PCode]", + fieldName, + fieldData, + "(" + (PCode)(byte)fieldData + ")"); + } + + private static string DecodeImageType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ImageType]", + fieldName, + fieldData, + "(" + (ImageType)(byte)fieldData + ")"); + } + + private static string DecodeImageCodec(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ImageCodec]", + fieldName, + fieldData, + "(" + (ImageCodec)(byte)fieldData + ")"); + } + + private static string DecodeObjectMaterial(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [Material]", + fieldName, + fieldData, + "(" + (Material)(byte)fieldData + ")"); + } + + private static string DecodeObjectClickAction(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ClickAction]", + fieldName, + fieldData, + "(" + (ClickAction)(byte)fieldData + ")"); + } + + private static string DecodeEventFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [EventFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.EventFlags)(uint)fieldData + ")"); + } + + private static string DecodeDirQueryFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.DirFindFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.DirFindFlags)(uint)fieldData + ")"); + } + + private static string DecodeDirClassifiedQueryFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedQueryFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.ClassifiedQueryFlags)(uint)fieldData + ")"); + } + + private static string DecodeDirClassifiedFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.ClassifiedFlags)(byte)fieldData + ")"); + } + + private static string DecodeGroupPowers(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-20} {2,-19} [GroupPowers]", + fieldName, + fieldData, + "(" + (GroupPowers)(ulong)fieldData + ")"); + } + + private static string DecodeParcelACL(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [AccessList]", + fieldName, + fieldData, + "(" + (AccessList)(uint)fieldData + ")"); + } + + private static string SearchTypeFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.SearchTypeFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.SearchTypeFlags)(uint)fieldData + ")"); + } + + private static string DecodeCategory(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ParcelCategory]", + fieldName, + fieldData, + "(" + fieldData + ")"); + } + + private static string DecodeObjectUpdateFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [PrimFlags]", + fieldName, + fieldData, + "(" + (PrimFlags)(uint)fieldData + ")"); + } + + private static string DecodeTeleportFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [TeleportFlags]", + fieldName, + fieldData, + "(" + (TeleportFlags)(uint)fieldData + ")"); + } + + private static string DecodeScriptControls(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [AgentManager.ControlFlags]", + fieldName, + (uint)fieldData, + "(" + (AgentManager.ControlFlags)(uint)fieldData + ")"); + } + + private static string DecodeColorField(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-40} [Color4]", + fieldName, + fieldData.GetType().Name.Equals("Color4") ? (Color4)fieldData : new Color4((byte[])fieldData, 0, false)); + } + + private static string DecodeTimeStamp(string fieldName, object fieldData) + { + if (fieldData is Int32 && (int)fieldData > 0) + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + Utils.UnixTimeToDateTime((int)fieldData) + ")", + fieldData.GetType().Name); + else if (fieldData is uint && (uint)fieldData > 0) + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + Utils.UnixTimeToDateTime((uint)fieldData) + ")", + fieldData.GetType().Name); + else + return String.Format("{0,30}: {1,-40} [{2}]", + fieldName, + fieldData, + fieldData.GetType().Name); + } + + private static string DecodeBinaryBucket(string fieldName, object fieldData) + { + byte[] bytes = (byte[])fieldData; + string bucket = String.Empty; + if (bytes.Length == 1) + { + bucket = String.Format("{0}", bytes[0]); + } + else if (bytes.Length == 17) + { + bucket = String.Format("{0,-36} {1} ({2})", + new UUID(bytes, 1), + bytes[0], + (AssetType)(sbyte)bytes[0]); + } + else if (bytes.Length == 16) // the folder ID for the asset to be stored into if we accept an inventory offer + { + bucket = new UUID(bytes, 0).ToString(); + } + else + { + bucket = Utils.BytesToString(bytes); // we'll try a string lastly + } + + return String.Format("{0,30}: {1,-40} [Byte[{2}]]", fieldName, bucket, bytes.Length); + } + + private static string DecodeBinaryToHexString(string fieldName, object fieldData) + { + return String.Format("{0,30}", + Utils.BytesToHexString((byte[])fieldData, + String.Format("{0,30}", fieldName))); + } + + private static string DecodeWearableType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [WearableType]", + fieldName, + (byte)fieldData, + "(" + (WearableType)fieldData + ")"); + } + + private static string DecodeInventoryType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]", + fieldName, + (sbyte)fieldData, + "(" + (AssetType)(sbyte)fieldData + ")"); + } + + private static string DecodeInventorySort(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [InventorySortOrder]", + fieldName, + fieldData, + "(" + (InventorySortOrder)(int)fieldData + ")"); + } + + private static string DecodeInventoryInvType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [InventoryType]", + fieldName, + (sbyte)fieldData, + "(" + (InventoryType)fieldData + ")"); + } + + private static string DecodeFolderType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]", + fieldName, + (sbyte)fieldData, + "(" + (AssetType)fieldData + ")"); + } + + private static string DecodeInventoryFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [InventoryItemFlags]", + fieldName, + (uint)fieldData, + "(" + (InventoryItemFlags)(uint)fieldData + ")"); + } + + private static string DecodeObjectSaleType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SaleType]", + fieldName, + (byte)fieldData, + "(" + (SaleType)fieldData + ")"); + } + + private static string DecodeRegionFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [RegionFlags]", + fieldName, + fieldData, + "(" + (RegionFlags)(uint)fieldData + ")"); + } + + private static string DecodeTransferParams(string fieldName, object fieldData) + { + byte[] paramData = (byte[])fieldData; + StringBuilder result = new StringBuilder(); + result.AppendLine(" "); + if (paramData.Length == 20) + { + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "AssetID", + new UUID(paramData, 0)); + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, + "AssetType", + (sbyte)paramData[16], + "(" + (AssetType)(sbyte)paramData[16] + ")"); + + } + else if (paramData.Length == 100) + { + //UUID agentID = new UUID(info.TransferInfo.Params, 0); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "AgentID", + new UUID(paramData, 0)); + + //UUID sessionID = new UUID(info.TransferInfo.Params, 16); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "SessionID", + new UUID(paramData, 16)); + //UUID ownerID = new UUID(info.TransferInfo.Params, 32); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "OwnerID", + new UUID(paramData, 32)); + //UUID taskID = new UUID(info.TransferInfo.Params, 48); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "TaskID", + new UUID(paramData, 48)); + //UUID itemID = new UUID(info.TransferInfo.Params, 64); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "ItemID", + new UUID(paramData, 64)); + + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "AssetID", + new UUID(paramData, 80)); + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, + "AssetType", + (sbyte)paramData[96], + "(" + (AssetType)(sbyte)paramData[96] + ")"); + } + else + { + Console.WriteLine("Oh Poop!"); + } + + result.Append(""); + + return result.ToString(); + } + + private static string DecodeTransferChannelType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [ChannelType]", + fieldName, + fieldData, + "(" + (ChannelType)(int)fieldData + ")"); + } + + private static string DecodeTransferSourceType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", + fieldName, + fieldData, + "(" + (SourceType)(int)fieldData + ")"); + } + + private static string DecodeTransferTargetType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [TargetType]", + fieldName, + fieldData, + "(" + (TargetType)(int)fieldData + ")"); + } + + private static string DecodeMapRequestFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [GridLayerType]", + fieldName, + fieldData, + "(" + (GridLayerType)(uint)fieldData + ")"); + } + + private static string DecodeGridItemType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [GridItemType]", + fieldName, + fieldData, + "(" + (GridItemType)(uint)fieldData + ")"); + + } + + private static string DecodeLayerDataType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [LayerType]", + fieldName, + fieldData, + "(" + (TerrainPatch.LayerType)(byte)fieldData + ")"); + } + + private static string DecodeMapAccess(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", + fieldName, + fieldData, + "(" + (SimAccess)(byte)fieldData + ")"); + } + + private static string DecodeSimAccess(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", + fieldName, + (byte)fieldData, + "(" + (SimAccess)fieldData + ")"); + } + + private static string DecodeAttachedSoundFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SoundFlags]", + fieldName, + (byte)fieldData, + "(" + (SoundFlags)fieldData + ")"); + } + + + private static string DecodeChatSourceType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", + fieldName, + fieldData, + "(" + (SourceType)(byte)fieldData + ")"); + } + + private static string DecodeChatChatType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [ChatType]", + fieldName, + (byte)fieldData, + "(" + (ChatType)fieldData + ")"); + } + + private static string DecodeChatAudible(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [ChatAudibleLevel]", + fieldName, + (byte)fieldData, + "(" + (ChatAudibleLevel)(byte)fieldData + ")"); + } + + private static string DecodeImageData(string fieldName, object fieldData) + { + return String.Format("{0,10}", + Utils.BytesToHexString((byte[])fieldData, + String.Format("{0,30}", fieldName))); + } + + private static string DecodeTerseTextureEntry(string fieldName, object fieldData) + { + byte[] block = (byte[])fieldData; + + Primitive.TextureEntry te = new Primitive.TextureEntry(block, 4, block.Length - 4); + + StringBuilder result = new StringBuilder(); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (te.DefaultTexture != null) + { + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericFieldsDecoder(te.DefaultTexture, ref result); + GenericPropertiesDecoder(te.DefaultTexture, ref result); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + for (int i = 0; i < te.FaceTextures.Length; i++) + { + if (te.FaceTextures[i] != null) + { + result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); + GenericFieldsDecoder(te.FaceTextures[i], ref result); + GenericPropertiesDecoder(te.FaceTextures[i], ref result); + } + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static string DecodeTextureEntry(string fieldName, object fieldData) + { + Primitive.TextureEntry te; + if (fieldData is Primitive.TextureEntry) + te = (Primitive.TextureEntry)fieldData; + else + { + byte[] tebytes = (byte[])fieldData; + te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length); + } + + StringBuilder result = new StringBuilder(); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (te.DefaultTexture != null) + { + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericFieldsDecoder(te.DefaultTexture, ref result); + GenericPropertiesDecoder(te.DefaultTexture, ref result); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + for (int i = 0; i < te.FaceTextures.Length; i++) + { + if (te.FaceTextures[i] != null) + { + result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); + GenericFieldsDecoder(te.FaceTextures[i], ref result); + GenericPropertiesDecoder(te.FaceTextures[i], ref result); + } + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static void GenericFieldsDecoder(object obj, ref StringBuilder result) + { + Type parcelType = obj.GetType(); + FieldInfo[] fields = parcelType.GetFields(); + foreach (FieldInfo field in fields) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + field.Name, + field.GetValue(obj), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + field.Name, + field.GetValue(obj), + field.FieldType.Name); + } + } + } + + private static void GenericPropertiesDecoder(object obj, ref StringBuilder result) + { + Type parcelType = obj.GetType(); + PropertyInfo[] propertyInfos = parcelType.GetProperties(); + foreach (PropertyInfo property in propertyInfos) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + property.Name, + property.GetValue(obj, null), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + property.Name, + property.GetValue(obj, null), + property.PropertyType.Name); + } + } + } + + private static string DecodeDialog(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", + fieldName, + (byte)fieldData, + "(" + (InstantMessageDialog)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeControlFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + (AgentManager.ControlFlags)(uint)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodePermissionMask(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + (uint)fieldData, + "(" + (PermissionMask)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeViewerEffectTypeData(string fieldName, object fieldData) + { + byte[] data = (byte[])fieldData; + StringBuilder sb = new StringBuilder(); + if (data.Length == 56 || data.Length == 57) + { + UUID sourceAvatar = new UUID(data, 0); + UUID targetObject = new UUID(data, 16); + Vector3d targetPos = new Vector3d(data, 32); + sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Source AvatarID=" + sourceAvatar); + sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Target ObjectID=" + targetObject); + + + float lx, ly; + Helpers.GlobalPosToRegionHandle((float)targetPos.X, (float)targetPos.Y, out lx, out ly); + + sb.AppendFormat("{0,30}: {1,-40} [Vector3d]", fieldName, targetPos); + + if (data.Length == 57) + { + sb.AppendLine(); + sb.AppendFormat("{0,30}: {1,-17} {2,-22} [Byte]", fieldName, "Point At Type=" + data[56], + "(" + (PointAtType)data[56] + ")"); + } + + return sb.ToString(); + } + else + { + return String.Format("{0,30}: (No Decoder) Length={1}" + Environment.NewLine, fieldName, data.Length) + Utils.BytesToHexString(data, String.Format("{0,30}", "")); + } + } + + private static string DecodeAgentState(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AgentState]", + fieldName, + fieldData, + "(" + (AgentState)(byte)fieldData + ")"); + } + + private static string DecodeAgentFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AgentFlags]", + fieldName, + fieldData, + "(" + (AgentFlags)(byte)fieldData + ")"); + } + + private static string DecodeObjectState(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AttachmentPoint]", + fieldName, + fieldData, + "(" + (AttachmentPoint)(byte)fieldData + ")"); + } + + private static string DecodeViewerEffectType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", + fieldName, + fieldData, + "(" + (EffectType)(byte)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeAnimToConst(string fieldName, object fieldData) + { + string animConst = "UUID"; + Dictionary animsDict = Animations.ToDictionary(); + if (animsDict.ContainsKey((UUID)fieldData)) + animConst = animsDict[(UUID)fieldData]; + return String.Format("{0,30}: {1,-40} [{2}]", + fieldName, + fieldData, + animConst); + } + #endregion + + /// + /// Creates a formatted string containing the values of a Packet + /// + /// The Packet + /// A formatted string of values of the nested items in the Packet object + public static string PacketToString(Packet packet) + { + StringBuilder result = new StringBuilder(); + + result.AppendFormat("Packet Type: {0} http://lib.openmetaverse.org/wiki/{0} http://wiki.secondlife.com/wiki/{0}" + Environment.NewLine, packet.Type); + result.AppendLine("[Packet Header]"); + // payload + result.AppendFormat("Sequence: {0}" + Environment.NewLine, packet.Header.Sequence); + result.AppendFormat(" Options: {0}" + Environment.NewLine, InterpretOptions(packet.Header)); + result.AppendLine(); + + result.AppendLine("[Packet Payload]"); + + FieldInfo[] fields = packet.GetType().GetFields(); + + for (int i = 0; i < fields.Length; i++) + { + // we're not interested in any of these here + if (fields[i].Name == "Type" || fields[i].Name == "Header" || fields[i].Name == "HasVariableBlocks") + continue; + + if (fields[i].FieldType.IsArray) + { + result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --"); + RecursePacketArray(fields[i], packet, ref result); + } + else + { + result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --"); + RecursePacketField(fields[i], packet, ref result); + } + } + return result.ToString(); + } + + public static string InterpretOptions(Header header) + { + return "[" + + (header.AppendedAcks ? "Ack" : " ") + + " " + + (header.Resent ? "Res" : " ") + + " " + + (header.Reliable ? "Rel" : " ") + + " " + + (header.Zerocoded ? "Zer" : " ") + + "]" + ; + } + + private static void RecursePacketArray(FieldInfo fieldInfo, object packet, ref StringBuilder result) + { + var packetDataObject = fieldInfo.GetValue(packet); + + foreach (object nestedArrayRecord in packetDataObject as Array) + { + FieldInfo[] fields = nestedArrayRecord.GetType().GetFields(); + + for (int i = 0; i < fields.Length; i++) + { + String special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + fields[i].Name, + fields[i].GetValue(nestedArrayRecord), out special)) + { + result.AppendLine(special); + } + else if (fields[i].FieldType.IsArray) // default for an array (probably a byte[]) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + fields[i].Name, + Utils.BytesToString((byte[])fields[i].GetValue(nestedArrayRecord)), + /*fields[i].GetValue(nestedArrayRecord).GetType().Name*/ "String"); + } + else // default for a field + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + fields[i].Name, + fields[i].GetValue(nestedArrayRecord), + fields[i].GetValue(nestedArrayRecord).GetType().Name); + } + } + + // Handle Properties + foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties()) + { + if (propertyInfo.Name.Equals("Length")) + continue; + + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, + propertyInfo.GetValue(nestedArrayRecord, null), + out special)) + { + result.AppendLine(special); + } + else + { + var p = propertyInfo.GetValue(nestedArrayRecord, null); + /* Leave the c for now at the end, it signifies something useful that still needs to be done i.e. a decoder written */ + result.AppendFormat("{0, 30}: {1,-40} [{2}]c" + Environment.NewLine, + propertyInfo.Name, + Utils.BytesToString((byte[])propertyInfo.GetValue(nestedArrayRecord, null)), + propertyInfo.PropertyType.Name); + } + } + result.AppendFormat("{0,32}" + Environment.NewLine, "***"); + } + } + + private static void RecursePacketField(FieldInfo fieldInfo, object packet, ref StringBuilder result) + { + object packetDataObject = fieldInfo.GetValue(packet); + + // handle Fields + foreach (FieldInfo packetValueField in fieldInfo.GetValue(packet).GetType().GetFields()) + { + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + packetValueField.Name, + packetValueField.GetValue(packetDataObject), + out special)) + { + result.AppendLine(special); + } + else if (packetValueField.FieldType.IsArray) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + packetValueField.Name, + Utils.BytesToString((byte[])packetValueField.GetValue(packetDataObject)), + /*packetValueField.FieldType.Name*/ "String"); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + packetValueField.Name, packetValueField.GetValue(packetDataObject), packetValueField.FieldType.Name); + + } + } + + // Handle Properties + foreach (PropertyInfo propertyInfo in packetDataObject.GetType().GetProperties()) + { + if (propertyInfo.Name.Equals("Length")) + continue; + + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, + propertyInfo.GetValue(packetDataObject, null), + out special)) + { + result.AppendLine(special); + } + else if (propertyInfo.GetValue(packetDataObject, null).GetType() == typeof(byte[])) + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + propertyInfo.Name, + Utils.BytesToString((byte[])propertyInfo.GetValue(packetDataObject, null)), + propertyInfo.PropertyType.Name); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + propertyInfo.Name, + propertyInfo.GetValue(packetDataObject, null), + propertyInfo.PropertyType.Name); + } + } + } + + private static bool SpecialDecoder(string decoderKey, object fieldData, out string result) + { + result = string.Empty; + string[] keys = decoderKey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + string[] keyList = { decoderKey, decoderKey.Replace("Packet", ""), keys[1] + "." + keys[2], keys[2] }; + foreach (string key in keyList) + { + + bool ok = true; + if (fieldData is byte[]) + { + byte[] fd = (byte[])fieldData; + ok = fd.Length > 0; + if (!ok) + { + // bypass the decoder since we were passed an empty byte array + result = String.Format("{0,30}:", keys[2]); + return true; + } + } + + if (ok && Callbacks.ContainsKey(key)) // fieldname e.g: Plane + { + foreach (CustomPacketDecoder decoder in Callbacks[key]) + result = decoder(keys[2], fieldData); + return true; + } + } + return false; + } + + /// + /// Decode an IMessage object into a beautifully formatted string + /// + /// The IMessage object + /// Recursion level (used for indenting) + /// A formatted string containing the names and values of the source object + public static string MessageToString(object message, int recurseLevel) + { + if (message == null) + return String.Empty; + + StringBuilder result = new StringBuilder(); + // common/custom types + if (recurseLevel <= 0) + { + result.AppendFormat("Message Type: {0} http://lib.openmetaverse.org/wiki/{0}" + Environment.NewLine, message.GetType().Name); + } + else + { + string pad = " +--".PadLeft(recurseLevel + 3); + result.AppendFormat("{0} {1}" + Environment.NewLine, pad, message.GetType().Name); + } + + recurseLevel++; + + foreach (FieldInfo messageField in message.GetType().GetFields()) + { + // an abstract message class + if (messageField.FieldType.IsAbstract) + { + result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); + } + // a byte array + else if (messageField.GetValue(message) != null && messageField.GetValue(message).GetType() == typeof(Byte[])) + { + result.AppendFormat("{0, 30}:" + Environment.NewLine, messageField.Name); + + result.AppendFormat("{0}" + Environment.NewLine, + Utils.BytesToHexString((byte[])messageField.GetValue(message), + String.Format("{0,30}", ""))); + } + + // an array of class objects + else if (messageField.FieldType.IsArray) + { + var messageObjectData = messageField.GetValue(message); + result.AppendFormat("-- {0} --" + Environment.NewLine, messageField.FieldType.Name); + foreach (object nestedArrayObject in messageObjectData as Array) + { + if (nestedArrayObject == null) + { + result.AppendFormat("{0,30}" + Environment.NewLine, "-- null --"); + continue; + } + else + { + result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + nestedArrayObject.GetType().Name + " --"); + } + foreach (FieldInfo nestedField in nestedArrayObject.GetType().GetFields()) + { + if (nestedField.FieldType.IsEnum) + { + result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, + nestedField.Name, + Enum.Format(nestedField.GetValue(nestedArrayObject).GetType(), + nestedField.GetValue(nestedArrayObject), "D"), + "(" + nestedField.GetValue(nestedArrayObject) + ")", + nestedField.GetValue(nestedArrayObject).GetType().Name); + } + else if (nestedField.FieldType.IsInterface) + { + result.AppendLine(MessageToString(nestedField.GetValue(nestedArrayObject), recurseLevel)); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + nestedField.Name, + nestedField.GetValue(nestedArrayObject), + nestedField.FieldType.Name); + } + } + } + } + else + { + if (messageField.FieldType.IsEnum) + { + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + messageField.Name, + Enum.Format(messageField.GetValue(message).GetType(), + messageField.GetValue(message), "D"), + "(" + messageField.GetValue(message) + ")", + messageField.FieldType.Name); + } + else if (messageField.FieldType.IsInterface) + { + result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + messageField.Name, messageField.GetValue(message), messageField.FieldType.Name); + } + } + } + + return result.ToString(); + } + } +} diff --git a/OpenMetaverse/Parallel.cs b/OpenMetaverse/Parallel.cs new file mode 100644 index 0000000..885b90d --- /dev/null +++ b/OpenMetaverse/Parallel.cs @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; + +namespace OpenMetaverse +{ + /// + /// Provides helper methods for parallelizing loops + /// + public static class Parallel + { + private static readonly int processorCount = System.Environment.ProcessorCount; + + /// + /// Executes a for loop in which iterations may run in parallel + /// + /// The loop will be started at this index + /// The loop will be terminated before this index is reached + /// Method body to run for each iteration of the loop + public static void For(int fromInclusive, int toExclusive, Action body) + { + For(processorCount, fromInclusive, toExclusive, body); + } + + /// + /// Executes a for loop in which iterations may run in parallel + /// + /// The number of concurrent execution threads to run + /// The loop will be started at this index + /// The loop will be terminated before this index is reached + /// Method body to run for each iteration of the loop + public static void For(int threadCount, int fromInclusive, int toExclusive, Action body) + { + int counter = threadCount; + AutoResetEvent threadFinishEvent = new AutoResetEvent(false); + Exception exception = null; + + --fromInclusive; + + for (int i = 0; i < threadCount; i++) + { + WorkPool.QueueUserWorkItem( + delegate(object o) + { + int threadIndex = (int)o; + + while (exception == null) + { + int currentIndex = Interlocked.Increment(ref fromInclusive); + + if (currentIndex >= toExclusive) + break; + + try { body(currentIndex); } + catch (Exception ex) { exception = ex; break; } + } + + if (Interlocked.Decrement(ref counter) == 0) + threadFinishEvent.Set(); + }, i + ); + } + + threadFinishEvent.WaitOne(); + + if (exception != null) + throw exception; + } + + /// + /// Executes a foreach loop in which iterations may run in parallel + /// + /// Object type that the collection wraps + /// An enumerable collection to iterate over + /// Method body to run for each object in the collection + public static void ForEach(IEnumerable enumerable, Action body) + { + ForEach(processorCount, enumerable, body); + } + + /// + /// Executes a foreach loop in which iterations may run in parallel + /// + /// Object type that the collection wraps + /// The number of concurrent execution threads to run + /// An enumerable collection to iterate over + /// Method body to run for each object in the collection + public static void ForEach(int threadCount, IEnumerable enumerable, Action body) + { + int counter = threadCount; + AutoResetEvent threadFinishEvent = new AutoResetEvent(false); + IEnumerator enumerator = enumerable.GetEnumerator(); + Exception exception = null; + + for (int i = 0; i < threadCount; i++) + { + WorkPool.QueueUserWorkItem( + delegate(object o) + { + int threadIndex = (int)o; + + while (exception == null) + { + T entry; + + lock (enumerator) + { + if (!enumerator.MoveNext()) + break; + entry = (T)enumerator.Current; // Explicit typecast for Mono's sake + } + + try { body(entry); } + catch (Exception ex) { exception = ex; break; } + } + + if (Interlocked.Decrement(ref counter) == 0) + threadFinishEvent.Set(); + }, i + ); + } + + threadFinishEvent.WaitOne(); + + if (exception != null) + throw exception; + } + + /// + /// Executes a series of tasks in parallel + /// + /// A series of method bodies to execute + public static void Invoke(params Action[] actions) + { + Invoke(processorCount, actions); + } + + /// + /// Executes a series of tasks in parallel + /// + /// The number of concurrent execution threads to run + /// A series of method bodies to execute + public static void Invoke(int threadCount, params Action[] actions) + { + int counter = threadCount; + AutoResetEvent threadFinishEvent = new AutoResetEvent(false); + int index = -1; + Exception exception = null; + + for (int i = 0; i < threadCount; i++) + { + WorkPool.QueueUserWorkItem( + delegate(object o) + { + int threadIndex = (int)o; + + while (exception == null) + { + int currentIndex = Interlocked.Increment(ref index); + + if (currentIndex >= actions.Length) + break; + + try { actions[currentIndex](); } + catch (Exception ex) { exception = ex; break; } + } + + if (Interlocked.Decrement(ref counter) == 0) + threadFinishEvent.Set(); + }, i + ); + } + + threadFinishEvent.WaitOne(); + + if (exception != null) + throw exception; + } + } +} diff --git a/OpenMetaverse/ParcelManager.cs b/OpenMetaverse/ParcelManager.cs new file mode 100644 index 0000000..9cb48cd --- /dev/null +++ b/OpenMetaverse/ParcelManager.cs @@ -0,0 +1,2280 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using System.Reflection; +using System.Collections.Generic; +using OpenMetaverse.Http; +using OpenMetaverse.Packets; +using OpenMetaverse.Interfaces; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Messages.Linden; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// Type of return to use when returning objects from a parcel + /// + public enum ObjectReturnType : uint + { + /// + None = 0, + /// Return objects owned by parcel owner + Owner = 1 << 1, + /// Return objects set to group + Group = 1 << 2, + /// Return objects not owned by parcel owner or set to group + Other = 1 << 3, + /// Return a specific list of objects on parcel + List = 1 << 4, + /// Return objects that are marked for-sale + Sell = 1 << 5 + } + + /// + /// Blacklist/Whitelist flags used in parcels Access List + /// + public enum ParcelAccessFlags : uint + { + /// Agent is denied access + NoAccess = 0, + /// Agent is granted access + Access = 1 + } + + /// + /// The result of a request for parcel properties + /// + public enum ParcelResult : int + { + /// No matches were found for the request + NoData = -1, + /// Request matched a single parcel + Single = 0, + /// Request matched multiple parcels + Multiple = 1 + } + + /// + /// Flags used in the ParcelAccessListRequest packet to specify whether + /// we want the access list (whitelist), ban list (blacklist), or both + /// + [Flags] + public enum AccessList : uint + { + /// Request the access list + Access = 1 << 0, + /// Request the ban list + Ban = 1 << 1, + /// Request both White and Black lists + Both = Access | Ban + } + + /// + /// Sequence ID in ParcelPropertiesReply packets (sent when avatar + /// tries to cross a parcel border) + /// + public enum ParcelPropertiesStatus : int + { + /// Parcel is currently selected + ParcelSelected = -10000, + /// Parcel restricted to a group the avatar is not a + /// member of + CollisionNotInGroup = -20000, + /// Avatar is banned from the parcel + CollisionBanned = -30000, + /// Parcel is restricted to an access list that the + /// avatar is not on + CollisionNotOnAccessList = -40000, + /// Response to hovering over a parcel + HoveredOverParcel = -50000 + } + + /// + /// The tool to use when modifying terrain levels + /// + public enum TerraformAction : byte + { + /// Level the terrain + Level = 0, + /// Raise the terrain + Raise = 1, + /// Lower the terrain + Lower = 2, + /// Smooth the terrain + Smooth = 3, + /// Add random noise to the terrain + Noise = 4, + /// Revert terrain to simulator default + Revert = 5 + } + + /// + /// The tool size to use when changing terrain levels + /// + public enum TerraformBrushSize : byte + { + /// Small + Small = 1, + /// Medium + Medium = 2, + /// Large + Large = 4 + } + + /// + /// Reasons agent is denied access to a parcel on the simulator + /// + public enum AccessDeniedReason : byte + { + /// Agent is not denied, access is granted + NotDenied = 0, + /// Agent is not a member of the group set for the parcel, or which owns the parcel + NotInGroup = 1, + /// Agent is not on the parcels specific allow list + NotOnAllowList = 2, + /// Agent is on the parcels ban list + BannedFromParcel = 3, + /// Unknown + NoAccess = 4, + /// Agent is not age verified and parcel settings deny access to non age verified avatars + NotAgeVerified = 5 + } + + /// + /// Parcel overlay type. This is used primarily for highlighting and + /// coloring which is why it is a single integer instead of a set of + /// flags + /// + /// These values seem to be poorly thought out. The first three + /// bits represent a single value, not flags. For example Auction (0x05) is + /// not a combination of OwnedByOther (0x01) and ForSale(0x04). However, + /// the BorderWest and BorderSouth values are bit flags that get attached + /// to the value stored in the first three bits. Bits four, five, and six + /// are unused + [Flags] + public enum ParcelOverlayType : byte + { + /// Public land + Public = 0, + /// Land is owned by another avatar + OwnedByOther = 1, + /// Land is owned by a group + OwnedByGroup = 2, + /// Land is owned by the current avatar + OwnedBySelf = 3, + /// Land is for sale + ForSale = 4, + /// Land is being auctioned + Auction = 5, + /// Land is private + Private = 32, + /// To the west of this area is a parcel border + BorderWest = 64, + /// To the south of this area is a parcel border + BorderSouth = 128 + } + + /// + /// Various parcel properties + /// + [Flags] + public enum ParcelFlags : uint + { + /// No flags set + None = 0, + /// Allow avatars to fly (a client-side only restriction) + AllowFly = 1 << 0, + /// Allow foreign scripts to run + AllowOtherScripts = 1 << 1, + /// This parcel is for sale + ForSale = 1 << 2, + /// Allow avatars to create a landmark on this parcel + AllowLandmark = 1 << 3, + /// Allows all avatars to edit the terrain on this parcel + AllowTerraform = 1 << 4, + /// Avatars have health and can take damage on this parcel. + /// If set, avatars can be killed and sent home here + AllowDamage = 1 << 5, + /// Foreign avatars can create objects here + CreateObjects = 1 << 6, + /// All objects on this parcel can be purchased + ForSaleObjects = 1 << 7, + /// Access is restricted to a group + UseAccessGroup = 1 << 8, + /// Access is restricted to a whitelist + UseAccessList = 1 << 9, + /// Ban blacklist is enabled + UseBanList = 1 << 10, + /// Unknown + UsePassList = 1 << 11, + /// List this parcel in the search directory + ShowDirectory = 1 << 12, + /// Allow personally owned parcels to be deeded to group + AllowDeedToGroup = 1 << 13, + /// If Deeded, owner contributes required tier to group parcel is deeded to + ContributeWithDeed = 1 << 14, + /// Restrict sounds originating on this parcel to the + /// parcel boundaries + SoundLocal = 1 << 15, + /// Objects on this parcel are sold when the land is + /// purchsaed + SellParcelObjects = 1 << 16, + /// Allow this parcel to be published on the web + AllowPublish = 1 << 17, + /// The information for this parcel is mature content + MaturePublish = 1 << 18, + /// The media URL is an HTML page + UrlWebPage = 1 << 19, + /// The media URL is a raw HTML string + UrlRawHtml = 1 << 20, + /// Restrict foreign object pushes + RestrictPushObject = 1 << 21, + /// Ban all non identified/transacted avatars + DenyAnonymous = 1 << 22, + // Ban all identified avatars [OBSOLETE] + //[Obsolete] + // This was obsoleted in 1.19.0 but appears to be recycled and is used on linden homes parcels + LindenHome = 1 << 23, + // Ban all transacted avatars [OBSOLETE] + //[Obsolete] + //DenyTransacted = 1 << 24, + /// Allow group-owned scripts to run + AllowGroupScripts = 1 << 25, + /// Allow object creation by group members or group + /// objects + CreateGroupObjects = 1 << 26, + /// Allow all objects to enter this parcel + AllowAPrimitiveEntry = 1 << 27, + /// Only allow group and owner objects to enter this parcel + AllowGroupObjectEntry = 1 << 28, + /// Voice Enabled on this parcel + AllowVoiceChat = 1 << 29, + /// Use Estate Voice channel for Voice on this parcel + UseEstateVoiceChan = 1 << 30, + /// Deny Age Unverified Users + DenyAgeUnverified = 1U << 31 + } + + /// + /// Parcel ownership status + /// + public enum ParcelStatus : sbyte + { + /// Placeholder + None = -1, + /// Parcel is leased (owned) by an avatar or group + Leased = 0, + /// Parcel is in process of being leased (purchased) by an avatar or group + LeasePending = 1, + /// Parcel has been abandoned back to Governor Linden + Abandoned = 2 + } + + /// + /// Category parcel is listed in under search + /// + public enum ParcelCategory : sbyte + { + /// No assigned category + None = 0, + /// Linden Infohub or public area + Linden, + /// Adult themed area + Adult, + /// Arts and Culture + Arts, + /// Business + Business, + /// Educational + Educational, + /// Gaming + Gaming, + /// Hangout or Club + Hangout, + /// Newcomer friendly + Newcomer, + /// Parks and Nature + Park, + /// Residential + Residential, + /// Shopping + Shopping, + /// Not Used? + Stage, + /// Other + Other, + /// Not an actual category, only used for queries + Any = -1 + } + + /// + /// Type of teleport landing for a parcel + /// + public enum LandingType : byte + { + /// Unset, simulator default + None = 0, + /// Specific landing point set for this parcel + LandingPoint = 1, + /// No landing point set, direct teleports enabled for + /// this parcel + Direct = 2 + } + + /// + /// Parcel Media Command used in ParcelMediaCommandMessage + /// + public enum ParcelMediaCommand : uint + { + /// Stop the media stream and go back to the first frame + Stop = 0, + /// Pause the media stream (stop playing but stay on current frame) + Pause, + /// Start the current media stream playing and stop when the end is reached + Play, + /// Start the current media stream playing, + /// loop to the beginning when the end is reached and continue to play + Loop, + /// Specifies the texture to replace with video + /// If passing the key of a texture, it must be explicitly typecast as a key, + /// not just passed within double quotes. + Texture, + /// Specifies the movie URL (254 characters max) + URL, + /// Specifies the time index at which to begin playing + Time, + /// Specifies a single agent to apply the media command to + Agent, + /// Unloads the stream. While the stop command sets the texture to the first frame of the movie, + /// unload resets it to the real texture that the movie was replacing. + Unload, + /// Turn on/off the auto align feature, similar to the auto align checkbox in the parcel media properties + /// (NOT to be confused with the "align" function in the textures view of the editor!) Takes TRUE or FALSE as parameter. + AutoAlign, + /// Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). + /// Use "text/html" for HTML. + Type, + /// Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). + /// This might still not be working + Size, + /// Sets a description for the media being displayed (1.19.1 RC0 and later only). + Desc + } + + #endregion Enums + + #region Structs + + /// + /// Some information about a parcel of land returned from a DirectoryManager search + /// + public struct ParcelInfo + { + /// Global Key of record + public UUID ID; + /// Parcel Owners + public UUID OwnerID; + /// Name field of parcel, limited to 128 characters + public string Name; + /// Description field of parcel, limited to 256 characters + public string Description; + /// Total Square meters of parcel + public int ActualArea; + /// Total area billable as Tier, for group owned land this will be 10% less than ActualArea + public int BillableArea; + /// True of parcel is in Mature simulator + public bool Mature; + /// Grid global X position of parcel + public float GlobalX; + /// Grid global Y position of parcel + public float GlobalY; + /// Grid global Z position of parcel (not used) + public float GlobalZ; + /// Name of simulator parcel is located in + public string SimName; + /// Texture of parcels display picture + public UUID SnapshotID; + /// Float representing calculated traffic based on time spent on parcel by avatars + public float Dwell; + /// Sale price of parcel (not used) + public int SalePrice; + /// Auction ID of parcel + public int AuctionID; + } + + /// + /// Parcel Media Information + /// + public struct ParcelMedia + { + /// A byte, if 0x1 viewer should auto scale media to fit object + public bool MediaAutoScale; + /// A boolean, if true the viewer should loop the media + public bool MediaLoop; + /// The Asset UUID of the Texture which when applied to a + /// primitive will display the media + public UUID MediaID; + /// A URL which points to any Quicktime supported media type + public string MediaURL; + /// A description of the media + public string MediaDesc; + /// An Integer which represents the height of the media + public int MediaHeight; + /// An integer which represents the width of the media + public int MediaWidth; + /// A string which contains the mime type of the media + public string MediaType; + } + + #endregion Structs + + #region Parcel Class + + /// + /// Parcel of land, a portion of virtual real estate in a simulator + /// + public class Parcel + { + /// The total number of contiguous 4x4 meter blocks your agent owns within this parcel + public int SelfCount; + /// The total number of contiguous 4x4 meter blocks contained in this parcel owned by a group or agent other than your own + public int OtherCount; + /// Deprecated, Value appears to always be 0 + public int PublicCount; + /// Simulator-local ID of this parcel + public int LocalID; + /// UUID of the owner of this parcel + public UUID OwnerID; + /// Whether the land is deeded to a group or not + public bool IsGroupOwned; + /// + public uint AuctionID; + /// Date land was claimed + public DateTime ClaimDate; + /// Appears to always be zero + public int ClaimPrice; + /// This field is no longer used + public int RentPrice; + /// Minimum corner of the axis-aligned bounding box for this + /// parcel + public Vector3 AABBMin; + /// Maximum corner of the axis-aligned bounding box for this + /// parcel + public Vector3 AABBMax; + /// Bitmap describing land layout in 4x4m squares across the + /// entire region + public byte[] Bitmap; + /// Total parcel land area + public int Area; + /// + public ParcelStatus Status; + /// Maximum primitives across the entire simulator owned by the same agent or group that owns this parcel that can be used + public int SimWideMaxPrims; + /// Total primitives across the entire simulator calculated by combining the allowed prim counts for each parcel + /// owned by the agent or group that owns this parcel + public int SimWideTotalPrims; + /// Maximum number of primitives this parcel supports + public int MaxPrims; + /// Total number of primitives on this parcel + public int TotalPrims; + /// For group-owned parcels this indicates the total number of prims deeded to the group, + /// for parcels owned by an individual this inicates the number of prims owned by the individual + public int OwnerPrims; + /// Total number of primitives owned by the parcel group on + /// this parcel, or for parcels owned by an individual with a group set the + /// total number of prims set to that group. + public int GroupPrims; + /// Total number of prims owned by other avatars that are not set to group, or not the parcel owner + public int OtherPrims; + /// A bonus multiplier which allows parcel prim counts to go over times this amount, this does not affect + /// the max prims per simulator. e.g: 117 prim parcel limit x 1.5 bonus = 175 allowed + public float ParcelPrimBonus; + /// Autoreturn value in minutes for others' objects + public int OtherCleanTime; + /// + public ParcelFlags Flags; + /// Sale price of the parcel, only useful if ForSale is set + /// The SalePrice will remain the same after an ownership + /// transfer (sale), so it can be used to see the purchase price after + /// a sale if the new owner has not changed it + public int SalePrice; + /// Parcel Name + public string Name; + /// Parcel Description + public string Desc; + /// URL For Music Stream + public string MusicURL; + /// + public UUID GroupID; + /// Price for a temporary pass + public int PassPrice; + /// How long is pass valid for + public float PassHours; + /// + public ParcelCategory Category; + /// Key of authorized buyer + public UUID AuthBuyerID; + /// Key of parcel snapshot + public UUID SnapshotID; + /// The landing point location + public Vector3 UserLocation; + /// The landing point LookAt + public Vector3 UserLookAt; + /// The type of landing enforced from the enum + public LandingType Landing; + /// + public float Dwell; + /// + public bool RegionDenyAnonymous; + /// + public bool RegionPushOverride; + /// Access list of who is whitelisted on this + /// parcel + public List AccessWhiteList; + /// Access list of who is blacklisted on this + /// parcel + public List AccessBlackList; + /// TRUE of region denies access to age unverified users + public bool RegionDenyAgeUnverified; + /// true to obscure (hide) media url + public bool ObscureMedia; + /// true to obscure (hide) music url + public bool ObscureMusic; + /// A struct containing media details + public ParcelMedia Media; + + /// + /// Displays a parcel object in string format + /// + /// string containing key=value pairs of a parcel object + public override string ToString() + { + string result = ""; + Type parcelType = this.GetType(); + FieldInfo[] fields = parcelType.GetFields(); + foreach (FieldInfo field in fields) + { + result += (field.Name + " = " + field.GetValue(this) + " "); + } + return result; + } + /// + /// Defalt constructor + /// + /// Local ID of this parcel + public Parcel(int localID) + { + LocalID = localID; + ClaimDate = Utils.Epoch; + Bitmap = Utils.EmptyBytes; + Name = String.Empty; + Desc = String.Empty; + MusicURL = String.Empty; + AccessWhiteList = new List(0); + AccessBlackList = new List(0); + Media = new ParcelMedia(); + } + + /// + /// Update the simulator with any local changes to this Parcel object + /// + /// Simulator to send updates to + /// Whether we want the simulator to confirm + /// the update with a reply packet or not + public void Update(Simulator simulator, bool wantReply) + { + Uri url = simulator.Caps.CapabilityURI("ParcelPropertiesUpdate"); + + if (url != null) + { + ParcelPropertiesUpdateMessage req = new ParcelPropertiesUpdateMessage(); + req.AuthBuyerID = this.AuthBuyerID; + req.Category = this.Category; + req.Desc = this.Desc; + req.GroupID = this.GroupID; + req.Landing = this.Landing; + req.LocalID = this.LocalID; + req.MediaAutoScale = this.Media.MediaAutoScale; + req.MediaDesc = this.Media.MediaDesc; + req.MediaHeight = this.Media.MediaHeight; + req.MediaID = this.Media.MediaID; + req.MediaLoop = this.Media.MediaLoop; + req.MediaType = this.Media.MediaType; + req.MediaURL = this.Media.MediaURL; + req.MediaWidth = this.Media.MediaWidth; + req.MusicURL = this.MusicURL; + req.Name = this.Name; + req.ObscureMedia = this.ObscureMedia; + req.ObscureMusic = this.ObscureMusic; + req.ParcelFlags = this.Flags; + req.PassHours = this.PassHours; + req.PassPrice = (uint)this.PassPrice; + req.SalePrice = (uint)this.SalePrice; + req.SnapshotID = this.SnapshotID; + req.UserLocation = this.UserLocation; + req.UserLookAt = this.UserLookAt; + + OSDMap body = req.Serialize(); + + CapsClient capsPost = new CapsClient(url); + capsPost.BeginGetResponse(body, OSDFormat.Xml, simulator.Client.Settings.CAPS_TIMEOUT); + } + else + { + ParcelPropertiesUpdatePacket request = new ParcelPropertiesUpdatePacket(); + + request.AgentData.AgentID = simulator.Client.Self.AgentID; + request.AgentData.SessionID = simulator.Client.Self.SessionID; + + request.ParcelData.LocalID = this.LocalID; + + request.ParcelData.AuthBuyerID = this.AuthBuyerID; + request.ParcelData.Category = (byte)this.Category; + request.ParcelData.Desc = Utils.StringToBytes(this.Desc); + request.ParcelData.GroupID = this.GroupID; + request.ParcelData.LandingType = (byte)this.Landing; + request.ParcelData.MediaAutoScale = (this.Media.MediaAutoScale) ? (byte)0x1 : (byte)0x0; + request.ParcelData.MediaID = this.Media.MediaID; + request.ParcelData.MediaURL = Utils.StringToBytes(this.Media.MediaURL.ToString()); + request.ParcelData.MusicURL = Utils.StringToBytes(this.MusicURL.ToString()); + request.ParcelData.Name = Utils.StringToBytes(this.Name); + if (wantReply) request.ParcelData.Flags = 1; + request.ParcelData.ParcelFlags = (uint)this.Flags; + request.ParcelData.PassHours = this.PassHours; + request.ParcelData.PassPrice = this.PassPrice; + request.ParcelData.SalePrice = this.SalePrice; + request.ParcelData.SnapshotID = this.SnapshotID; + request.ParcelData.UserLocation = this.UserLocation; + request.ParcelData.UserLookAt = this.UserLookAt; + + simulator.SendPacket(request); + } + + UpdateOtherCleanTime(simulator); + + } + + /// + /// Set Autoreturn time + /// + /// Simulator to send the update to + public void UpdateOtherCleanTime(Simulator simulator) + { + ParcelSetOtherCleanTimePacket request = new ParcelSetOtherCleanTimePacket(); + request.AgentData.AgentID = simulator.Client.Self.AgentID; + request.AgentData.SessionID = simulator.Client.Self.SessionID; + request.ParcelData.LocalID = this.LocalID; + request.ParcelData.OtherCleanTime = this.OtherCleanTime; + + simulator.SendPacket(request); + } + } + + #endregion Parcel Class + + /// + /// Parcel (subdivided simulator lots) subsystem + /// + public class ParcelManager + { + #region Structs + + /// + /// Parcel Accesslist + /// + public struct ParcelAccessEntry + { + /// Agents + public UUID AgentID; + /// + public DateTime Time; + /// Flags for specific entry in white/black lists + public AccessList Flags; + } + + /// + /// Owners of primitives on parcel + /// + public struct ParcelPrimOwners + { + /// Prim Owners + public UUID OwnerID; + /// True of owner is group + public bool IsGroupOwned; + /// Total count of prims owned by OwnerID + public int Count; + /// true of OwnerID is currently online and is not a group + public bool OnlineStatus; + /// The date of the most recent prim left by OwnerID + public DateTime NewestPrim; + } + + #endregion Structs + + #region Delegates + /// + /// Called once parcel resource usage information has been collected + /// + /// Indicates if operation was successfull + /// Parcel resource usage information + public delegate void LandResourcesCallback(bool success, LandResourcesInfo info); + + /// The event subscribers. null if no subcribers + private EventHandler m_DwellReply; + + /// Raises the ParcelDwellReply event + /// A ParcelDwellReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnParcelDwellReply(ParcelDwellReplyEventArgs e) + { + EventHandler handler = m_DwellReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_DwellReplyLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler ParcelDwellReply + { + add { lock (m_DwellReplyLock) { m_DwellReply += value; } } + remove { lock (m_DwellReplyLock) { m_DwellReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ParcelInfo; + + /// Raises the ParcelInfoReply event + /// A ParcelInfoReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnParcelInfoReply(ParcelInfoReplyEventArgs e) + { + EventHandler handler = m_ParcelInfo; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ParcelInfoLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler ParcelInfoReply + { + add { lock (m_ParcelInfoLock) { m_ParcelInfo += value; } } + remove { lock (m_ParcelInfoLock) { m_ParcelInfo -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ParcelProperties; + + /// Raises the ParcelProperties event + /// A ParcelPropertiesEventArgs object containing the + /// data returned from the simulator + protected virtual void OnParcelProperties(ParcelPropertiesEventArgs e) + { + EventHandler handler = m_ParcelProperties; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ParcelPropertiesLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler ParcelProperties + { + add { lock (m_ParcelPropertiesLock) { m_ParcelProperties += value; } } + remove { lock (m_ParcelPropertiesLock) { m_ParcelProperties -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ParcelACL; + + /// Raises the ParcelAccessListReply event + /// A ParcelAccessListReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnParcelAccessListReply(ParcelAccessListReplyEventArgs e) + { + EventHandler handler = m_ParcelACL; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ParcelACLLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler ParcelAccessListReply + { + add { lock (m_ParcelACLLock) { m_ParcelACL += value; } } + remove { lock (m_ParcelACLLock) { m_ParcelACL -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ParcelObjectOwnersReply; + + /// Raises the ParcelObjectOwnersReply event + /// A ParcelObjectOwnersReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnParcelObjectOwnersReply(ParcelObjectOwnersReplyEventArgs e) + { + EventHandler handler = m_ParcelObjectOwnersReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ParcelObjectOwnersLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler ParcelObjectOwnersReply + { + add { lock (m_ParcelObjectOwnersLock) { m_ParcelObjectOwnersReply += value; } } + remove { lock (m_ParcelObjectOwnersLock) { m_ParcelObjectOwnersReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_SimParcelsDownloaded; + + /// Raises the SimParcelsDownloaded event + /// A SimParcelsDownloadedEventArgs object containing the + /// data returned from the simulator + protected virtual void OnSimParcelsDownloaded(SimParcelsDownloadedEventArgs e) + { + EventHandler handler = m_SimParcelsDownloaded; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SimParcelsDownloadedLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler SimParcelsDownloaded + { + add { lock (m_SimParcelsDownloadedLock) { m_SimParcelsDownloaded += value; } } + remove { lock (m_SimParcelsDownloadedLock) { m_SimParcelsDownloaded -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ForceSelectObjects; + + /// Raises the ForceSelectObjectsReply event + /// A ForceSelectObjectsReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnForceSelectObjectsReply(ForceSelectObjectsReplyEventArgs e) + { + EventHandler handler = m_ForceSelectObjects; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ForceSelectObjectsLock = new object(); + + /// Raised when the simulator responds to a request + public event EventHandler ForceSelectObjectsReply + { + add { lock (m_ForceSelectObjectsLock) { m_ForceSelectObjects += value; } } + remove { lock (m_ForceSelectObjectsLock) { m_ForceSelectObjects -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ParcelMediaUpdateReply; + + /// Raises the ParcelMediaUpdateReply event + /// A ParcelMediaUpdateReplyEventArgs object containing the + /// data returned from the simulator + protected virtual void OnParcelMediaUpdateReply(ParcelMediaUpdateReplyEventArgs e) + { + EventHandler handler = m_ParcelMediaUpdateReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ParcelMediaUpdateReplyLock = new object(); + + /// Raised when the simulator responds to a Parcel Update request + public event EventHandler ParcelMediaUpdateReply + { + add { lock (m_ParcelMediaUpdateReplyLock) { m_ParcelMediaUpdateReply += value; } } + remove { lock (m_ParcelMediaUpdateReplyLock) { m_ParcelMediaUpdateReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_ParcelMediaCommand; + + /// Raises the ParcelMediaCommand event + /// A ParcelMediaCommandEventArgs object containing the + /// data returned from the simulator + protected virtual void OnParcelMediaCommand(ParcelMediaCommandEventArgs e) + { + EventHandler handler = m_ParcelMediaCommand; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_ParcelMediaCommandLock = new object(); + + /// Raised when the parcel your agent is located sends a ParcelMediaCommand + public event EventHandler ParcelMediaCommand + { + add { lock (m_ParcelMediaCommandLock) { m_ParcelMediaCommand += value; } } + remove { lock (m_ParcelMediaCommandLock) { m_ParcelMediaCommand -= value; } } + } + #endregion Delegates + + private GridClient Client; + private AutoResetEvent WaitForSimParcel; + + #region Public Methods + + /// + /// Default constructor + /// + /// A reference to the GridClient object + public ParcelManager(GridClient client) + { + Client = client; + + // Setup the callbacks + Client.Network.RegisterCallback(PacketType.ParcelInfoReply, ParcelInfoReplyHandler); + Client.Network.RegisterEventCallback("ParcelObjectOwnersReply", new Caps.EventQueueCallback(ParcelObjectOwnersReplyHandler)); + // CAPS packet handler, to allow for Media Data not contained in the message template + Client.Network.RegisterEventCallback("ParcelProperties", new Caps.EventQueueCallback(ParcelPropertiesReplyHandler)); + Client.Network.RegisterCallback(PacketType.ParcelDwellReply, ParcelDwellReplyHandler); + Client.Network.RegisterCallback(PacketType.ParcelAccessListReply, ParcelAccessListReplyHandler); + Client.Network.RegisterCallback(PacketType.ForceObjectSelect, SelectParcelObjectsReplyHandler); + Client.Network.RegisterCallback(PacketType.ParcelMediaUpdate, ParcelMediaUpdateHandler); + Client.Network.RegisterCallback(PacketType.ParcelOverlay, ParcelOverlayHandler); + Client.Network.RegisterCallback(PacketType.ParcelMediaCommandMessage, ParcelMediaCommandMessagePacketHandler); + } + + /// + /// Request basic information for a single parcel + /// + /// Simulator-local ID of the parcel + public void RequestParcelInfo(UUID parcelID) + { + ParcelInfoRequestPacket request = new ParcelInfoRequestPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.Data.ParcelID = parcelID; + + Client.Network.SendPacket(request); + } + + /// + /// Request properties of a single parcel + /// + /// Simulator containing the parcel + /// Simulator-local ID of the parcel + /// An arbitrary integer that will be returned + /// with the ParcelProperties reply, useful for distinguishing between + /// multiple simultaneous requests + public void RequestParcelProperties(Simulator simulator, int localID, int sequenceID) + { + ParcelPropertiesRequestByIDPacket request = new ParcelPropertiesRequestByIDPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + request.ParcelData.LocalID = localID; + request.ParcelData.SequenceID = sequenceID; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Request the access list for a single parcel + /// + /// Simulator containing the parcel + /// Simulator-local ID of the parcel + /// An arbitrary integer that will be returned + /// with the ParcelAccessList reply, useful for distinguishing between + /// multiple simultaneous requests + /// + public void RequestParcelAccessList(Simulator simulator, int localID, AccessList flags, int sequenceID) + { + ParcelAccessListRequestPacket request = new ParcelAccessListRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.Data.LocalID = localID; + request.Data.Flags = (uint)flags; + request.Data.SequenceID = sequenceID; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Request properties of parcels using a bounding box selection + /// + /// Simulator containing the parcel + /// Northern boundary of the parcel selection + /// Eastern boundary of the parcel selection + /// Southern boundary of the parcel selection + /// Western boundary of the parcel selection + /// An arbitrary integer that will be returned + /// with the ParcelProperties reply, useful for distinguishing between + /// different types of parcel property requests + /// A boolean that is returned with the + /// ParcelProperties reply, useful for snapping focus to a single + /// parcel + public void RequestParcelProperties(Simulator simulator, float north, float east, float south, float west, + int sequenceID, bool snapSelection) + { + ParcelPropertiesRequestPacket request = new ParcelPropertiesRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.ParcelData.North = north; + request.ParcelData.East = east; + request.ParcelData.South = south; + request.ParcelData.West = west; + request.ParcelData.SequenceID = sequenceID; + request.ParcelData.SnapSelection = snapSelection; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Request all simulator parcel properties (used for populating the Simulator.Parcels + /// dictionary) + /// + /// Simulator to request parcels from (must be connected) + public void RequestAllSimParcels(Simulator simulator) + { + RequestAllSimParcels(simulator, false, 750); + } + + /// + /// Request all simulator parcel properties (used for populating the Simulator.Parcels + /// dictionary) + /// + /// Simulator to request parcels from (must be connected) + /// If TRUE, will force a full refresh + /// Number of milliseconds to pause in between each request + public void RequestAllSimParcels(Simulator simulator, bool refresh, int msDelay) + { + if (simulator.DownloadingParcelMap) + { + Logger.Log("Already downloading parcels in " + simulator.Name, Helpers.LogLevel.Info, Client); + return; + } + else + { + simulator.DownloadingParcelMap = true; + WaitForSimParcel = new AutoResetEvent(false); + } + + if (refresh) + { + for (int y = 0; y < 64; y++) + for (int x = 0; x < 64; x++) + simulator.ParcelMap[y, x] = 0; + } + + Thread th = new Thread(delegate() + { + int count = 0, timeouts = 0, y, x; + + for (y = 0; y < 64; y++) + { + for (x = 0; x < 64; x++) + { + if (!Client.Network.Connected) + return; + + if (simulator.ParcelMap[y, x] == 0) + { + Client.Parcels.RequestParcelProperties(simulator, + (y + 1) * 4.0f, (x + 1) * 4.0f, + y * 4.0f, x * 4.0f, int.MaxValue, false); + + // Wait the given amount of time for a reply before sending the next request + if (!WaitForSimParcel.WaitOne(msDelay, false)) + ++timeouts; + + ++count; + } + } + } + + Logger.Log(String.Format( + "Full simulator parcel information retrieved. Sent {0} parcel requests. Current outgoing queue: {1}, Retry Count {2}", + count, Client.Network.OutboxCount, timeouts), Helpers.LogLevel.Info, Client); + + simulator.DownloadingParcelMap = false; + }); + + th.Start(); + } + + /// + /// Request the dwell value for a parcel + /// + /// Simulator containing the parcel + /// Simulator-local ID of the parcel + public void RequestDwell(Simulator simulator, int localID) + { + ParcelDwellRequestPacket request = new ParcelDwellRequestPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + request.Data.LocalID = localID; + request.Data.ParcelID = UUID.Zero; // Not used by clients + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Send a request to Purchase a parcel of land + /// + /// The Simulator the parcel is located in + /// The parcels region specific local ID + /// true if this parcel is being purchased by a group + /// The groups + /// true to remove tier contribution if purchase is successful + /// The parcels size + /// The purchase price of the parcel + /// + public void Buy(Simulator simulator, int localID, bool forGroup, UUID groupID, + bool removeContribution, int parcelArea, int parcelPrice) + { + ParcelBuyPacket request = new ParcelBuyPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + request.Data.Final = true; + request.Data.GroupID = groupID; + request.Data.LocalID = localID; + request.Data.IsGroupOwned = forGroup; + request.Data.RemoveContribution = removeContribution; + + request.ParcelData.Area = parcelArea; + request.ParcelData.Price = parcelPrice; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Reclaim a parcel of land + /// + /// The simulator the parcel is in + /// The parcels region specific local ID + public void Reclaim(Simulator simulator, int localID) + { + ParcelReclaimPacket request = new ParcelReclaimPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + request.Data.LocalID = localID; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Deed a parcel to a group + /// + /// The simulator the parcel is in + /// The parcels region specific local ID + /// The groups + public void DeedToGroup(Simulator simulator, int localID, UUID groupID) + { + ParcelDeedToGroupPacket request = new ParcelDeedToGroupPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + request.Data.LocalID = localID; + request.Data.GroupID = groupID; + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Request prim owners of a parcel of land. + /// + /// Simulator parcel is in + /// The parcels region specific local ID + public void RequestObjectOwners(Simulator simulator, int localID) + { + ParcelObjectOwnersRequestPacket request = new ParcelObjectOwnersRequestPacket(); + + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + request.ParcelData.LocalID = localID; + Client.Network.SendPacket(request, simulator); + } + + /// + /// Return objects from a parcel + /// + /// Simulator parcel is in + /// The parcels region specific local ID + /// the type of objects to return, + /// A list containing object owners s to return + public void ReturnObjects(Simulator simulator, int localID, ObjectReturnType type, List ownerIDs) + { + ParcelReturnObjectsPacket request = new ParcelReturnObjectsPacket(); + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; + + request.ParcelData.LocalID = localID; + request.ParcelData.ReturnType = (uint)type; + + // A single null TaskID is (not) used for parcel object returns + request.TaskIDs = new ParcelReturnObjectsPacket.TaskIDsBlock[1]; + request.TaskIDs[0] = new ParcelReturnObjectsPacket.TaskIDsBlock(); + request.TaskIDs[0].TaskID = UUID.Zero; + + // Convert the list of owner UUIDs to packet blocks if a list is given + if (ownerIDs != null) + { + request.OwnerIDs = new ParcelReturnObjectsPacket.OwnerIDsBlock[ownerIDs.Count]; + + for (int i = 0; i < ownerIDs.Count; i++) + { + request.OwnerIDs[i] = new ParcelReturnObjectsPacket.OwnerIDsBlock(); + request.OwnerIDs[i].OwnerID = ownerIDs[i]; + } + } + else + { + request.OwnerIDs = new ParcelReturnObjectsPacket.OwnerIDsBlock[0]; + } + + Client.Network.SendPacket(request, simulator); + } + + /// + /// Subdivide (split) a parcel + /// + /// + /// + /// + /// + /// + public void ParcelSubdivide(Simulator simulator, float west, float south, float east, float north) + { + ParcelDividePacket divide = new ParcelDividePacket(); + divide.AgentData.AgentID = Client.Self.AgentID; + divide.AgentData.SessionID = Client.Self.SessionID; + divide.ParcelData.East = east; + divide.ParcelData.North = north; + divide.ParcelData.South = south; + divide.ParcelData.West = west; + + Client.Network.SendPacket(divide, simulator); + } + + /// + /// Join two parcels of land creating a single parcel + /// + /// + /// + /// + /// + /// + public void ParcelJoin(Simulator simulator, float west, float south, float east, float north) + { + ParcelJoinPacket join = new ParcelJoinPacket(); + join.AgentData.AgentID = Client.Self.AgentID; + join.AgentData.SessionID = Client.Self.SessionID; + join.ParcelData.East = east; + join.ParcelData.North = north; + join.ParcelData.South = south; + join.ParcelData.West = west; + + Client.Network.SendPacket(join, simulator); + } + + /// + /// Get a parcels LocalID + /// + /// Simulator parcel is in + /// Vector3 position in simulator (Z not used) + /// 0 on failure, or parcel LocalID on success. + /// A call to Parcels.RequestAllSimParcels is required to populate map and + /// dictionary. + public int GetParcelLocalID(Simulator simulator, Vector3 position) + { + if (simulator.ParcelMap[(byte)position.Y / 4, (byte)position.X / 4] > 0) + { + return simulator.ParcelMap[(byte)position.Y / 4, (byte)position.X / 4]; + } + else + { + Logger.Log(String.Format("ParcelMap returned an default/invalid value for location {0}/{1} Did you use RequestAllSimParcels() to populate the dictionaries?", (byte)position.Y / 4, (byte)position.X / 4 ), Helpers.LogLevel.Warning); + return 0; + } + } + + /// + /// Terraform (raise, lower, etc) an area or whole parcel of land + /// + /// Simulator land area is in. + /// LocalID of parcel, or -1 if using bounding box + /// From Enum, Raise, Lower, Level, Smooth, Etc. + /// Size of area to modify + /// true on successful request sent. + /// Settings.STORE_LAND_PATCHES must be true, + /// Parcel information must be downloaded using RequestAllSimParcels() + public bool Terraform(Simulator simulator, int localID, TerraformAction action, TerraformBrushSize brushSize) + { + return Terraform(simulator, localID, 0f, 0f, 0f, 0f, action, brushSize, 1); + } + + /// + /// Terraform (raise, lower, etc) an area or whole parcel of land + /// + /// Simulator land area is in. + /// west border of area to modify + /// south border of area to modify + /// east border of area to modify + /// north border of area to modify + /// From Enum, Raise, Lower, Level, Smooth, Etc. + /// Size of area to modify + /// true on successful request sent. + /// Settings.STORE_LAND_PATCHES must be true, + /// Parcel information must be downloaded using RequestAllSimParcels() + public bool Terraform(Simulator simulator, float west, float south, float east, float north, + TerraformAction action, TerraformBrushSize brushSize) + { + return Terraform(simulator, -1, west, south, east, north, action, brushSize, 1); + } + + /// + /// Terraform (raise, lower, etc) an area or whole parcel of land + /// + /// Simulator land area is in. + /// LocalID of parcel, or -1 if using bounding box + /// west border of area to modify + /// south border of area to modify + /// east border of area to modify + /// north border of area to modify + /// From Enum, Raise, Lower, Level, Smooth, Etc. + /// Size of area to modify + /// How many meters + or - to lower, 1 = 1 meter + /// true on successful request sent. + /// Settings.STORE_LAND_PATCHES must be true, + /// Parcel information must be downloaded using RequestAllSimParcels() + public bool Terraform(Simulator simulator, int localID, float west, float south, float east, float north, + TerraformAction action, TerraformBrushSize brushSize, int seconds) + { + float height = 0f; + int x, y; + if (localID == -1) + { + x = (int)east - (int)west / 2; + y = (int)north - (int)south / 2; + } + else + { + Parcel p; + if (!simulator.Parcels.TryGetValue(localID, out p)) + { + Logger.Log(String.Format("Can't find parcel {0} in simulator {1}", localID, simulator), + Helpers.LogLevel.Warning, Client); + return false; + } + + x = (int)p.AABBMax.X - (int)p.AABBMin.X / 2; + y = (int)p.AABBMax.Y - (int)p.AABBMin.Y / 2; + } + + if (!simulator.TerrainHeightAtPoint(x, y, out height)) + { + Logger.Log("Land Patch not stored for location", Helpers.LogLevel.Warning, Client); + return false; + } + + Terraform(simulator, localID, west, south, east, north, action, brushSize, seconds, height); + return true; + } + + /// + /// Terraform (raise, lower, etc) an area or whole parcel of land + /// + /// Simulator land area is in. + /// LocalID of parcel, or -1 if using bounding box + /// west border of area to modify + /// south border of area to modify + /// east border of area to modify + /// north border of area to modify + /// From Enum, Raise, Lower, Level, Smooth, Etc. + /// Size of area to modify + /// How many meters + or - to lower, 1 = 1 meter + /// Height at which the terraform operation is acting at + public void Terraform(Simulator simulator, int localID, float west, float south, float east, float north, + TerraformAction action, TerraformBrushSize brushSize, int seconds, float height) + { + ModifyLandPacket land = new ModifyLandPacket(); + land.AgentData.AgentID = Client.Self.AgentID; + land.AgentData.SessionID = Client.Self.SessionID; + + land.ModifyBlock.Action = (byte)action; + land.ModifyBlock.BrushSize = (byte)brushSize; + land.ModifyBlock.Seconds = seconds; + land.ModifyBlock.Height = height; + + land.ParcelData = new ModifyLandPacket.ParcelDataBlock[1]; + land.ParcelData[0] = new ModifyLandPacket.ParcelDataBlock(); + land.ParcelData[0].LocalID = localID; + land.ParcelData[0].West = west; + land.ParcelData[0].South = south; + land.ParcelData[0].East = east; + land.ParcelData[0].North = north; + + land.ModifyBlockExtended = new ModifyLandPacket.ModifyBlockExtendedBlock[1]; + land.ModifyBlockExtended[0] = new ModifyLandPacket.ModifyBlockExtendedBlock(); + land.ModifyBlockExtended[0].BrushSize = (float)brushSize; + + Client.Network.SendPacket(land, simulator); + } + + /// + /// Sends a request to the simulator to return a list of objects owned by specific owners + /// + /// Simulator local ID of parcel + /// Owners, Others, Etc + /// List containing keys of avatars objects to select; + /// if List is null will return Objects of type selectType + /// Response data is returned in the event + public void RequestSelectObjects(int localID, ObjectReturnType selectType, UUID ownerID) + { + ParcelSelectObjectsPacket select = new ParcelSelectObjectsPacket(); + select.AgentData.AgentID = Client.Self.AgentID; + select.AgentData.SessionID = Client.Self.SessionID; + + select.ParcelData.LocalID = localID; + select.ParcelData.ReturnType = (uint)selectType; + + select.ReturnIDs = new ParcelSelectObjectsPacket.ReturnIDsBlock[1]; + select.ReturnIDs[0] = new ParcelSelectObjectsPacket.ReturnIDsBlock(); + select.ReturnIDs[0].ReturnID = ownerID; + + Client.Network.SendPacket(select); + } + + /// + /// Eject and optionally ban a user from a parcel + /// + /// target key of avatar to eject + /// true to also ban target + public void EjectUser(UUID targetID, bool ban) + { + EjectUserPacket eject = new EjectUserPacket(); + eject.AgentData.AgentID = Client.Self.AgentID; + eject.AgentData.SessionID = Client.Self.SessionID; + eject.Data.TargetID = targetID; + if (ban) eject.Data.Flags = 1; + else eject.Data.Flags = 0; + + Client.Network.SendPacket(eject); + } + + /// + /// Freeze or unfreeze an avatar over your land + /// + /// target key to freeze + /// true to freeze, false to unfreeze + public void FreezeUser(UUID targetID, bool freeze) + { + FreezeUserPacket frz = new FreezeUserPacket(); + frz.AgentData.AgentID = Client.Self.AgentID; + frz.AgentData.SessionID = Client.Self.SessionID; + frz.Data.TargetID = targetID; + if (freeze) frz.Data.Flags = 0; + else frz.Data.Flags = 1; + + Client.Network.SendPacket(frz); + } + + /// + /// Abandon a parcel of land + /// + /// Simulator parcel is in + /// Simulator local ID of parcel + public void ReleaseParcel(Simulator simulator, int localID) + { + ParcelReleasePacket abandon = new ParcelReleasePacket(); + abandon.AgentData.AgentID = Client.Self.AgentID; + abandon.AgentData.SessionID = Client.Self.SessionID; + abandon.Data.LocalID = localID; + + Client.Network.SendPacket(abandon, simulator); + } + + /// + /// Requests the UUID of the parcel in a remote region at a specified location + /// + /// Location of the parcel in the remote region + /// Remote region handle + /// Remote region UUID + /// If successful UUID of the remote parcel, UUID.Zero otherwise + public UUID RequestRemoteParcelID(Vector3 location, ulong regionHandle, UUID regionID) + { + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) + return UUID.Zero; + + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("RemoteParcelRequest"); + + if (url != null) + { + RemoteParcelRequestRequest msg = new RemoteParcelRequestRequest(); + msg.Location = location; + msg.RegionHandle = regionHandle; + msg.RegionID = regionID; + + try + { + CapsClient request = new CapsClient(url); + OSD result = request.GetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + RemoteParcelRequestReply response = new RemoteParcelRequestReply(); + response.Deserialize((OSDMap)result); + return response.ParcelID; + } + catch (Exception) + { + Logger.Log("Failed to fetch remote parcel ID", Helpers.LogLevel.Debug, Client); + } + } + + return UUID.Zero; + + } + + /// + /// Retrieves information on resources used by the parcel + /// + /// UUID of the parcel + /// Should per object resource usage be requested + /// Callback invoked when the request is complete + public void GetParcelResouces(UUID parcelID, bool getDetails, LandResourcesCallback callback) + { + try + { + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("LandResources"); + CapsClient request = new CapsClient(url); + + request.OnComplete += delegate(CapsClient client, OSD result, Exception error) + { + try + { + if (result == null || error != null) + { + callback(false, null); + } + LandResourcesMessage response = new LandResourcesMessage(); + response.Deserialize((OSDMap)result); + + CapsClient summaryRequest = new CapsClient(response.ScriptResourceSummary); + OSD summaryResponse = summaryRequest.GetResponse(Client.Settings.CAPS_TIMEOUT); + + LandResourcesInfo res = new LandResourcesInfo(); + res.Deserialize((OSDMap)summaryResponse); + + if (response.ScriptResourceDetails != null && getDetails) + { + CapsClient detailRequest = new CapsClient(response.ScriptResourceDetails); + OSD detailResponse = detailRequest.GetResponse(Client.Settings.CAPS_TIMEOUT); + res.Deserialize((OSDMap)detailResponse); + } + callback(true, res); + } + catch (Exception ex) + { + Logger.Log("Failed fetching land resources", Helpers.LogLevel.Error, Client, ex); + callback(false, null); + } + }; + + LandResourcesRequest param = new LandResourcesRequest(); + param.ParcelID = parcelID; + request.BeginGetResponse(param.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + + } + catch (Exception ex) + { + Logger.Log("Failed fetching land resources:", Helpers.LogLevel.Error, Client, ex); + callback(false, null); + } + } + + #endregion Public Methods + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + /// Raises the event + protected void ParcelDwellReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_DwellReply != null || Client.Settings.ALWAYS_REQUEST_PARCEL_DWELL == true) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ParcelDwellReplyPacket dwell = (ParcelDwellReplyPacket)packet; + + lock (simulator.Parcels.Dictionary) + { + if (simulator.Parcels.Dictionary.ContainsKey(dwell.Data.LocalID)) + { + Parcel parcel = simulator.Parcels.Dictionary[dwell.Data.LocalID]; + parcel.Dwell = dwell.Data.Dwell; + simulator.Parcels.Dictionary[dwell.Data.LocalID] = parcel; + } + } + + if (m_DwellReply != null) + { + OnParcelDwellReply(new ParcelDwellReplyEventArgs(dwell.Data.ParcelID, dwell.Data.LocalID, dwell.Data.Dwell)); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + /// Raises the event + protected void ParcelInfoReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ParcelInfo != null) + { + Packet packet = e.Packet; + ParcelInfoReplyPacket info = (ParcelInfoReplyPacket)packet; + + ParcelInfo parcelInfo = new ParcelInfo(); + + parcelInfo.ActualArea = info.Data.ActualArea; + parcelInfo.AuctionID = info.Data.AuctionID; + parcelInfo.BillableArea = info.Data.BillableArea; + parcelInfo.Description = Utils.BytesToString(info.Data.Desc); + parcelInfo.Dwell = info.Data.Dwell; + parcelInfo.GlobalX = info.Data.GlobalX; + parcelInfo.GlobalY = info.Data.GlobalY; + parcelInfo.GlobalZ = info.Data.GlobalZ; + parcelInfo.ID = info.Data.ParcelID; + parcelInfo.Mature = ((info.Data.Flags & 1) != 0) ? true : false; + parcelInfo.Name = Utils.BytesToString(info.Data.Name); + parcelInfo.OwnerID = info.Data.OwnerID; + parcelInfo.SalePrice = info.Data.SalePrice; + parcelInfo.SimName = Utils.BytesToString(info.Data.SimName); + parcelInfo.SnapshotID = info.Data.SnapshotID; + + OnParcelInfoReply(new ParcelInfoReplyEventArgs(parcelInfo)); + } + } + + protected void ParcelPropertiesReplyHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_ParcelProperties != null || Client.Settings.PARCEL_TRACKING == true) + { + ParcelPropertiesMessage msg = (ParcelPropertiesMessage)message; + + Parcel parcel = new Parcel(msg.LocalID); + + parcel.AABBMax = msg.AABBMax; + parcel.AABBMin = msg.AABBMin; + parcel.Area = msg.Area; + parcel.AuctionID = msg.AuctionID; + parcel.AuthBuyerID = msg.AuthBuyerID; + parcel.Bitmap = msg.Bitmap; + parcel.Category = msg.Category; + parcel.ClaimDate = msg.ClaimDate; + parcel.ClaimPrice = msg.ClaimPrice; + parcel.Desc = msg.Desc; + parcel.Flags = msg.ParcelFlags; + parcel.GroupID = msg.GroupID; + parcel.GroupPrims = msg.GroupPrims; + parcel.IsGroupOwned = msg.IsGroupOwned; + parcel.Landing = msg.LandingType; + parcel.MaxPrims = msg.MaxPrims; + parcel.Media.MediaAutoScale = msg.MediaAutoScale; + parcel.Media.MediaID = msg.MediaID; + parcel.Media.MediaURL = msg.MediaURL; + parcel.MusicURL = msg.MusicURL; + parcel.Name = msg.Name; + parcel.OtherCleanTime = msg.OtherCleanTime; + parcel.OtherCount = msg.OtherCount; + parcel.OtherPrims = msg.OtherPrims; + parcel.OwnerID = msg.OwnerID; + parcel.OwnerPrims = msg.OwnerPrims; + parcel.ParcelPrimBonus = msg.ParcelPrimBonus; + parcel.PassHours = msg.PassHours; + parcel.PassPrice = msg.PassPrice; + parcel.PublicCount = msg.PublicCount; + parcel.RegionDenyAgeUnverified = msg.RegionDenyAgeUnverified; + parcel.RegionDenyAnonymous = msg.RegionDenyAnonymous; + parcel.RegionPushOverride = msg.RegionPushOverride; + parcel.RentPrice = msg.RentPrice; + ParcelResult result = msg.RequestResult; + parcel.SalePrice = msg.SalePrice; + int selectedPrims = msg.SelectedPrims; + parcel.SelfCount = msg.SelfCount; + int sequenceID = msg.SequenceID; + parcel.SimWideMaxPrims = msg.SimWideMaxPrims; + parcel.SimWideTotalPrims = msg.SimWideTotalPrims; + bool snapSelection = msg.SnapSelection; + parcel.SnapshotID = msg.SnapshotID; + parcel.Status = msg.Status; + parcel.TotalPrims = msg.TotalPrims; + parcel.UserLocation = msg.UserLocation; + parcel.UserLookAt = msg.UserLookAt; + parcel.Media.MediaDesc = msg.MediaDesc; + parcel.Media.MediaHeight = msg.MediaHeight; + parcel.Media.MediaWidth = msg.MediaWidth; + parcel.Media.MediaLoop = msg.MediaLoop; + parcel.Media.MediaType = msg.MediaType; + parcel.ObscureMedia = msg.ObscureMedia; + parcel.ObscureMusic = msg.ObscureMusic; + + if (Client.Settings.PARCEL_TRACKING) + { + lock (simulator.Parcels.Dictionary) + simulator.Parcels.Dictionary[parcel.LocalID] = parcel; + + bool set = false; + int y, x, index, bit; + for (y = 0; y < 64; y++) + { + for (x = 0; x < 64; x++) + { + index = (y * 64) + x; + bit = index % 8; + index >>= 3; + + if ((parcel.Bitmap[index] & (1 << bit)) != 0) + { + simulator.ParcelMap[y, x] = parcel.LocalID; + set = true; + } + } + } + + if (!set) + { + Logger.Log("Received a parcel with a bitmap that did not map to any locations", + Helpers.LogLevel.Warning); + } + } + + if (sequenceID.Equals(int.MaxValue) && WaitForSimParcel != null) + WaitForSimParcel.Set(); + + // auto request acl, will be stored in parcel tracking dictionary if enabled + if (Client.Settings.ALWAYS_REQUEST_PARCEL_ACL) + Client.Parcels.RequestParcelAccessList(simulator, parcel.LocalID, + AccessList.Both, sequenceID); + + // auto request dwell, will be stored in parcel tracking dictionary if enables + if (Client.Settings.ALWAYS_REQUEST_PARCEL_DWELL) + Client.Parcels.RequestDwell(simulator, parcel.LocalID); + + // Fire the callback for parcel properties being received + if (m_ParcelProperties != null) + { + OnParcelProperties(new ParcelPropertiesEventArgs(simulator, parcel, result, selectedPrims, sequenceID, snapSelection)); + } + + // Check if all of the simulator parcels have been retrieved, if so fire another callback + if (simulator.IsParcelMapFull() && m_SimParcelsDownloaded != null) + { + OnSimParcelsDownloaded(new SimParcelsDownloadedEventArgs(simulator, simulator.Parcels, simulator.ParcelMap)); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + /// Raises the event + protected void ParcelAccessListReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ParcelACL != null || Client.Settings.ALWAYS_REQUEST_PARCEL_ACL == true) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ParcelAccessListReplyPacket reply = (ParcelAccessListReplyPacket)packet; + + List accessList = new List(reply.List.Length); + + for (int i = 0; i < reply.List.Length; i++) + { + ParcelAccessEntry pae = new ParcelAccessEntry(); + pae.AgentID = reply.List[i].ID; + pae.Time = Utils.UnixTimeToDateTime((uint)reply.List[i].Time); + pae.Flags = (AccessList)reply.List[i].Flags; + + accessList.Add(pae); + } + + lock (simulator.Parcels.Dictionary) + { + if (simulator.Parcels.Dictionary.ContainsKey(reply.Data.LocalID)) + { + Parcel parcel = simulator.Parcels.Dictionary[reply.Data.LocalID]; + if ((AccessList)reply.Data.Flags == AccessList.Ban) + parcel.AccessBlackList = accessList; + else + parcel.AccessWhiteList = accessList; + + simulator.Parcels.Dictionary[reply.Data.LocalID] = parcel; + } + } + + + if (m_ParcelACL != null) + { + OnParcelAccessListReply(new ParcelAccessListReplyEventArgs(simulator, reply.Data.SequenceID, reply.Data.LocalID, + reply.Data.Flags, accessList)); + } + } + } + + protected void ParcelObjectOwnersReplyHandler(string capsKey, IMessage message, Simulator simulator) + { + if (m_ParcelObjectOwnersReply != null) + { + List primOwners = new List(); + + ParcelObjectOwnersReplyMessage msg = (ParcelObjectOwnersReplyMessage)message; + + for (int i = 0; i < msg.PrimOwnersBlock.Length; i++) + { + ParcelPrimOwners primOwner = new ParcelPrimOwners(); + primOwner.OwnerID = msg.PrimOwnersBlock[i].OwnerID; + primOwner.Count = msg.PrimOwnersBlock[i].Count; + primOwner.IsGroupOwned = msg.PrimOwnersBlock[i].IsGroupOwned; + primOwner.OnlineStatus = msg.PrimOwnersBlock[i].OnlineStatus; + primOwner.NewestPrim = msg.PrimOwnersBlock[i].TimeStamp; + + primOwners.Add(primOwner); + } + + OnParcelObjectOwnersReply(new ParcelObjectOwnersReplyEventArgs(simulator, primOwners)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + /// Raises the event + protected void SelectParcelObjectsReplyHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ForceSelectObjects != null) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ForceObjectSelectPacket reply = (ForceObjectSelectPacket)packet; + List objectIDs = new List(reply.Data.Length); + + for (int i = 0; i < reply.Data.Length; i++) + { + objectIDs.Add(reply.Data[i].LocalID); + } + + OnForceSelectObjectsReply(new ForceSelectObjectsReplyEventArgs(simulator, objectIDs, reply._Header.ResetList)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + /// Raises the event + protected void ParcelMediaUpdateHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ParcelMediaUpdateReply != null) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ParcelMediaUpdatePacket reply = (ParcelMediaUpdatePacket)packet; + ParcelMedia media = new ParcelMedia(); + + media.MediaAutoScale = (reply.DataBlock.MediaAutoScale == (byte)0x1) ? true : false; + media.MediaID = reply.DataBlock.MediaID; + media.MediaDesc = Utils.BytesToString(reply.DataBlockExtended.MediaDesc); + media.MediaHeight = reply.DataBlockExtended.MediaHeight; + media.MediaLoop = ((reply.DataBlockExtended.MediaLoop & 1) != 0) ? true : false; + media.MediaType = Utils.BytesToString(reply.DataBlockExtended.MediaType); + media.MediaWidth = reply.DataBlockExtended.MediaWidth; + media.MediaURL = Utils.BytesToString(reply.DataBlock.MediaURL); + + OnParcelMediaUpdateReply(new ParcelMediaUpdateReplyEventArgs(simulator, media)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ParcelOverlayHandler(object sender, PacketReceivedEventArgs e) + { + const int OVERLAY_COUNT = 4; + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ParcelOverlayPacket overlay = (ParcelOverlayPacket)packet; + + if (overlay.ParcelData.SequenceID >= 0 && overlay.ParcelData.SequenceID < OVERLAY_COUNT) + { + int length = overlay.ParcelData.Data.Length; + + Buffer.BlockCopy(overlay.ParcelData.Data, 0, simulator.ParcelOverlay, + overlay.ParcelData.SequenceID * length, length); + simulator.ParcelOverlaysReceived++; + + if (simulator.ParcelOverlaysReceived >= OVERLAY_COUNT) + { + // TODO: ParcelOverlaysReceived should become internal, and reset to zero every + // time it hits four. Also need a callback here + } + } + else + { + Logger.Log("Parcel overlay with sequence ID of " + overlay.ParcelData.SequenceID + + " received from " + simulator.ToString(), Helpers.LogLevel.Warning, Client); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + /// Raises the event + protected void ParcelMediaCommandMessagePacketHandler(object sender, PacketReceivedEventArgs e) + { + if (m_ParcelMediaCommand != null) + { + Packet packet = e.Packet; + Simulator simulator = e.Simulator; + + ParcelMediaCommandMessagePacket pmc = (ParcelMediaCommandMessagePacket)packet; + ParcelMediaCommandMessagePacket.CommandBlockBlock block = pmc.CommandBlock; + + OnParcelMediaCommand(new ParcelMediaCommandEventArgs(simulator, pmc.Header.Sequence, (ParcelFlags)block.Flags, + (ParcelMediaCommand)block.Command, block.Time)); + } + } + + #endregion Packet Handlers + } + #region EventArgs classes + + /// Contains a parcels dwell data returned from the simulator in response to an + public class ParcelDwellReplyEventArgs : EventArgs + { + private readonly UUID m_ParcelID; + private readonly int m_LocalID; + private readonly float m_Dwell; + + /// Get the global ID of the parcel + public UUID ParcelID { get { return m_ParcelID; } } + /// Get the simulator specific ID of the parcel + public int LocalID { get { return m_LocalID; } } + /// Get the calculated dwell + public float Dwell { get { return m_Dwell; } } + + /// + /// Construct a new instance of the ParcelDwellReplyEventArgs class + /// + /// The global ID of the parcel + /// The simulator specific ID of the parcel + /// The calculated dwell for the parcel + public ParcelDwellReplyEventArgs(UUID parcelID, int localID, float dwell) + { + this.m_ParcelID = parcelID; + this.m_LocalID = localID; + this.m_Dwell = dwell; + } + } + + /// Contains basic parcel information data returned from the + /// simulator in response to an request + public class ParcelInfoReplyEventArgs : EventArgs + { + private readonly ParcelInfo m_Parcel; + + /// Get the object containing basic parcel info + public ParcelInfo Parcel { get { return m_Parcel; } } + + /// + /// Construct a new instance of the ParcelInfoReplyEventArgs class + /// + /// The object containing basic parcel info + public ParcelInfoReplyEventArgs(ParcelInfo parcel) + { + this.m_Parcel = parcel; + } + } + + /// Contains basic parcel information data returned from the simulator in response to an request + public class ParcelPropertiesEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private Parcel m_Parcel; + private readonly ParcelResult m_Result; + private readonly int m_SelectedPrims; + private readonly int m_SequenceID; + private readonly bool m_SnapSelection; + + /// Get the simulator the parcel is located in + public Simulator Simulator { get { return m_Simulator; } } + /// Get the object containing the details + /// If Result is NoData, this object will not contain valid data + public Parcel Parcel { get { return m_Parcel; } } + /// Get the result of the request + public ParcelResult Result { get { return m_Result; } } + /// Get the number of primitieves your agent is + /// currently selecting and or sitting on in this parcel + public int SelectedPrims { get { return m_SelectedPrims; } } + /// Get the user assigned ID used to correlate a request with + /// these results + public int SequenceID { get { return m_SequenceID; } } + /// TODO: + public bool SnapSelection { get { return m_SnapSelection; } } + + /// + /// Construct a new instance of the ParcelPropertiesEventArgs class + /// + /// The object containing the details + /// The object containing the details + /// The result of the request + /// The number of primitieves your agent is + /// currently selecting and or sitting on in this parcel + /// The user assigned ID used to correlate a request with + /// these results + /// TODO: + public ParcelPropertiesEventArgs(Simulator simulator, Parcel parcel, ParcelResult result, int selectedPrims, + int sequenceID, bool snapSelection) + { + this.m_Simulator = simulator; + this.m_Parcel = parcel; + this.m_Result = result; + this.m_SelectedPrims = selectedPrims; + this.m_SequenceID = sequenceID; + this.m_SnapSelection = snapSelection; + } + } + + /// Contains blacklist and whitelist data returned from the simulator in response to an request + public class ParcelAccessListReplyEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly int m_SequenceID; + private readonly int m_LocalID; + private readonly uint m_Flags; + private readonly List m_AccessList; + + /// Get the simulator the parcel is located in + public Simulator Simulator { get { return m_Simulator; } } + /// Get the user assigned ID used to correlate a request with + /// these results + public int SequenceID { get { return m_SequenceID; } } + /// Get the simulator specific ID of the parcel + public int LocalID { get { return m_LocalID; } } + /// TODO: + public uint Flags { get { return m_Flags; } } + /// Get the list containing the white/blacklisted agents for the parcel + public List AccessList { get { return m_AccessList; } } + + /// + /// Construct a new instance of the ParcelAccessListReplyEventArgs class + /// + /// The simulator the parcel is located in + /// The user assigned ID used to correlate a request with + /// these results + /// The simulator specific ID of the parcel + /// TODO: + /// The list containing the white/blacklisted agents for the parcel + public ParcelAccessListReplyEventArgs(Simulator simulator, int sequenceID, int localID, uint flags, List accessEntries) + { + this.m_Simulator = simulator; + this.m_SequenceID = sequenceID; + this.m_LocalID = localID; + this.m_Flags = flags; + this.m_AccessList = accessEntries; + } + } + + /// Contains blacklist and whitelist data returned from the + /// simulator in response to an request + public class ParcelObjectOwnersReplyEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly List m_Owners; + + /// Get the simulator the parcel is located in + public Simulator Simulator { get { return m_Simulator; } } + /// Get the list containing prim ownership counts + public List PrimOwners { get { return m_Owners; } } + + /// + /// Construct a new instance of the ParcelObjectOwnersReplyEventArgs class + /// + /// The simulator the parcel is located in + /// The list containing prim ownership counts + public ParcelObjectOwnersReplyEventArgs(Simulator simulator, List primOwners) + { + this.m_Simulator = simulator; + this.m_Owners = primOwners; + } + } + + /// Contains the data returned when all parcel data has been retrieved from a simulator + public class SimParcelsDownloadedEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly InternalDictionary m_Parcels; + private readonly int[,] m_ParcelMap; + + /// Get the simulator the parcel data was retrieved from + public Simulator Simulator { get { return m_Simulator; } } + /// A dictionary containing the parcel data where the key correlates to the ParcelMap entry + public InternalDictionary Parcels { get { return m_Parcels; } } + /// Get the multidimensional array containing a x,y grid mapped + /// to each 64x64 parcel's LocalID. + public int[,] ParcelMap { get { return m_ParcelMap; } } + + /// + /// Construct a new instance of the SimParcelsDownloadedEventArgs class + /// + /// The simulator the parcel data was retrieved from + /// The dictionary containing the parcel data + /// The multidimensional array containing a x,y grid mapped + /// to each 64x64 parcel's LocalID. + public SimParcelsDownloadedEventArgs(Simulator simulator, InternalDictionary simParcels, int[,] parcelMap) + { + this.m_Simulator = simulator; + this.m_Parcels = simParcels; + this.m_ParcelMap = parcelMap; + } + } + + /// Contains the data returned when a request + public class ForceSelectObjectsReplyEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly List m_ObjectIDs; + private readonly bool m_ResetList; + + /// Get the simulator the parcel data was retrieved from + public Simulator Simulator { get { return m_Simulator; } } + /// Get the list of primitive IDs + public List ObjectIDs { get { return m_ObjectIDs; } } + /// true if the list is clean and contains the information + /// only for a given request + public bool ResetList { get { return m_ResetList; } } + + /// + /// Construct a new instance of the ForceSelectObjectsReplyEventArgs class + /// + /// The simulator the parcel data was retrieved from + /// The list of primitive IDs + /// true if the list is clean and contains the information + /// only for a given request + public ForceSelectObjectsReplyEventArgs(Simulator simulator, List objectIDs, bool resetList) + { + this.m_Simulator = simulator; + this.m_ObjectIDs = objectIDs; + this.m_ResetList = resetList; + } + } + + /// Contains data when the media data for a parcel the avatar is on changes + public class ParcelMediaUpdateReplyEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly ParcelMedia m_ParcelMedia; + + /// Get the simulator the parcel media data was updated in + public Simulator Simulator { get { return m_Simulator; } } + /// Get the updated media information + public ParcelMedia Media { get { return m_ParcelMedia; } } + + /// + /// Construct a new instance of the ParcelMediaUpdateReplyEventArgs class + /// + /// the simulator the parcel media data was updated in + /// The updated media information + public ParcelMediaUpdateReplyEventArgs(Simulator simulator, ParcelMedia media) + { + this.m_Simulator = simulator; + this.m_ParcelMedia = media; + } + } + + /// Contains the media command for a parcel the agent is currently on + public class ParcelMediaCommandEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly uint m_Sequence; + private readonly ParcelFlags m_ParcelFlags; + private readonly ParcelMediaCommand m_MediaCommand; + private readonly float m_Time; + + /// Get the simulator the parcel media command was issued in + public Simulator Simulator { get { return m_Simulator; } } + /// + public uint Sequence { get { return m_Sequence; } } + /// + public ParcelFlags ParcelFlags { get { return m_ParcelFlags; } } + /// Get the media command that was sent + public ParcelMediaCommand MediaCommand { get { return m_MediaCommand; } } + /// + public float Time { get { return m_Time; } } + + /// + /// Construct a new instance of the ParcelMediaCommandEventArgs class + /// + /// The simulator the parcel media command was issued in + /// + /// + /// The media command that was sent + /// + public ParcelMediaCommandEventArgs(Simulator simulator, uint sequence, ParcelFlags flags, ParcelMediaCommand command, float time) + { + this.m_Simulator = simulator; + this.m_Sequence = sequence; + this.m_ParcelFlags = flags; + this.m_MediaCommand = command; + this.m_Time = time; + } + } + #endregion +} diff --git a/OpenMetaverse/Permissions.cs b/OpenMetaverse/Permissions.cs new file mode 100644 index 0000000..7aa8f80 --- /dev/null +++ b/OpenMetaverse/Permissions.cs @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse +{ + /// + /// + /// + [Flags] + public enum PermissionMask : uint + { + None = 0, + Transfer = 1 << 13, + Modify = 1 << 14, + Copy = 1 << 15, + Export = 1 << 16, + Move = 1 << 19, + Damage = 1 << 20, + // All does not contain Export, which is special and must be + // explicitly given + All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) + } + + /// + /// + /// + [Flags] + public enum PermissionWho : byte + { + /// + Base = 0x01, + /// + Owner = 0x02, + /// + Group = 0x04, + /// + Everyone = 0x08, + /// + NextOwner = 0x10, + /// + All = 0x1F + } + + /// + /// + /// + [Serializable()] + public struct Permissions + { + public PermissionMask BaseMask; + public PermissionMask EveryoneMask; + public PermissionMask GroupMask; + public PermissionMask NextOwnerMask; + public PermissionMask OwnerMask; + + public Permissions(uint baseMask, uint everyoneMask, uint groupMask, uint nextOwnerMask, uint ownerMask) + { + BaseMask = (PermissionMask)baseMask; + EveryoneMask = (PermissionMask)everyoneMask; + GroupMask = (PermissionMask)groupMask; + NextOwnerMask = (PermissionMask)nextOwnerMask; + OwnerMask = (PermissionMask)ownerMask; + } + + public Permissions GetNextPermissions() + { + uint nextMask = (uint)NextOwnerMask; + + return new Permissions( + (uint)BaseMask & nextMask, + (uint)EveryoneMask & nextMask, + (uint)GroupMask & nextMask, + (uint)NextOwnerMask, + (uint)OwnerMask & nextMask + ); + } + + public OSD GetOSD() + { + OSDMap permissions = new OSDMap(5); + permissions["base_mask"] = OSD.FromInteger((uint)BaseMask); + permissions["everyone_mask"] = OSD.FromInteger((uint)EveryoneMask); + permissions["group_mask"] = OSD.FromInteger((uint)GroupMask); + permissions["next_owner_mask"] = OSD.FromInteger((uint)NextOwnerMask); + permissions["owner_mask"] = OSD.FromInteger((uint)OwnerMask); + return permissions; + } + + public static Permissions FromOSD(OSD llsd) + { + Permissions permissions = new Permissions(); + OSDMap map = llsd as OSDMap; + + if (map != null) + { + permissions.BaseMask = (PermissionMask)map["base_mask"].AsUInteger(); + permissions.EveryoneMask = (PermissionMask)map["everyone_mask"].AsUInteger(); + permissions.GroupMask = (PermissionMask)map["group_mask"].AsUInteger(); + permissions.NextOwnerMask = (PermissionMask)map["next_owner_mask"].AsUInteger(); + permissions.OwnerMask = (PermissionMask)map["owner_mask"].AsUInteger(); + } + + return permissions; + } + + public override string ToString() + { + return String.Format("Base: {0}, Everyone: {1}, Group: {2}, NextOwner: {3}, Owner: {4}", + BaseMask, EveryoneMask, GroupMask, NextOwnerMask, OwnerMask); + } + + public override int GetHashCode() + { + return BaseMask.GetHashCode() ^ EveryoneMask.GetHashCode() ^ GroupMask.GetHashCode() ^ + NextOwnerMask.GetHashCode() ^ OwnerMask.GetHashCode(); + } + + public override bool Equals(object obj) + { + return (obj is Permissions) ? this == (Permissions)obj : false; + } + + public bool Equals(Permissions other) + { + return this == other; + } + + public static bool operator ==(Permissions lhs, Permissions rhs) + { + return (lhs.BaseMask == rhs.BaseMask) && (lhs.EveryoneMask == rhs.EveryoneMask) && + (lhs.GroupMask == rhs.GroupMask) && (lhs.NextOwnerMask == rhs.NextOwnerMask) && + (lhs.OwnerMask == rhs.OwnerMask); + } + + public static bool operator !=(Permissions lhs, Permissions rhs) + { + return !(lhs == rhs); + } + + public static bool HasPermissions(PermissionMask perms, PermissionMask checkPerms) + { + return (perms & checkPerms) == checkPerms; + } + + public static readonly Permissions NoPermissions = new Permissions(); + public static readonly Permissions FullPermissions = new Permissions((uint)PermissionMask.All, (uint)PermissionMask.All, + (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All); + } +} diff --git a/OpenMetaverse/Primitives/ObjectMedia.cs b/OpenMetaverse/Primitives/ObjectMedia.cs new file mode 100644 index 0000000..d59733e --- /dev/null +++ b/OpenMetaverse/Primitives/ObjectMedia.cs @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse +{ + #region enums + /// + /// Permissions for control of object media + /// + [Flags] + public enum MediaPermission : byte + { + None = 0, + Owner = 1, + Group = 2, + Anyone = 4, + All = None | Owner | Group | Anyone + } + + /// + /// Style of cotrols that shold be displayed to the user + /// + public enum MediaControls + { + Standard = 0, + Mini + } + #endregion enums + + /// + /// Class representing media data for a single face + /// + public class MediaEntry + { + /// Is display of the alternative image enabled + public bool EnableAlterntiveImage; + + /// Should media auto loop + public bool AutoLoop; + + /// Shoule media be auto played + public bool AutoPlay; + + /// Auto scale media to prim face + public bool AutoScale; + + /// Should viewer automatically zoom in on the face when clicked + public bool AutoZoom; + + /// Should viewer interpret first click as interaction with the media + /// or when false should the first click be treated as zoom in commadn + public bool InteractOnFirstClick; + + /// Style of controls viewer should display when + /// viewer media on this face + public MediaControls Controls; + + /// Starting URL for the media + public string HomeURL; + + /// Currently navigated URL + public string CurrentURL; + + /// Media height in pixes + public int Height; + + /// Media width in pixels + public int Width; + + /// Who can controls the media + public MediaPermission ControlPermissions; + + /// Who can interact with the media + public MediaPermission InteractPermissions; + + /// Is URL whitelist enabled + public bool EnableWhiteList; + + /// Array of URLs that are whitelisted + public string[] WhiteList; + + /// + /// Serialize to OSD + /// + /// OSDMap with the serialized data + public OSDMap GetOSD() + { + OSDMap map = new OSDMap(); + + map["alt_image_enable"] = OSD.FromBoolean(EnableAlterntiveImage); + map["auto_loop"] = OSD.FromBoolean(AutoLoop); + map["auto_play"] = OSD.FromBoolean(AutoPlay); + map["auto_scale"] = OSD.FromBoolean(AutoScale); + map["auto_zoom"] = OSD.FromBoolean(AutoZoom); + map["controls"] = OSD.FromInteger((int)Controls); + map["current_url"] = OSD.FromString(CurrentURL); + map["first_click_interact"] = OSD.FromBoolean(InteractOnFirstClick); + map["height_pixels"] = OSD.FromInteger(Height); + map["home_url"] = OSD.FromString(HomeURL); + map["perms_control"] = OSD.FromInteger((int)ControlPermissions); + map["perms_interact"] = OSD.FromInteger((int)InteractPermissions); + + List wl = new List(); + if (WhiteList != null && WhiteList.Length > 0) + { + for (int i = 0; i < WhiteList.Length; i++) + wl.Add(OSD.FromString(WhiteList[i])); + } + + map["whitelist"] = new OSDArray(wl); + map["whitelist_enable"] = OSD.FromBoolean(EnableWhiteList); + map["width_pixels"] = OSD.FromInteger(Width); + + return map; + } + + /// + /// Deserialize from OSD data + /// + /// Serialized OSD data + /// Deserialized object + public static MediaEntry FromOSD(OSD osd) + { + MediaEntry m = new MediaEntry(); + OSDMap map = (OSDMap)osd; + + m.EnableAlterntiveImage = map["alt_image_enable"].AsBoolean(); + m.AutoLoop = map["auto_loop"].AsBoolean(); + m.AutoPlay = map["auto_play"].AsBoolean(); + m.AutoScale = map["auto_scale"].AsBoolean(); + m.AutoZoom = map["auto_zoom"].AsBoolean(); + m.Controls = (MediaControls)map["controls"].AsInteger(); + m.CurrentURL = map["current_url"].AsString(); + m.InteractOnFirstClick = map["first_click_interact"].AsBoolean(); + m.Height = map["height_pixels"].AsInteger(); + m.HomeURL = map["home_url"].AsString(); + m.ControlPermissions = (MediaPermission)map["perms_control"].AsInteger(); + m.InteractPermissions = (MediaPermission)map["perms_interact"].AsInteger(); + + if (map["whitelist"].Type == OSDType.Array) + { + OSDArray wl = (OSDArray)map["whitelist"]; + if (wl.Count > 0) + { + m.WhiteList = new string[wl.Count]; + for (int i = 0; i < wl.Count; i++) + { + m.WhiteList[i] = wl[i].AsString(); + } + } + } + + m.EnableWhiteList = map["whitelist_enable"].AsBoolean(); + m.Width = map["width_pixels"].AsInteger(); + + return m; + } + } + + public partial class Primitive + { + /// + /// Current version of the media data for the prim + /// + public string MediaVersion = string.Empty; + + /// + /// Array of media entries indexed by face number + /// + public MediaEntry[] FaceMedia; + } +} diff --git a/OpenMetaverse/Primitives/ParticleSystem.cs b/OpenMetaverse/Primitives/ParticleSystem.cs new file mode 100644 index 0000000..6b8cb00 --- /dev/null +++ b/OpenMetaverse/Primitives/ParticleSystem.cs @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse +{ + /// + /// Particle system specific enumerators, flags and methods. + /// + public partial class Primitive + { + #region Subclasses + + /// + /// Complete structure for the particle system + /// + public struct ParticleSystem + { + /// + /// Particle source pattern + /// + public enum SourcePattern : byte + { + /// None + None = 0, + /// Drop particles from source position with no force + Drop = 0x01, + /// "Explode" particles in all directions + Explode = 0x02, + /// Particles shoot across a 2D area + Angle = 0x04, + /// Particles shoot across a 3D Cone + AngleCone = 0x08, + /// Inverse of AngleCone (shoot particles everywhere except the 3D cone defined + AngleConeEmpty = 0x10 + } + + /// + /// Particle Data Flags + /// + [Flags] + public enum ParticleDataFlags : uint + { + /// None + None = 0, + /// Interpolate color and alpha from start to end + InterpColor = 0x001, + /// Interpolate scale from start to end + InterpScale = 0x002, + /// Bounce particles off particle sources Z height + Bounce = 0x004, + /// velocity of particles is dampened toward the simulators wind + Wind = 0x008, + /// Particles follow the source + FollowSrc = 0x010, + /// Particles point towards the direction of source's velocity + FollowVelocity = 0x020, + /// Target of the particles + TargetPos = 0x040, + /// Particles are sent in a straight line + TargetLinear = 0x080, + /// Particles emit a glow + Emissive = 0x100, + /// used for point/grab/touch + Beam = 0x200, + /// continuous ribbon particle + Ribbon = 0x400, + /// particle data contains glow + DataGlow = 0x10000, + /// particle data contains blend functions + DataBlend = 0x20000, + } + + /// + /// Particle Flags Enum + /// + [Flags] + public enum ParticleFlags : uint + { + /// None + None = 0, + /// Acceleration and velocity for particles are + /// relative to the object rotation + ObjectRelative = 0x01, + /// Particles use new 'correct' angle parameters + UseNewAngle = 0x02 + } + + public enum BlendFunc : byte + { + One = 0, + Zero = 1, + DestColor = 2, + SourceColor = 3, + OneMinusDestColor = 4, + OneMinusSourceColor = 5, + DestAlpha = 6, + SourceAlpha = 7, + OneMinusDestAlpha = 8, + OneMinusSourceAlpha = 9, + } + + public uint CRC; + /// Particle Flags + /// There appears to be more data packed in to this area + /// for many particle systems. It doesn't appear to be flag values + /// and serialization breaks unless there is a flag for every + /// possible bit so it is left as an unsigned integer + public uint PartFlags; + /// pattern of particles + public SourcePattern Pattern; + /// A representing the maximimum age (in seconds) particle will be displayed + /// Maximum value is 30 seconds + public float MaxAge; + /// A representing the number of seconds, + /// from when the particle source comes into view, + /// or the particle system's creation, that the object will emits particles; + /// after this time period no more particles are emitted + public float StartAge; + /// A in radians that specifies where particles will not be created + public float InnerAngle; + /// A in radians that specifies where particles will be created + public float OuterAngle; + /// A representing the number of seconds between burts. + public float BurstRate; + /// A representing the number of meters + /// around the center of the source where particles will be created. + public float BurstRadius; + /// A representing in seconds, the minimum speed between bursts of new particles + /// being emitted + public float BurstSpeedMin; + /// A representing in seconds the maximum speed of new particles being emitted. + public float BurstSpeedMax; + /// A representing the maximum number of particles emitted per burst + public byte BurstPartCount; + /// A which represents the velocity (speed) from the source which particles are emitted + public Vector3 AngularVelocity; + /// A which represents the Acceleration from the source which particles are emitted + public Vector3 PartAcceleration; + /// The Key of the texture displayed on the particle + public UUID Texture; + /// The Key of the specified target object or avatar particles will follow + public UUID Target; + /// Flags of particle from + public ParticleDataFlags PartDataFlags; + /// Max Age particle system will emit particles for + public float PartMaxAge; + /// The the particle has at the beginning of its lifecycle + public Color4 PartStartColor; + /// The the particle has at the ending of its lifecycle + public Color4 PartEndColor; + /// A that represents the starting X size of the particle + /// Minimum value is 0, maximum value is 4 + public float PartStartScaleX; + /// A that represents the starting Y size of the particle + /// Minimum value is 0, maximum value is 4 + public float PartStartScaleY; + /// A that represents the ending X size of the particle + /// Minimum value is 0, maximum value is 4 + public float PartEndScaleX; + /// A that represents the ending Y size of the particle + /// Minimum value is 0, maximum value is 4 + public float PartEndScaleY; + + /// A that represents the start glow value + /// Minimum value is 0, maximum value is 1 + public float PartStartGlow; + /// A that represents the end glow value + /// Minimum value is 0, maximum value is 1 + public float PartEndGlow; + + /// OpenGL blend function to use at particle source + public byte BlendFuncSource; + /// OpenGL blend function to use at particle destination + public byte BlendFuncDest; + + public const byte MaxDataBlockSize = 98; + public const byte LegacyDataBlockSize = 86; + public const byte SysDataSize = 68; + public const byte PartDataSize = 18; + + /// + /// Can this particle system be packed in a legacy compatible way + /// + /// True if the particle system doesn't use new particle system features + public bool IsLegacyCompatible() + { + return !HasGlow() && !HasBlendFunc(); + } + + public bool HasGlow() + { + return PartStartGlow > 0f || PartEndGlow > 0f; + } + + public bool HasBlendFunc() + { + return BlendFuncSource != (byte)BlendFunc.SourceAlpha || BlendFuncDest != (byte)BlendFunc.OneMinusSourceAlpha; + } + + /// + /// Decodes a byte[] array into a ParticleSystem Object + /// + /// ParticleSystem object + /// Start position for BitPacker + public ParticleSystem(byte[] data, int pos) + { + PartStartGlow = 0f; + PartEndGlow = 0f; + BlendFuncSource = (byte)BlendFunc.SourceAlpha; + BlendFuncDest = (byte)BlendFunc.OneMinusSourceAlpha; + + CRC = PartFlags = 0; + Pattern = SourcePattern.None; + MaxAge = StartAge = InnerAngle = OuterAngle = BurstRate = BurstRadius = BurstSpeedMin = + BurstSpeedMax = 0.0f; + BurstPartCount = 0; + AngularVelocity = PartAcceleration = Vector3.Zero; + Texture = Target = UUID.Zero; + PartDataFlags = ParticleDataFlags.None; + PartMaxAge = 0.0f; + PartStartColor = PartEndColor = Color4.Black; + PartStartScaleX = PartStartScaleY = PartEndScaleX = PartEndScaleY = 0.0f; + + int size = data.Length - pos; + BitPack pack = new BitPack(data, pos); + + if (size == LegacyDataBlockSize) + { + UnpackSystem(ref pack); + UnpackLegacyData(ref pack); + } + else if (size > LegacyDataBlockSize && size <= MaxDataBlockSize) + { + int sysSize = pack.UnpackBits(32); + if (sysSize != SysDataSize) return; // unkown particle system data size + UnpackSystem(ref pack); + int dataSize = pack.UnpackBits(32); + UnpackLegacyData(ref pack); + + + if ((PartDataFlags & ParticleDataFlags.DataGlow) == ParticleDataFlags.DataGlow) + { + if (pack.Data.Length - pack.BytePos < 2) return; + uint glow = pack.UnpackUBits(8); + PartStartGlow = glow / 255f; + glow = pack.UnpackUBits(8); + PartEndGlow = glow / 255f; + } + + if ((PartDataFlags & ParticleDataFlags.DataBlend) == ParticleDataFlags.DataBlend) + { + if (pack.Data.Length - pack.BytePos < 2) return; + BlendFuncSource = (byte)pack.UnpackUBits(8); + BlendFuncDest = (byte)pack.UnpackUBits(8); + } + + } + } + + void UnpackSystem(ref BitPack pack) + { + CRC = pack.UnpackUBits(32); + PartFlags = pack.UnpackUBits(32); + Pattern = (SourcePattern)pack.UnpackByte(); + MaxAge = pack.UnpackFixed(false, 8, 8); + StartAge = pack.UnpackFixed(false, 8, 8); + InnerAngle = pack.UnpackFixed(false, 3, 5); + OuterAngle = pack.UnpackFixed(false, 3, 5); + BurstRate = pack.UnpackFixed(false, 8, 8); + BurstRadius = pack.UnpackFixed(false, 8, 8); + BurstSpeedMin = pack.UnpackFixed(false, 8, 8); + BurstSpeedMax = pack.UnpackFixed(false, 8, 8); + BurstPartCount = pack.UnpackByte(); + float x = pack.UnpackFixed(true, 8, 7); + float y = pack.UnpackFixed(true, 8, 7); + float z = pack.UnpackFixed(true, 8, 7); + AngularVelocity = new Vector3(x, y, z); + x = pack.UnpackFixed(true, 8, 7); + y = pack.UnpackFixed(true, 8, 7); + z = pack.UnpackFixed(true, 8, 7); + PartAcceleration = new Vector3(x, y, z); + Texture = pack.UnpackUUID(); + Target = pack.UnpackUUID(); + } + + void UnpackLegacyData(ref BitPack pack) + { + PartDataFlags = (ParticleDataFlags)pack.UnpackUBits(32); + PartMaxAge = pack.UnpackFixed(false, 8, 8); + byte r = pack.UnpackByte(); + byte g = pack.UnpackByte(); + byte b = pack.UnpackByte(); + byte a = pack.UnpackByte(); + PartStartColor = new Color4(r, g, b, a); + r = pack.UnpackByte(); + g = pack.UnpackByte(); + b = pack.UnpackByte(); + a = pack.UnpackByte(); + PartEndColor = new Color4(r, g, b, a); + PartStartScaleX = pack.UnpackFixed(false, 3, 5); + PartStartScaleY = pack.UnpackFixed(false, 3, 5); + PartEndScaleX = pack.UnpackFixed(false, 3, 5); + PartEndScaleY = pack.UnpackFixed(false, 3, 5); + } + + /// + /// Generate byte[] array from particle data + /// + /// Byte array + public byte[] GetBytes() + { + int size = LegacyDataBlockSize; + if (!IsLegacyCompatible()) size += 8; // two new ints for size + if (HasGlow()) size += 2; // two bytes for start and end glow + if (HasBlendFunc()) size += 2; // two bytes for start end end blend function + + byte[] bytes = new byte[size]; + BitPack pack = new BitPack(bytes, 0); + + if (IsLegacyCompatible()) + { + PackSystemBytes(ref pack); + PackLegacyData(ref pack); + } + else + { + if (HasGlow()) PartDataFlags |= ParticleDataFlags.DataGlow; + if (HasBlendFunc()) PartDataFlags |= ParticleDataFlags.DataBlend; + + pack.PackBits(SysDataSize, 32); + PackSystemBytes(ref pack); + int partSize = PartDataSize; + if (HasGlow()) partSize += 2; // two bytes for start and end glow + if (HasBlendFunc()) partSize += 2; // two bytes for start end end blend function + pack.PackBits(partSize, 32); + PackLegacyData(ref pack); + + if (HasGlow()) + { + pack.PackBits((byte)(PartStartGlow * 255f), 8); + pack.PackBits((byte)(PartEndGlow * 255f), 8); + } + + if (HasBlendFunc()) + { + pack.PackBits(BlendFuncSource, 8); + pack.PackBits(BlendFuncDest, 8); + } + } + + return bytes; + } + + void PackSystemBytes(ref BitPack pack) + { + pack.PackBits(CRC, 32); + pack.PackBits((uint)PartFlags, 32); + pack.PackBits((uint)Pattern, 8); + pack.PackFixed(MaxAge, false, 8, 8); + pack.PackFixed(StartAge, false, 8, 8); + pack.PackFixed(InnerAngle, false, 3, 5); + pack.PackFixed(OuterAngle, false, 3, 5); + pack.PackFixed(BurstRate, false, 8, 8); + pack.PackFixed(BurstRadius, false, 8, 8); + pack.PackFixed(BurstSpeedMin, false, 8, 8); + pack.PackFixed(BurstSpeedMax, false, 8, 8); + pack.PackBits(BurstPartCount, 8); + pack.PackFixed(AngularVelocity.X, true, 8, 7); + pack.PackFixed(AngularVelocity.Y, true, 8, 7); + pack.PackFixed(AngularVelocity.Z, true, 8, 7); + pack.PackFixed(PartAcceleration.X, true, 8, 7); + pack.PackFixed(PartAcceleration.Y, true, 8, 7); + pack.PackFixed(PartAcceleration.Z, true, 8, 7); + pack.PackUUID(Texture); + pack.PackUUID(Target); + } + + void PackLegacyData(ref BitPack pack) + { + pack.PackBits((uint)PartDataFlags, 32); + pack.PackFixed(PartMaxAge, false, 8, 8); + pack.PackColor(PartStartColor); + pack.PackColor(PartEndColor); + pack.PackFixed(PartStartScaleX, false, 3, 5); + pack.PackFixed(PartStartScaleY, false, 3, 5); + pack.PackFixed(PartEndScaleX, false, 3, 5); + pack.PackFixed(PartEndScaleY, false, 3, 5); + } + + public OSD GetOSD() + { + OSDMap map = new OSDMap(); + + map["crc"] = OSD.FromInteger(CRC); + map["part_flags"] = OSD.FromInteger(PartFlags); + map["pattern"] = OSD.FromInteger((int)Pattern); + map["max_age"] = OSD.FromReal(MaxAge); + map["start_age"] = OSD.FromReal(StartAge); + map["inner_angle"] = OSD.FromReal(InnerAngle); + map["outer_angle"] = OSD.FromReal(OuterAngle); + map["burst_rate"] = OSD.FromReal(BurstRate); + map["burst_radius"] = OSD.FromReal(BurstRadius); + map["burst_speed_min"] = OSD.FromReal(BurstSpeedMin); + map["burst_speed_max"] = OSD.FromReal(BurstSpeedMax); + map["burst_part_count"] = OSD.FromInteger(BurstPartCount); + map["ang_velocity"] = OSD.FromVector3(AngularVelocity); + map["part_acceleration"] = OSD.FromVector3(PartAcceleration); + map["texture"] = OSD.FromUUID(Texture); + map["target"] = OSD.FromUUID(Target); + + map["part_data_flags"] = (uint)PartDataFlags; + map["part_max_age"] = PartMaxAge; + map["part_start_color"] = PartStartColor; + map["part_end_color"] = PartEndColor; + map["part_start_scale"] = new Vector3(PartStartScaleX, PartStartScaleY, 0f); + map["part_end_scale"] = new Vector3(PartEndScaleX, PartEndScaleY, 0f); + + if (HasGlow()) + { + map["part_start_glow"] = PartStartGlow; + map["part_end_glow"] = PartEndGlow; + } + + if (HasBlendFunc()) + { + map["blendfunc_source"] = BlendFuncSource; + map["blendfunc_dest"] = BlendFuncDest; + } + + return map; + } + + public static ParticleSystem FromOSD(OSD osd) + { + ParticleSystem partSys = new ParticleSystem(); + OSDMap map = osd as OSDMap; + + if (map != null) + { + partSys.CRC = map["crc"].AsUInteger(); + partSys.PartFlags = map["part_flags"].AsUInteger(); + partSys.Pattern = (SourcePattern)map["pattern"].AsInteger(); + partSys.MaxAge = (float)map["max_age"].AsReal(); + partSys.StartAge = (float)map["start_age"].AsReal(); + partSys.InnerAngle = (float)map["inner_angle"].AsReal(); + partSys.OuterAngle = (float)map["outer_angle"].AsReal(); + partSys.BurstRate = (float)map["burst_rate"].AsReal(); + partSys.BurstRadius = (float)map["burst_radius"].AsReal(); + partSys.BurstSpeedMin = (float)map["burst_speed_min"].AsReal(); + partSys.BurstSpeedMax = (float)map["burst_speed_max"].AsReal(); + partSys.BurstPartCount = (byte)map["burst_part_count"].AsInteger(); + partSys.AngularVelocity = map["ang_velocity"].AsVector3(); + partSys.PartAcceleration = map["part_acceleration"].AsVector3(); + partSys.Texture = map["texture"].AsUUID(); + partSys.Target = map["target"].AsUUID(); + + partSys.PartDataFlags = (ParticleDataFlags)map["part_data_flags"].AsUInteger(); + partSys.PartMaxAge = map["part_max_age"]; + partSys.PartStartColor = map["part_start_color"]; + partSys.PartEndColor = map["part_end_color"]; + Vector3 ss = map["part_start_scale"]; + partSys.PartStartScaleX = ss.X; + partSys.PartStartScaleY = ss.Y; + Vector3 es = map["part_end_scale"]; + partSys.PartEndScaleX = es.X; + partSys.PartEndScaleY = es.Y; + + if (map.ContainsKey("part_start_glow")) + { + partSys.PartStartGlow = map["part_start_glow"]; + partSys.PartEndGlow = map["part_end_glow"]; + } + + if (map.ContainsKey("blendfunc_source")) + { + partSys.BlendFuncSource = (byte)map["blendfunc_source"].AsUInteger(); + partSys.BlendFuncDest = (byte)map["blendfunc_dest"].AsUInteger(); + } + } + + return partSys; + } + } + + #endregion Subclasses + + #region Public Members + + /// + public ParticleSystem ParticleSys; + + #endregion Public Members + } +} diff --git a/OpenMetaverse/Primitives/Primitive.cs b/OpenMetaverse/Primitives/Primitive.cs new file mode 100644 index 0000000..fb32fee --- /dev/null +++ b/OpenMetaverse/Primitives/Primitive.cs @@ -0,0 +1,1512 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse +{ + public partial class Primitive : IEquatable + { + // Used for packing and unpacking parameters + protected const float CUT_QUANTA = 0.00002f; + protected const float SCALE_QUANTA = 0.01f; + protected const float SHEAR_QUANTA = 0.01f; + protected const float TAPER_QUANTA = 0.01f; + protected const float REV_QUANTA = 0.015f; + protected const float HOLLOW_QUANTA = 0.00002f; + + #region Subclasses + + /// + /// Parameters used to construct a visual representation of a primitive + /// + public struct ConstructionData + { + private const byte PROFILE_MASK = 0x0F; + private const byte HOLE_MASK = 0xF0; + + /// + public byte profileCurve; + /// + public PathCurve PathCurve; + /// + public float PathEnd; + /// + public float PathRadiusOffset; + /// + public float PathSkew; + /// + public float PathScaleX; + /// + public float PathScaleY; + /// + public float PathShearX; + /// + public float PathShearY; + /// + public float PathTaperX; + /// + public float PathTaperY; + /// + public float PathBegin; + /// + public float PathTwist; + /// + public float PathTwistBegin; + /// + public float PathRevolutions; + /// + public float ProfileBegin; + /// + public float ProfileEnd; + /// + public float ProfileHollow; + + /// + public Material Material; + /// + public byte State; + /// + public PCode PCode; + + #region Properties + + /// Attachment point to an avatar + public AttachmentPoint AttachmentPoint + { + get { return (AttachmentPoint)Utils.SwapWords(State); } + set { State = (byte)Utils.SwapWords((byte)value); } + } + + /// + public ProfileCurve ProfileCurve + { + get { return (ProfileCurve)(profileCurve & PROFILE_MASK); } + set + { + profileCurve &= HOLE_MASK; + profileCurve |= (byte)value; + } + } + + /// + public HoleType ProfileHole + { + get { return (HoleType)(profileCurve & HOLE_MASK); } + set + { + profileCurve &= PROFILE_MASK; + profileCurve |= (byte)value; + } + } + + /// + public Vector2 PathBeginScale + { + get + { + Vector2 begin = new Vector2(1f, 1f); + if (PathScaleX > 1f) + begin.X = 2f - PathScaleX; + if (PathScaleY > 1f) + begin.Y = 2f - PathScaleY; + return begin; + } + } + + /// + public Vector2 PathEndScale + { + get + { + Vector2 end = new Vector2(1f, 1f); + if (PathScaleX < 1f) + end.X = PathScaleX; + if (PathScaleY < 1f) + end.Y = PathScaleY; + return end; + } + } + + #endregion Properties + + /// + /// Calculdates hash code for prim construction data + /// + /// The has + public override int GetHashCode() + { + return profileCurve.GetHashCode() + ^ PathCurve.GetHashCode() + ^ PathEnd.GetHashCode() + ^ PathRadiusOffset.GetHashCode() + ^ PathSkew.GetHashCode() + ^ PathScaleX.GetHashCode() + ^ PathScaleY.GetHashCode() + ^ PathShearX.GetHashCode() + ^ PathShearY.GetHashCode() + ^ PathTaperX.GetHashCode() + ^ PathTaperY.GetHashCode() + ^ PathBegin.GetHashCode() + ^ PathTwist.GetHashCode() + ^ PathTwistBegin.GetHashCode() + ^ PathRevolutions.GetHashCode() + ^ ProfileBegin.GetHashCode() + ^ ProfileEnd.GetHashCode() + ^ ProfileHollow.GetHashCode() + ^ Material.GetHashCode() + ^ State.GetHashCode() + ^ PCode.GetHashCode(); + } + } + + /// + /// Information on the flexible properties of a primitive + /// + public class FlexibleData + { + /// + public int Softness; + /// + public float Gravity; + /// + public float Drag; + /// + public float Wind; + /// + public float Tension; + /// + public Vector3 Force; + + /// + /// Default constructor + /// + public FlexibleData() + { + } + + /// + /// + /// + /// + /// + public FlexibleData(byte[] data, int pos) + { + if (data.Length >= 5) + { + Softness = ((data[pos] & 0x80) >> 6) | ((data[pos + 1] & 0x80) >> 7); + + Tension = (float)(data[pos++] & 0x7F) / 10.0f; + Drag = (float)(data[pos++] & 0x7F) / 10.0f; + Gravity = (float)(data[pos++] / 10.0f) - 10.0f; + Wind = (float)data[pos++] / 10.0f; + Force = new Vector3(data, pos); + } + else + { + Softness = 0; + + Tension = 0.0f; + Drag = 0.0f; + Gravity = 0.0f; + Wind = 0.0f; + Force = Vector3.Zero; + } + } + + /// + /// + /// + /// + public byte[] GetBytes() + { + byte[] data = new byte[16]; + int i = 0; + + // Softness is packed in the upper bits of tension and drag + data[i] = (byte)((Softness & 2) << 6); + data[i + 1] = (byte)((Softness & 1) << 7); + + data[i++] |= (byte)((byte)(Tension * 10.01f) & 0x7F); + data[i++] |= (byte)((byte)(Drag * 10.01f) & 0x7F); + data[i++] = (byte)((Gravity + 10.0f) * 10.01f); + data[i++] = (byte)(Wind * 10.01f); + + Force.GetBytes().CopyTo(data, i); + + return data; + } + + /// + /// + /// + /// + public OSD GetOSD() + { + OSDMap map = new OSDMap(); + + map["simulate_lod"] = OSD.FromInteger(Softness); + map["gravity"] = OSD.FromReal(Gravity); + map["air_friction"] = OSD.FromReal(Drag); + map["wind_sensitivity"] = OSD.FromReal(Wind); + map["tension"] = OSD.FromReal(Tension); + map["user_force"] = OSD.FromVector3(Force); + + return map; + } + + public static FlexibleData FromOSD(OSD osd) + { + FlexibleData flex = new FlexibleData(); + + if (osd.Type == OSDType.Map) + { + OSDMap map = (OSDMap)osd; + + flex.Softness = map["simulate_lod"].AsInteger(); + flex.Gravity = (float)map["gravity"].AsReal(); + flex.Drag = (float)map["air_friction"].AsReal(); + flex.Wind = (float)map["wind_sensitivity"].AsReal(); + flex.Tension = (float)map["tension"].AsReal(); + flex.Force = ((OSDArray)map["user_force"]).AsVector3(); + } + + return flex; + } + + public override int GetHashCode() + { + return + Softness.GetHashCode() ^ + Gravity.GetHashCode() ^ + Drag.GetHashCode() ^ + Wind.GetHashCode() ^ + Tension.GetHashCode() ^ + Force.GetHashCode(); + } + } + + /// + /// Information on the light properties of a primitive + /// + public class LightData + { + /// + public Color4 Color; + /// + public float Intensity; + /// + public float Radius; + /// + public float Cutoff; + /// + public float Falloff; + + /// + /// Default constructor + /// + public LightData() + { + } + + /// + /// + /// + /// + /// + public LightData(byte[] data, int pos) + { + if (data.Length - pos >= 16) + { + Color = new Color4(data, pos, false); + Radius = Utils.BytesToFloat(data, pos + 4); + Cutoff = Utils.BytesToFloat(data, pos + 8); + Falloff = Utils.BytesToFloat(data, pos + 12); + + // Alpha in color is actually intensity + Intensity = Color.A; + Color.A = 1f; + } + else + { + Color = Color4.Black; + Radius = 0f; + Cutoff = 0f; + Falloff = 0f; + Intensity = 0f; + } + } + + /// + /// + /// + /// + public byte[] GetBytes() + { + byte[] data = new byte[16]; + + // Alpha channel in color is intensity + Color4 tmpColor = Color; + tmpColor.A = Intensity; + tmpColor.GetBytes().CopyTo(data, 0); + Utils.FloatToBytes(Radius).CopyTo(data, 4); + Utils.FloatToBytes(Cutoff).CopyTo(data, 8); + Utils.FloatToBytes(Falloff).CopyTo(data, 12); + + return data; + } + + public OSD GetOSD() + { + OSDMap map = new OSDMap(); + + map["color"] = OSD.FromColor4(Color); + map["intensity"] = OSD.FromReal(Intensity); + map["radius"] = OSD.FromReal(Radius); + map["cutoff"] = OSD.FromReal(Cutoff); + map["falloff"] = OSD.FromReal(Falloff); + + return map; + } + + public static LightData FromOSD(OSD osd) + { + LightData light = new LightData(); + + if (osd.Type == OSDType.Map) + { + OSDMap map = (OSDMap)osd; + + light.Color = ((OSDArray)map["color"]).AsColor4(); + light.Intensity = (float)map["intensity"].AsReal(); + light.Radius = (float)map["radius"].AsReal(); + light.Cutoff = (float)map["cutoff"].AsReal(); + light.Falloff = (float)map["falloff"].AsReal(); + } + + return light; + } + + public override int GetHashCode() + { + return + Color.GetHashCode() ^ + Intensity.GetHashCode() ^ + Radius.GetHashCode() ^ + Cutoff.GetHashCode() ^ + Falloff.GetHashCode(); + } + + /// + /// + /// + /// + public override string ToString() + { + return String.Format("Color: {0} Intensity: {1} Radius: {2} Cutoff: {3} Falloff: {4}", + Color, Intensity, Radius, Cutoff, Falloff); + } + } + + /// + /// Information on the light properties of a primitive as texture map + /// + public class LightImage + { + /// + public UUID LightTexture; + /// + public Vector3 Params; + + /// + /// Default constructor + /// + public LightImage() + { + } + + /// + /// + /// + /// + /// + public LightImage(byte[] data, int pos) + { + if (data.Length - pos >= 28) + { + LightTexture = new UUID(data, pos); + Params = new Vector3(data, pos + 16); + } + else + { + LightTexture = UUID.Zero; + Params = Vector3.Zero; + } + } + + /// + /// + /// + /// + public byte[] GetBytes() + { + byte[] data = new byte[28]; + + // Alpha channel in color is intensity + LightTexture.ToBytes(data, 0); + Params.ToBytes(data, 16); + + return data; + } + + public OSD GetOSD() + { + OSDMap map = new OSDMap(); + + map["texture"] = OSD.FromUUID(LightTexture); + map["params"] = OSD.FromVector3(Params); + + return map; + } + + public static LightImage FromOSD(OSD osd) + { + LightImage light = new LightImage(); + + if (osd.Type == OSDType.Map) + { + OSDMap map = (OSDMap)osd; + + light.LightTexture = map["texture"].AsUUID(); + light.Params = map["params"].AsVector3(); + } + + return light; + } + + public override int GetHashCode() + { + return LightTexture.GetHashCode() ^ Params.GetHashCode(); + } + + /// + /// + /// + /// + public override string ToString() + { + return String.Format("LightTexture: {0} Params; {1]", LightTexture, Params); + } + } + + /// + /// Information on the sculpt properties of a sculpted primitive + /// + public class SculptData + { + public UUID SculptTexture; + private byte type; + + public SculptType Type + { + get { return (SculptType)(type & 7); } + set { type = (byte)value; } + } + + /// + /// Render inside out (inverts the normals). + /// + public bool Invert + { + get { return ((type & (byte)SculptType.Invert) != 0); } + } + + /// + /// Render an X axis mirror of the sculpty. + /// + public bool Mirror + { + get { return ((type & (byte)SculptType.Mirror) != 0); } + } + + /// + /// Default constructor + /// + public SculptData() + { + } + + /// + /// + /// + /// + /// + public SculptData(byte[] data, int pos) + { + if (data.Length >= 17) + { + SculptTexture = new UUID(data, pos); + type = data[pos + 16]; + } + else + { + SculptTexture = UUID.Zero; + type = (byte)SculptType.None; + } + } + + public byte[] GetBytes() + { + byte[] data = new byte[17]; + + SculptTexture.GetBytes().CopyTo(data, 0); + data[16] = type; + + return data; + } + + public OSD GetOSD() + { + OSDMap map = new OSDMap(); + + map["texture"] = OSD.FromUUID(SculptTexture); + map["type"] = OSD.FromInteger(type); + + return map; + } + + public static SculptData FromOSD(OSD osd) + { + SculptData sculpt = new SculptData(); + + if (osd.Type == OSDType.Map) + { + OSDMap map = (OSDMap)osd; + + sculpt.SculptTexture = map["texture"].AsUUID(); + sculpt.type = (byte)map["type"].AsInteger(); + } + + return sculpt; + } + + public override int GetHashCode() + { + return SculptTexture.GetHashCode() ^ type.GetHashCode(); + } + } + + /// + /// Extended properties to describe an object + /// + public class ObjectProperties + { + /// + public UUID ObjectID; + /// + public UUID CreatorID; + /// + public UUID OwnerID; + /// + public UUID GroupID; + /// + public DateTime CreationDate; + /// + public Permissions Permissions; + /// + public int OwnershipCost; + /// + public SaleType SaleType; + /// + public int SalePrice; + /// + public byte AggregatePerms; + /// + public byte AggregatePermTextures; + /// + public byte AggregatePermTexturesOwner; + /// + public ObjectCategory Category; + /// + public short InventorySerial; + /// + public UUID ItemID; + /// + public UUID FolderID; + /// + public UUID FromTaskID; + /// + public UUID LastOwnerID; + /// + public string Name; + /// + public string Description; + /// + public string TouchName; + /// + public string SitName; + /// + public UUID[] TextureIDs; + + /// + /// Default constructor + /// + public ObjectProperties() + { + Name = String.Empty; + Description = String.Empty; + TouchName = String.Empty; + SitName = String.Empty; + } + + /// + /// Set the properties that are set in an ObjectPropertiesFamily packet + /// + /// that has + /// been partially filled by an ObjectPropertiesFamily packet + public void SetFamilyProperties(ObjectProperties props) + { + ObjectID = props.ObjectID; + OwnerID = props.OwnerID; + GroupID = props.GroupID; + Permissions = props.Permissions; + OwnershipCost = props.OwnershipCost; + SaleType = props.SaleType; + SalePrice = props.SalePrice; + Category = props.Category; + LastOwnerID = props.LastOwnerID; + Name = props.Name; + Description = props.Description; + } + + public byte[] GetTextureIDBytes() + { + if (TextureIDs == null || TextureIDs.Length == 0) + return Utils.EmptyBytes; + + byte[] bytes = new byte[16 * TextureIDs.Length]; + for (int i = 0; i < TextureIDs.Length; i++) + TextureIDs[i].ToBytes(bytes, 16 * i); + + return bytes; + } + } + + /// + /// Describes physics attributes of the prim + /// + public class PhysicsProperties + { + /// Primitive's local ID + public uint LocalID; + /// Density (1000 for normal density) + public float Density; + /// Friction + public float Friction; + /// Gravity multiplier (1 for normal gravity) + public float GravityMultiplier; + /// Type of physics representation of this primitive in the simulator + public PhysicsShapeType PhysicsShapeType; + /// Restitution + public float Restitution; + + /// + /// Creates PhysicsProperties from OSD + /// + /// OSDMap with incoming data + /// Deserialized PhysicsProperties object + public static PhysicsProperties FromOSD(OSD osd) + { + PhysicsProperties ret = new PhysicsProperties(); + + if (osd is OSDMap) + { + OSDMap map = (OSDMap)osd; + ret.LocalID = map["LocalID"]; + ret.Density = map["Density"]; + ret.Friction = map["Friction"]; + ret.GravityMultiplier = map["GravityMultiplier"]; + ret.Restitution = map["Restitution"]; + ret.PhysicsShapeType = (PhysicsShapeType)map["PhysicsShapeType"].AsInteger(); + } + + return ret; + } + + /// + /// Serializes PhysicsProperties to OSD + /// + /// OSDMap with serialized PhysicsProperties data + public OSD GetOSD() + { + OSDMap map = new OSDMap(6); + map["LocalID"] = LocalID; + map["Density"] = Density; + map["Friction"] = Friction; + map["GravityMultiplier"] = GravityMultiplier; + map["Restitution"] = Restitution; + map["PhysicsShapeType"] = (int)PhysicsShapeType; + return map; + } + } + + #endregion Subclasses + + #region Public Members + + /// + public UUID ID; + /// + public UUID GroupID; + /// + public uint LocalID; + /// + public uint ParentID; + /// + public ulong RegionHandle; + /// + public PrimFlags Flags; + /// Foliage type for this primitive. Only applicable if this + /// primitive is foliage + public Tree TreeSpecies; + /// Unknown + public byte[] ScratchPad; + /// + public Vector3 Position; + /// + public Vector3 Scale; + /// + public Quaternion Rotation = Quaternion.Identity; + /// + public Vector3 Velocity; + /// + public Vector3 AngularVelocity; + /// + public Vector3 Acceleration; + /// + public Vector4 CollisionPlane; + /// + public FlexibleData Flexible; + /// + public LightData Light; + /// + public LightImage LightMap; + /// + public SculptData Sculpt; + /// + public ClickAction ClickAction; + /// + public UUID Sound; + /// Identifies the owner if audio or a particle system is + /// active + public UUID OwnerID; + /// + public SoundFlags SoundFlags; + /// + public float SoundGain; + /// + public float SoundRadius; + /// + public string Text; + /// + public Color4 TextColor; + /// + public string MediaURL; + /// + public JointType Joint; + /// + public Vector3 JointPivot; + /// + public Vector3 JointAxisOrAnchor; + /// + public NameValue[] NameValues; + /// + public ConstructionData PrimData; + /// + public ObjectProperties Properties; + /// Objects physics engine propertis + public PhysicsProperties PhysicsProps; + /// Extra data about primitive + public object Tag; + /// Indicates if prim is attached to an avatar + public bool IsAttachment; + /// Number of clients referencing this prim + public int ActiveClients = 0; + + #endregion Public Members + + #region Properties + + /// Uses basic heuristics to estimate the primitive shape + public PrimType Type + { + get + { + if (Sculpt != null && Sculpt.Type != SculptType.None && Sculpt.SculptTexture != UUID.Zero) + { + if (Sculpt.Type == SculptType.Mesh) + return PrimType.Mesh; + else + return PrimType.Sculpt; + } + + bool linearPath = (PrimData.PathCurve == PathCurve.Line || PrimData.PathCurve == PathCurve.Flexible); + float scaleY = PrimData.PathScaleY; + + if (linearPath) + { + switch (PrimData.ProfileCurve) + { + case ProfileCurve.Circle: + return PrimType.Cylinder; + case ProfileCurve.Square: + return PrimType.Box; + case ProfileCurve.IsoTriangle: + case ProfileCurve.EqualTriangle: + case ProfileCurve.RightTriangle: + return PrimType.Prism; + case ProfileCurve.HalfCircle: + default: + return PrimType.Unknown; + } + } + else + { + switch (PrimData.PathCurve) + { + case PathCurve.Flexible: + return PrimType.Unknown; + case PathCurve.Circle: + switch (PrimData.ProfileCurve) + { + case ProfileCurve.Circle: + if (scaleY > 0.75f) + return PrimType.Sphere; + else + return PrimType.Torus; + case ProfileCurve.HalfCircle: + return PrimType.Sphere; + case ProfileCurve.EqualTriangle: + return PrimType.Ring; + case ProfileCurve.Square: + if (scaleY <= 0.75f) + return PrimType.Tube; + else + return PrimType.Unknown; + default: + return PrimType.Unknown; + } + case PathCurve.Circle2: + if (PrimData.ProfileCurve == ProfileCurve.Circle) + return PrimType.Sphere; + else + return PrimType.Unknown; + default: + return PrimType.Unknown; + } + } + } + } + + #endregion Properties + + #region Constructors + + /// + /// Default constructor + /// + public Primitive() + { + // Default a few null property values to String.Empty + Text = String.Empty; + MediaURL = String.Empty; + } + + public Primitive(Primitive prim) + { + ID = prim.ID; + GroupID = prim.GroupID; + LocalID = prim.LocalID; + ParentID = prim.ParentID; + RegionHandle = prim.RegionHandle; + Flags = prim.Flags; + TreeSpecies = prim.TreeSpecies; + if (prim.ScratchPad != null) + { + ScratchPad = new byte[prim.ScratchPad.Length]; + Buffer.BlockCopy(prim.ScratchPad, 0, ScratchPad, 0, ScratchPad.Length); + } + else + ScratchPad = Utils.EmptyBytes; + Position = prim.Position; + Scale = prim.Scale; + Rotation = prim.Rotation; + Velocity = prim.Velocity; + AngularVelocity = prim.AngularVelocity; + Acceleration = prim.Acceleration; + CollisionPlane = prim.CollisionPlane; + Flexible = prim.Flexible; + Light = prim.Light; + LightMap = prim.LightMap; + Sculpt = prim.Sculpt; + ClickAction = prim.ClickAction; + Sound = prim.Sound; + OwnerID = prim.OwnerID; + SoundFlags = prim.SoundFlags; + SoundGain = prim.SoundGain; + SoundRadius = prim.SoundRadius; + Text = prim.Text; + TextColor = prim.TextColor; + MediaURL = prim.MediaURL; + Joint = prim.Joint; + JointPivot = prim.JointPivot; + JointAxisOrAnchor = prim.JointAxisOrAnchor; + if (prim.NameValues != null) + { + if (NameValues == null || NameValues.Length != prim.NameValues.Length) + NameValues = new NameValue[prim.NameValues.Length]; + Array.Copy(prim.NameValues, NameValues, prim.NameValues.Length); + } + else + NameValues = null; + PrimData = prim.PrimData; + Properties = prim.Properties; + // FIXME: Get a real copy constructor for TextureEntry instead of serializing to bytes and back + if (prim.Textures != null) + { + byte[] textureBytes = prim.Textures.GetBytes(); + Textures = new TextureEntry(textureBytes, 0, textureBytes.Length); + } + else + { + Textures = null; + } + TextureAnim = prim.TextureAnim; + ParticleSys = prim.ParticleSys; + } + + #endregion Constructors + + #region Public Methods + + public virtual OSD GetOSD() + { + OSDMap path = new OSDMap(14); + path["begin"] = OSD.FromReal(PrimData.PathBegin); + path["curve"] = OSD.FromInteger((int)PrimData.PathCurve); + path["end"] = OSD.FromReal(PrimData.PathEnd); + path["radius_offset"] = OSD.FromReal(PrimData.PathRadiusOffset); + path["revolutions"] = OSD.FromReal(PrimData.PathRevolutions); + path["scale_x"] = OSD.FromReal(PrimData.PathScaleX); + path["scale_y"] = OSD.FromReal(PrimData.PathScaleY); + path["shear_x"] = OSD.FromReal(PrimData.PathShearX); + path["shear_y"] = OSD.FromReal(PrimData.PathShearY); + path["skew"] = OSD.FromReal(PrimData.PathSkew); + path["taper_x"] = OSD.FromReal(PrimData.PathTaperX); + path["taper_y"] = OSD.FromReal(PrimData.PathTaperY); + path["twist"] = OSD.FromReal(PrimData.PathTwist); + path["twist_begin"] = OSD.FromReal(PrimData.PathTwistBegin); + + OSDMap profile = new OSDMap(4); + profile["begin"] = OSD.FromReal(PrimData.ProfileBegin); + profile["curve"] = OSD.FromInteger((int)PrimData.ProfileCurve); + profile["hole"] = OSD.FromInteger((int)PrimData.ProfileHole); + profile["end"] = OSD.FromReal(PrimData.ProfileEnd); + profile["hollow"] = OSD.FromReal(PrimData.ProfileHollow); + + OSDMap volume = new OSDMap(2); + volume["path"] = path; + volume["profile"] = profile; + + OSDMap prim = new OSDMap(20); + if (Properties != null) + { + prim["name"] = OSD.FromString(Properties.Name); + prim["description"] = OSD.FromString(Properties.Description); + } + else + { + prim["name"] = OSD.FromString("Object"); + prim["description"] = OSD.FromString(String.Empty); + } + + prim["phantom"] = OSD.FromBoolean(((Flags & PrimFlags.Phantom) != 0)); + prim["physical"] = OSD.FromBoolean(((Flags & PrimFlags.Physics) != 0)); + prim["position"] = OSD.FromVector3(Position); + prim["rotation"] = OSD.FromQuaternion(Rotation); + prim["scale"] = OSD.FromVector3(Scale); + prim["pcode"] = OSD.FromInteger((int)PrimData.PCode); + prim["material"] = OSD.FromInteger((int)PrimData.Material); + prim["shadows"] = OSD.FromBoolean(((Flags & PrimFlags.CastShadows) != 0)); + prim["state"] = OSD.FromInteger(PrimData.State); + + prim["id"] = OSD.FromUUID(ID); + prim["localid"] = OSD.FromUInteger(LocalID); + prim["parentid"] = OSD.FromUInteger(ParentID); + + prim["volume"] = volume; + + if (Textures != null) + prim["textures"] = Textures.GetOSD(); + + if ((TextureAnim.Flags & TextureAnimMode.ANIM_ON) != 0) + prim["texture_anim"] = TextureAnim.GetOSD(); + + if (Light != null) + prim["light"] = Light.GetOSD(); + + if (LightMap != null) + prim["light_image"] = LightMap.GetOSD(); + + if (Flexible != null) + prim["flex"] = Flexible.GetOSD(); + + if (Sculpt != null) + prim["sculpt"] = Sculpt.GetOSD(); + + return prim; + } + + public static Primitive FromOSD(OSD osd) + { + Primitive prim = new Primitive(); + Primitive.ConstructionData data; + + OSDMap map = (OSDMap)osd; + OSDMap volume = (OSDMap)map["volume"]; + OSDMap path = (OSDMap)volume["path"]; + OSDMap profile = (OSDMap)volume["profile"]; + + #region Path/Profile + + data.profileCurve = (byte)0; + data.Material = (Material)map["material"].AsInteger(); + data.PCode = (PCode)map["pcode"].AsInteger(); + data.State = (byte)map["state"].AsInteger(); + + data.PathBegin = (float)path["begin"].AsReal(); + data.PathCurve = (PathCurve)path["curve"].AsInteger(); + data.PathEnd = (float)path["end"].AsReal(); + data.PathRadiusOffset = (float)path["radius_offset"].AsReal(); + data.PathRevolutions = (float)path["revolutions"].AsReal(); + data.PathScaleX = (float)path["scale_x"].AsReal(); + data.PathScaleY = (float)path["scale_y"].AsReal(); + data.PathShearX = (float)path["shear_x"].AsReal(); + data.PathShearY = (float)path["shear_y"].AsReal(); + data.PathSkew = (float)path["skew"].AsReal(); + data.PathTaperX = (float)path["taper_x"].AsReal(); + data.PathTaperY = (float)path["taper_y"].AsReal(); + data.PathTwist = (float)path["twist"].AsReal(); + data.PathTwistBegin = (float)path["twist_begin"].AsReal(); + + data.ProfileBegin = (float)profile["begin"].AsReal(); + data.ProfileEnd = (float)profile["end"].AsReal(); + data.ProfileHollow = (float)profile["hollow"].AsReal(); + data.ProfileCurve = (ProfileCurve)profile["curve"].AsInteger(); + data.ProfileHole = (HoleType)profile["hole"].AsInteger(); + + #endregion Path/Profile + + prim.PrimData = data; + + if (map["phantom"].AsBoolean()) + prim.Flags |= PrimFlags.Phantom; + + if (map["physical"].AsBoolean()) + prim.Flags |= PrimFlags.Physics; + + if (map["shadows"].AsBoolean()) + prim.Flags |= PrimFlags.CastShadows; + + prim.ID = map["id"].AsUUID(); + prim.LocalID = map["localid"].AsUInteger(); + prim.ParentID = map["parentid"].AsUInteger(); + prim.Position = ((OSDArray)map["position"]).AsVector3(); + prim.Rotation = ((OSDArray)map["rotation"]).AsQuaternion(); + prim.Scale = ((OSDArray)map["scale"]).AsVector3(); + + if (map["flex"]) + prim.Flexible = FlexibleData.FromOSD(map["flex"]); + + if (map["light"]) + prim.Light = LightData.FromOSD(map["light"]); + + if (map["light_image"]) + prim.LightMap = LightImage.FromOSD(map["light_image"]); + + if (map["sculpt"]) + prim.Sculpt = SculptData.FromOSD(map["sculpt"]); + + prim.Textures = TextureEntry.FromOSD(map["textures"]); + + if (map["texture_anim"]) + prim.TextureAnim = TextureAnimation.FromOSD(map["texture_anim"]); + + prim.Properties = new ObjectProperties(); + + if (!string.IsNullOrEmpty(map["name"].AsString())) + { + prim.Properties.Name = map["name"].AsString(); + } + + if (!string.IsNullOrEmpty(map["description"].AsString())) + { + prim.Properties.Description = map["description"].AsString(); + } + + return prim; + } + + public int SetExtraParamsFromBytes(byte[] data, int pos) + { + int i = pos; + int totalLength = 1; + + if (data.Length == 0 || pos >= data.Length) + return 0; + + byte extraParamCount = data[i++]; + + for (int k = 0; k < extraParamCount; k++) + { + ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i); + i += 2; + + uint paramLength = Utils.BytesToUInt(data, i); + i += 4; + + if (type == ExtraParamType.Flexible) + Flexible = new FlexibleData(data, i); + else if (type == ExtraParamType.Light) + Light = new LightData(data, i); + else if (type == ExtraParamType.LightImage) + LightMap = new LightImage(data, i); + else if (type == ExtraParamType.Sculpt || type == ExtraParamType.Mesh) + Sculpt = new SculptData(data, i); + + i += (int)paramLength; + totalLength += (int)paramLength + 6; + } + + return totalLength; + } + + public byte[] GetExtraParamsBytes() + { + byte[] flexible = null; + byte[] light = null; + byte[] lightmap = null; + byte[] sculpt = null; + byte[] buffer = null; + int size = 1; + int pos = 0; + byte count = 0; + + if (Flexible != null) + { + flexible = Flexible.GetBytes(); + size += flexible.Length + 6; + ++count; + } + if (Light != null) + { + light = Light.GetBytes(); + size += light.Length + 6; + ++count; + } + if (LightMap != null) + { + lightmap = LightMap.GetBytes(); + size += lightmap.Length + 6; + ++count; + } + if (Sculpt != null) + { + sculpt = Sculpt.GetBytes(); + size += sculpt.Length + 6; + ++count; + } + + buffer = new byte[size]; + buffer[0] = count; + ++pos; + + if (flexible != null) + { + Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Flexible), 0, buffer, pos, 2); + pos += 2; + + Buffer.BlockCopy(Utils.UIntToBytes((uint)flexible.Length), 0, buffer, pos, 4); + pos += 4; + + Buffer.BlockCopy(flexible, 0, buffer, pos, flexible.Length); + pos += flexible.Length; + } + if (light != null) + { + Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Light), 0, buffer, pos, 2); + pos += 2; + + Buffer.BlockCopy(Utils.UIntToBytes((uint)light.Length), 0, buffer, pos, 4); + pos += 4; + + Buffer.BlockCopy(light, 0, buffer, pos, light.Length); + pos += light.Length; + } + if (lightmap != null) + { + Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.LightImage), 0, buffer, pos, 2); + pos += 2; + + Buffer.BlockCopy(Utils.UIntToBytes((uint)lightmap.Length), 0, buffer, pos, 4); + pos += 4; + + Buffer.BlockCopy(lightmap, 0, buffer, pos, lightmap.Length); + pos += lightmap.Length; + } + if (sculpt != null) + { + if (Sculpt.Type == SculptType.Mesh) + { + Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Mesh), 0, buffer, pos, 2); + } + else + { + Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Sculpt), 0, buffer, pos, 2); + } + pos += 2; + + Buffer.BlockCopy(Utils.UIntToBytes((uint)sculpt.Length), 0, buffer, pos, 4); + pos += 4; + + Buffer.BlockCopy(sculpt, 0, buffer, pos, sculpt.Length); + pos += sculpt.Length; + } + + return buffer; + } + + #endregion Public Methods + + #region Overrides + + public override bool Equals(object obj) + { + return (obj is Primitive) ? this == (Primitive)obj : false; + } + + public bool Equals(Primitive other) + { + return this == other; + } + + public override string ToString() + { + switch (PrimData.PCode) + { + case PCode.Prim: + return String.Format("{0} ({1})", Type, ID); + default: + return String.Format("{0} ({1})", PrimData.PCode, ID); + } + } + + public override int GetHashCode() + { + return + Position.GetHashCode() ^ + Velocity.GetHashCode() ^ + Acceleration.GetHashCode() ^ + Rotation.GetHashCode() ^ + AngularVelocity.GetHashCode() ^ + ClickAction.GetHashCode() ^ + (Flexible != null ? Flexible.GetHashCode() : 0) ^ + (Light != null ? Light.GetHashCode() : 0) ^ + (Sculpt != null ? Sculpt.GetHashCode() : 0) ^ + Flags.GetHashCode() ^ + PrimData.Material.GetHashCode() ^ + MediaURL.GetHashCode() ^ + //TODO: NameValues? + (Properties != null ? Properties.OwnerID.GetHashCode() : 0) ^ + ParentID.GetHashCode() ^ + PrimData.PathBegin.GetHashCode() ^ + PrimData.PathCurve.GetHashCode() ^ + PrimData.PathEnd.GetHashCode() ^ + PrimData.PathRadiusOffset.GetHashCode() ^ + PrimData.PathRevolutions.GetHashCode() ^ + PrimData.PathScaleX.GetHashCode() ^ + PrimData.PathScaleY.GetHashCode() ^ + PrimData.PathShearX.GetHashCode() ^ + PrimData.PathShearY.GetHashCode() ^ + PrimData.PathSkew.GetHashCode() ^ + PrimData.PathTaperX.GetHashCode() ^ + PrimData.PathTaperY.GetHashCode() ^ + PrimData.PathTwist.GetHashCode() ^ + PrimData.PathTwistBegin.GetHashCode() ^ + PrimData.PCode.GetHashCode() ^ + PrimData.ProfileBegin.GetHashCode() ^ + PrimData.ProfileCurve.GetHashCode() ^ + PrimData.ProfileEnd.GetHashCode() ^ + PrimData.ProfileHollow.GetHashCode() ^ + ParticleSys.GetHashCode() ^ + TextColor.GetHashCode() ^ + TextureAnim.GetHashCode() ^ + (Textures != null ? Textures.GetHashCode() : 0) ^ + SoundRadius.GetHashCode() ^ + Scale.GetHashCode() ^ + Sound.GetHashCode() ^ + PrimData.State.GetHashCode() ^ + Text.GetHashCode() ^ + TreeSpecies.GetHashCode(); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Primitive lhs, Primitive rhs) + { + if ((Object)lhs == null || (Object)rhs == null) + { + return (Object)rhs == (Object)lhs; + } + return (lhs.ID == rhs.ID); + } + + public static bool operator !=(Primitive lhs, Primitive rhs) + { + if ((Object)lhs == null || (Object)rhs == null) + { + return (Object)rhs != (Object)lhs; + } + return !(lhs.ID == rhs.ID); + } + + #endregion Operators + + #region Parameter Packing Methods + + public static ushort PackBeginCut(float beginCut) + { + return (ushort)Math.Round(beginCut / CUT_QUANTA); + } + + public static ushort PackEndCut(float endCut) + { + return (ushort)(50000 - (ushort)Math.Round(endCut / CUT_QUANTA)); + } + + public static byte PackPathScale(float pathScale) + { + return (byte)(200 - (byte)Math.Round(pathScale / SCALE_QUANTA)); + } + + public static sbyte PackPathShear(float pathShear) + { + return (sbyte)Math.Round(pathShear / SHEAR_QUANTA); + } + + /// + /// Packs PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew + /// parameters in to signed eight bit values + /// + /// Floating point parameter to pack + /// Signed eight bit value containing the packed parameter + public static sbyte PackPathTwist(float pathTwist) + { + return (sbyte)Math.Round(pathTwist / SCALE_QUANTA); + } + + public static sbyte PackPathTaper(float pathTaper) + { + return (sbyte)Math.Round(pathTaper / TAPER_QUANTA); + } + + public static byte PackPathRevolutions(float pathRevolutions) + { + return (byte)Math.Round((pathRevolutions - 1f) / REV_QUANTA); + } + + public static ushort PackProfileHollow(float profileHollow) + { + return (ushort)Math.Round(profileHollow / HOLLOW_QUANTA); + } + + #endregion Parameter Packing Methods + + #region Parameter Unpacking Methods + + public static float UnpackBeginCut(ushort beginCut) + { + return (float)beginCut * CUT_QUANTA; + } + + public static float UnpackEndCut(ushort endCut) + { + return (float)(50000 - endCut) * CUT_QUANTA; + } + + public static float UnpackPathScale(byte pathScale) + { + return (float)(200 - pathScale) * SCALE_QUANTA; + } + + public static float UnpackPathShear(sbyte pathShear) + { + return (float)pathShear * SHEAR_QUANTA; + } + + /// + /// Unpacks PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew + /// parameters from signed eight bit integers to floating point values + /// + /// Signed eight bit value to unpack + /// Unpacked floating point value + public static float UnpackPathTwist(sbyte pathTwist) + { + return (float)pathTwist * SCALE_QUANTA; + } + + public static float UnpackPathTaper(sbyte pathTaper) + { + return (float)pathTaper * TAPER_QUANTA; + } + + public static float UnpackPathRevolutions(byte pathRevolutions) + { + return (float)pathRevolutions * REV_QUANTA + 1f; + } + + public static float UnpackProfileHollow(ushort profileHollow) + { + return (float)profileHollow * HOLLOW_QUANTA; + } + + #endregion Parameter Unpacking Methods + } +} diff --git a/OpenMetaverse/Primitives/TextureEntry.cs b/OpenMetaverse/Primitives/TextureEntry.cs new file mode 100644 index 0000000..6e61167 --- /dev/null +++ b/OpenMetaverse/Primitives/TextureEntry.cs @@ -0,0 +1,1415 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse +{ + #region Enumerations + + /// + /// The type of bump-mapping applied to a face + /// + public enum Bumpiness : byte + { + /// + None = 0, + /// + Brightness = 1, + /// + Darkness = 2, + /// + Woodgrain = 3, + /// + Bark = 4, + /// + Bricks = 5, + /// + Checker = 6, + /// + Concrete = 7, + /// + Crustytile = 8, + /// + Cutstone = 9, + /// + Discs = 10, + /// + Gravel = 11, + /// + Petridish = 12, + /// + Siding = 13, + /// + Stonetile = 14, + /// + Stucco = 15, + /// + Suction = 16, + /// + Weave = 17 + } + + /// + /// The level of shininess applied to a face + /// + public enum Shininess : byte + { + /// + None = 0, + /// + Low = 0x40, + /// + Medium = 0x80, + /// + High = 0xC0 + } + + /// + /// The texture mapping style used for a face + /// + public enum MappingType : byte + { + /// + Default = 0, + /// + Planar = 2, + /// + Spherical = 4, + /// + Cylindrical = 6 + } + + /// + /// Flags in the TextureEntry block that describe which properties are + /// set + /// + [Flags] + public enum TextureAttributes : uint + { + /// + None = 0, + /// + TextureID = 1 << 0, + /// + RGBA = 1 << 1, + /// + RepeatU = 1 << 2, + /// + RepeatV = 1 << 3, + /// + OffsetU = 1 << 4, + /// + OffsetV = 1 << 5, + /// + Rotation = 1 << 6, + /// + Material = 1 << 7, + /// + Media = 1 << 8, + /// + Glow = 1 << 9, + /// + MaterialID = 1 << 10, + /// + All = 0xFFFFFFFF + } + + #endregion Enumerations + + public partial class Primitive + { + #region Enums + + /// + /// Texture animation mode + /// + [Flags] + public enum TextureAnimMode : uint + { + /// Disable texture animation + ANIM_OFF = 0x00, + /// Enable texture animation + ANIM_ON = 0x01, + /// Loop when animating textures + LOOP = 0x02, + /// Animate in reverse direction + REVERSE = 0x04, + /// Animate forward then reverse + PING_PONG = 0x08, + /// Slide texture smoothly instead of frame-stepping + SMOOTH = 0x10, + /// Rotate texture instead of using frames + ROTATE = 0x20, + /// Scale texture instead of using frames + SCALE = 0x40, + } + + #endregion Enums + + #region Subclasses + + /// + /// A single textured face. Don't instantiate this class yourself, use the + /// methods in TextureEntry + /// + public class TextureEntryFace : ICloneable + { + // +----------+ S = Shiny + // | SSFBBBBB | F = Fullbright + // | 76543210 | B = Bumpmap + // +----------+ + private const byte BUMP_MASK = 0x1F; + private const byte FULLBRIGHT_MASK = 0x20; + private const byte SHINY_MASK = 0xC0; + // +----------+ M = Media Flags (web page) + // | .....TTM | T = Texture Mapping + // | 76543210 | . = Unused + // +----------+ + private const byte MEDIA_MASK = 0x01; + private const byte TEX_MAP_MASK = 0x06; + + private Color4 rgba; + private float repeatU; + private float repeatV; + private float offsetU; + private float offsetV; + private float rotation; + private float glow; + private byte materialb; + private byte mediab; + private TextureAttributes hasAttribute; + private UUID textureID; + private UUID materialID; + private TextureEntryFace DefaultTexture; + + + #region Properties + + /// + internal byte material + { + get + { + if ((hasAttribute & TextureAttributes.Material) != 0) + return materialb; + else + return DefaultTexture.material; + } + set + { + materialb = value; + hasAttribute |= TextureAttributes.Material; + } + } + + /// + internal byte media + { + get + { + if ((hasAttribute & TextureAttributes.Media) != 0) + return mediab; + else + return DefaultTexture.media; + } + set + { + mediab = value; + hasAttribute |= TextureAttributes.Media; + } + } + + /// + public Color4 RGBA + { + get + { + if ((hasAttribute & TextureAttributes.RGBA) != 0) + return rgba; + else + return DefaultTexture.rgba; + } + set + { + rgba = value; + hasAttribute |= TextureAttributes.RGBA; + } + } + + /// + public float RepeatU + { + get + { + if ((hasAttribute & TextureAttributes.RepeatU) != 0) + return repeatU; + else + return DefaultTexture.repeatU; + } + set + { + repeatU = value; + hasAttribute |= TextureAttributes.RepeatU; + } + } + + /// + public float RepeatV + { + get + { + if ((hasAttribute & TextureAttributes.RepeatV) != 0) + return repeatV; + else + return DefaultTexture.repeatV; + } + set + { + repeatV = value; + hasAttribute |= TextureAttributes.RepeatV; + } + } + + /// + public float OffsetU + { + get + { + if ((hasAttribute & TextureAttributes.OffsetU) != 0) + return offsetU; + else + return DefaultTexture.offsetU; + } + set + { + offsetU = value; + hasAttribute |= TextureAttributes.OffsetU; + } + } + + /// + public float OffsetV + { + get + { + if ((hasAttribute & TextureAttributes.OffsetV) != 0) + return offsetV; + else + return DefaultTexture.offsetV; + } + set + { + offsetV = value; + hasAttribute |= TextureAttributes.OffsetV; + } + } + + /// + public float Rotation + { + get + { + if ((hasAttribute & TextureAttributes.Rotation) != 0) + return rotation; + else + return DefaultTexture.rotation; + } + set + { + rotation = value; + hasAttribute |= TextureAttributes.Rotation; + } + } + + /// + public float Glow + { + get + { + if ((hasAttribute & TextureAttributes.Glow) != 0) + return glow; + else + return DefaultTexture.glow; + } + set + { + glow = value; + hasAttribute |= TextureAttributes.Glow; + } + } + + /// + public Bumpiness Bump + { + get + { + if ((hasAttribute & TextureAttributes.Material) != 0) + return (Bumpiness)(material & BUMP_MASK); + else + return DefaultTexture.Bump; + } + set + { + // Clear out the old material value + material &= 0xE0; + // Put the new bump value in the material byte + material |= (byte)value; + hasAttribute |= TextureAttributes.Material; + } + } + + public Shininess Shiny + { + get + { + if ((hasAttribute & TextureAttributes.Material) != 0) + return (Shininess)(material & SHINY_MASK); + else + return DefaultTexture.Shiny; + } + set + { + // Clear out the old shiny value + material &= 0x3F; + // Put the new shiny value in the material byte + material |= (byte)value; + hasAttribute |= TextureAttributes.Material; + } + } + + public bool Fullbright + { + get + { + if ((hasAttribute & TextureAttributes.Material) != 0) + return (material & FULLBRIGHT_MASK) != 0; + else + return DefaultTexture.Fullbright; + } + set + { + // Clear out the old fullbright value + material &= 0xDF; + if (value) + { + material |= 0x20; + hasAttribute |= TextureAttributes.Material; + } + } + } + + /// In the future this will specify whether a webpage is + /// attached to this face + public bool MediaFlags + { + get + { + if ((hasAttribute & TextureAttributes.Media) != 0) + return (media & MEDIA_MASK) != 0; + else + return DefaultTexture.MediaFlags; + } + set + { + // Clear out the old mediaflags value + media &= 0xFE; + if (value) + { + media |= 0x01; + hasAttribute |= TextureAttributes.Media; + } + } + } + + public MappingType TexMapType + { + get + { + if ((hasAttribute & TextureAttributes.Media) != 0) + return (MappingType)(media & TEX_MAP_MASK); + else + return DefaultTexture.TexMapType; + } + set + { + // Clear out the old texmap value + media &= 0xF9; + // Put the new texmap value in the media byte + media |= (byte)value; + hasAttribute |= TextureAttributes.Media; + } + } + + /// + public UUID TextureID + { + get + { + if ((hasAttribute & TextureAttributes.TextureID) != 0) + return textureID; + else + return DefaultTexture.textureID; + } + set + { + textureID = value; + hasAttribute |= TextureAttributes.TextureID; + } + } + + /// + public UUID MaterialID + { + get + { + if ((hasAttribute & TextureAttributes.MaterialID) != 0) + return materialID; + else + return DefaultTexture.materialID; + } + set + { + materialID = value; + hasAttribute |= TextureAttributes.MaterialID; + } + } + + #endregion Properties + + /// + /// Contains the definition for individual faces + /// + /// + public TextureEntryFace(TextureEntryFace defaultTexture) + { + rgba = Color4.White; + repeatU = 1.0f; + repeatV = 1.0f; + + DefaultTexture = defaultTexture; + if (DefaultTexture == null) + hasAttribute = TextureAttributes.All; + else + hasAttribute = TextureAttributes.None; + } + + public OSD GetOSD(int faceNumber) + { + OSDMap tex = new OSDMap(10); + if (faceNumber >= 0) tex["face_number"] = OSD.FromInteger(faceNumber); + tex["colors"] = OSD.FromColor4(RGBA); + tex["scales"] = OSD.FromReal(RepeatU); + tex["scalet"] = OSD.FromReal(RepeatV); + tex["offsets"] = OSD.FromReal(OffsetU); + tex["offsett"] = OSD.FromReal(OffsetV); + tex["imagerot"] = OSD.FromReal(Rotation); + tex["bump"] = OSD.FromInteger((int)Bump); + tex["shiny"] = OSD.FromInteger((int)Shiny); + tex["fullbright"] = OSD.FromBoolean(Fullbright); + tex["media_flags"] = OSD.FromInteger(Convert.ToInt32(MediaFlags)); + tex["mapping"] = OSD.FromInteger((int)TexMapType); + tex["glow"] = OSD.FromReal(Glow); + + if (TextureID != Primitive.TextureEntry.WHITE_TEXTURE) + tex["imageid"] = OSD.FromUUID(TextureID); + else + tex["imageid"] = OSD.FromUUID(UUID.Zero); + + tex["materialid"] = OSD.FromUUID(materialID); + + return tex; + } + + public static TextureEntryFace FromOSD(OSD osd, TextureEntryFace defaultFace, out int faceNumber) + { + OSDMap map = (OSDMap)osd; + + TextureEntryFace face = new TextureEntryFace(defaultFace); + faceNumber = (map.ContainsKey("face_number")) ? map["face_number"].AsInteger() : -1; + Color4 rgba = face.RGBA; + rgba = ((OSDArray)map["colors"]).AsColor4(); + face.RGBA = rgba; + face.RepeatU = (float)map["scales"].AsReal(); + face.RepeatV = (float)map["scalet"].AsReal(); + face.OffsetU = (float)map["offsets"].AsReal(); + face.OffsetV = (float)map["offsett"].AsReal(); + face.Rotation = (float)map["imagerot"].AsReal(); + face.Bump = (Bumpiness)map["bump"].AsInteger(); + face.Shiny = (Shininess)map["shiny"].AsInteger(); + face.Fullbright = map["fullbright"].AsBoolean(); + face.MediaFlags = map["media_flags"].AsBoolean(); + face.TexMapType = (MappingType)map["mapping"].AsInteger(); + face.Glow = (float)map["glow"].AsReal(); + face.TextureID = map["imageid"].AsUUID(); + face.MaterialID = map["materialid"]; + return face; + } + + public object Clone() + { + TextureEntryFace ret = new TextureEntryFace(this.DefaultTexture == null ? null : (TextureEntryFace)this.DefaultTexture.Clone()); + ret.rgba = rgba; + ret.repeatU = repeatU; + ret.repeatV = repeatV; + ret.offsetU = offsetU; + ret.offsetV = offsetV; + ret.rotation = rotation; + ret.glow = glow; + ret.materialb = materialb; + ret.mediab = mediab; + ret.hasAttribute = hasAttribute; + ret.textureID = textureID; + ret.materialID = materialID; + return ret; + } + + public override int GetHashCode() + { + return + RGBA.GetHashCode() ^ + RepeatU.GetHashCode() ^ + RepeatV.GetHashCode() ^ + OffsetU.GetHashCode() ^ + OffsetV.GetHashCode() ^ + Rotation.GetHashCode() ^ + Glow.GetHashCode() ^ + Bump.GetHashCode() ^ + Shiny.GetHashCode() ^ + Fullbright.GetHashCode() ^ + MediaFlags.GetHashCode() ^ + TexMapType.GetHashCode() ^ + TextureID.GetHashCode() ^ + MaterialID.GetHashCode(); + } + + /// + /// + /// + /// + public override string ToString() + { + return String.Format("Color: {0} RepeatU: {1} RepeatV: {2} OffsetU: {3} OffsetV: {4} " + + "Rotation: {5} Bump: {6} Shiny: {7} Fullbright: {8} Mapping: {9} Media: {10} Glow: {11} ID: {12} MaterialID: {13}", + RGBA, RepeatU, RepeatV, OffsetU, OffsetV, Rotation, Bump, Shiny, Fullbright, TexMapType, + MediaFlags, Glow, TextureID, MaterialID); + } + } + + /// + /// Represents all of the texturable faces for an object + /// + /// Grid objects have infinite faces, with each face + /// using the properties of the default face unless set otherwise. So if + /// you have a TextureEntry with a default texture uuid of X, and face 18 + /// has a texture UUID of Y, every face would be textured with X except for + /// face 18 that uses Y. In practice however, primitives utilize a maximum + /// of nine faces + public class TextureEntry + { + public const int MAX_FACES = 32; + public static readonly UUID WHITE_TEXTURE = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); + + /// + public TextureEntryFace DefaultTexture; + /// + public TextureEntryFace[] FaceTextures = new TextureEntryFace[MAX_FACES]; + + /// + /// Constructor that takes a default texture UUID + /// + /// Texture UUID to use as the default texture + public TextureEntry(UUID defaultTextureID) + { + DefaultTexture = new TextureEntryFace(null); + DefaultTexture.TextureID = defaultTextureID; + } + + /// + /// Constructor that takes a TextureEntryFace for the + /// default face + /// + /// Face to use as the default face + public TextureEntry(TextureEntryFace defaultFace) + { + DefaultTexture = new TextureEntryFace(null); + DefaultTexture.Bump = defaultFace.Bump; + DefaultTexture.Fullbright = defaultFace.Fullbright; + DefaultTexture.MediaFlags = defaultFace.MediaFlags; + DefaultTexture.OffsetU = defaultFace.OffsetU; + DefaultTexture.OffsetV = defaultFace.OffsetV; + DefaultTexture.RepeatU = defaultFace.RepeatU; + DefaultTexture.RepeatV = defaultFace.RepeatV; + DefaultTexture.RGBA = defaultFace.RGBA; + DefaultTexture.Rotation = defaultFace.Rotation; + DefaultTexture.Glow = defaultFace.Glow; + DefaultTexture.Shiny = defaultFace.Shiny; + DefaultTexture.TexMapType = defaultFace.TexMapType; + DefaultTexture.TextureID = defaultFace.TextureID; + DefaultTexture.MaterialID = defaultFace.MaterialID; + } + + /// + /// Constructor that creates the TextureEntry class from a byte array + /// + /// Byte array containing the TextureEntry field + /// Starting position of the TextureEntry field in + /// the byte array + /// Length of the TextureEntry field, in bytes + public TextureEntry(byte[] data, int pos, int length) + { + FromBytes(data, pos, length); + } + + /// + /// This will either create a new face if a custom face for the given + /// index is not defined, or return the custom face for that index if + /// it already exists + /// + /// The index number of the face to create or + /// retrieve + /// A TextureEntryFace containing all the properties for that + /// face + public TextureEntryFace CreateFace(uint index) + { + if (index >= MAX_FACES) throw new Exception(index + " is outside the range of MAX_FACES"); + + if (FaceTextures[index] == null) + FaceTextures[index] = new TextureEntryFace(this.DefaultTexture); + + return FaceTextures[index]; + } + + /// + /// + /// + /// + /// + public TextureEntryFace GetFace(uint index) + { + if (index >= MAX_FACES) throw new Exception(index + " is outside the range of MAX_FACES"); + + if (FaceTextures[index] != null) + return FaceTextures[index]; + else + return DefaultTexture; + } + + /// + /// + /// + /// + public OSD GetOSD() + { + OSDArray array = new OSDArray(); + + // If DefaultTexture is null, assume the whole TextureEntry is empty + if (DefaultTexture == null) + return array; + + // Otherwise, always add default texture + array.Add(DefaultTexture.GetOSD(-1)); + + for (int i = 0; i < MAX_FACES; i++) + { + if (FaceTextures[i] != null) + array.Add(FaceTextures[i].GetOSD(i)); + } + + return array; + } + + public static TextureEntry FromOSD(OSD osd) + { + if (osd.Type == OSDType.Array) + { + OSDArray array = (OSDArray)osd; + OSDMap faceSD; + + if (array.Count > 0) + { + int faceNumber; + faceSD = (OSDMap)array[0]; + TextureEntryFace defaultFace = TextureEntryFace.FromOSD(faceSD, null, out faceNumber); + TextureEntry te = new TextureEntry(defaultFace); + + for (int i = 1; i < array.Count; i++) + { + TextureEntryFace tex = TextureEntryFace.FromOSD(array[i], defaultFace, out faceNumber); + if (faceNumber >= 0 && faceNumber < te.FaceTextures.Length) + te.FaceTextures[faceNumber] = tex; + } + + return te; + } + } + + return new TextureEntry(UUID.Zero); + } + + private void FromBytes(byte[] data, int pos, int length) + { + if (length < 16) + { + // No TextureEntry to process + DefaultTexture = null; + return; + } + else + { + DefaultTexture = new TextureEntryFace(null); + } + + uint bitfieldSize = 0; + uint faceBits = 0; + int i = pos; + + #region Texture + DefaultTexture.TextureID = new UUID(data, i); + i += 16; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + UUID tmpUUID = new UUID(data, i); + i += 16; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).TextureID = tmpUUID; + } + #endregion Texture + + #region Color + DefaultTexture.RGBA = new Color4(data, i, true); + i += 4; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + Color4 tmpColor = new Color4(data, i, true); + i += 4; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).RGBA = tmpColor; + } + #endregion Color + + #region RepeatU + DefaultTexture.RepeatU = Utils.BytesToFloat(data, i); + i += 4; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + float tmpFloat = Utils.BytesToFloat(data, i); + i += 4; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).RepeatU = tmpFloat; + } + #endregion RepeatU + + #region RepeatV + DefaultTexture.RepeatV = Utils.BytesToFloat(data, i); + i += 4; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + float tmpFloat = Utils.BytesToFloat(data, i); + i += 4; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).RepeatV = tmpFloat; + } + #endregion RepeatV + + #region OffsetU + DefaultTexture.OffsetU = Helpers.TEOffsetFloat(data, i); + i += 2; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + float tmpFloat = Helpers.TEOffsetFloat(data, i); + i += 2; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).OffsetU = tmpFloat; + } + #endregion OffsetU + + #region OffsetV + DefaultTexture.OffsetV = Helpers.TEOffsetFloat(data, i); + i += 2; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + float tmpFloat = Helpers.TEOffsetFloat(data, i); + i += 2; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).OffsetV = tmpFloat; + } + #endregion OffsetV + + #region Rotation + DefaultTexture.Rotation = Helpers.TERotationFloat(data, i); + i += 2; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + float tmpFloat = Helpers.TERotationFloat(data, i); + i += 2; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).Rotation = tmpFloat; + } + #endregion Rotation + + #region Material + DefaultTexture.material = data[i]; + i++; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + byte tmpByte = data[i]; + i++; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).material = tmpByte; + } + #endregion Material + + #region Media + DefaultTexture.media = data[i]; + i++; + + while (i - pos < length && ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + byte tmpByte = data[i]; + i++; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).media = tmpByte; + } + #endregion Media + + #region Glow + DefaultTexture.Glow = Helpers.TEGlowFloat(data, i); + i++; + + while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + float tmpFloat = Helpers.TEGlowFloat(data, i); + i++; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).Glow = tmpFloat; + } + #endregion Glow + + #region MaterialID + if (i - pos + 16 <= length) + { + DefaultTexture.MaterialID = new UUID(data, i); + i += 16; + + while (i - pos + 16 <= length && ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize)) + { + UUID tmpUUID = new UUID(data, i); + i += 16; + + for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1) + if ((faceBits & bit) != 0) + CreateFace(face).MaterialID = tmpUUID; + } + } + #endregion MaterialID + } + + /// + /// + /// + /// + public byte[] GetBytes() + { + if (DefaultTexture == null) + return Utils.EmptyBytes; + + using (MemoryStream memStream = new MemoryStream()) + { + using (BinaryWriter binWriter = new BinaryWriter(memStream)) + { + #region Bitfield Setup + + uint[] textures = new uint[FaceTextures.Length]; + InitializeArray(ref textures); + uint[] rgbas = new uint[FaceTextures.Length]; + InitializeArray(ref rgbas); + uint[] repeatus = new uint[FaceTextures.Length]; + InitializeArray(ref repeatus); + uint[] repeatvs = new uint[FaceTextures.Length]; + InitializeArray(ref repeatvs); + uint[] offsetus = new uint[FaceTextures.Length]; + InitializeArray(ref offsetus); + uint[] offsetvs = new uint[FaceTextures.Length]; + InitializeArray(ref offsetvs); + uint[] rotations = new uint[FaceTextures.Length]; + InitializeArray(ref rotations); + uint[] materials = new uint[FaceTextures.Length]; + InitializeArray(ref materials); + uint[] medias = new uint[FaceTextures.Length]; + InitializeArray(ref medias); + uint[] glows = new uint[FaceTextures.Length]; + InitializeArray(ref glows); + uint[] materialIDs = new uint[FaceTextures.Length]; + InitializeArray(ref materialIDs); + + for (int i = 0; i < FaceTextures.Length; i++) + { + if (FaceTextures[i] == null) continue; + + if (FaceTextures[i].TextureID != DefaultTexture.TextureID) + { + if (textures[i] == UInt32.MaxValue) textures[i] = 0; + textures[i] |= (uint)(1 << i); + } + if (FaceTextures[i].RGBA != DefaultTexture.RGBA) + { + if (rgbas[i] == UInt32.MaxValue) rgbas[i] = 0; + rgbas[i] |= (uint)(1 << i); + } + if (FaceTextures[i].RepeatU != DefaultTexture.RepeatU) + { + if (repeatus[i] == UInt32.MaxValue) repeatus[i] = 0; + repeatus[i] |= (uint)(1 << i); + } + if (FaceTextures[i].RepeatV != DefaultTexture.RepeatV) + { + if (repeatvs[i] == UInt32.MaxValue) repeatvs[i] = 0; + repeatvs[i] |= (uint)(1 << i); + } + if (Helpers.TEOffsetShort(FaceTextures[i].OffsetU) != Helpers.TEOffsetShort(DefaultTexture.OffsetU)) + { + if (offsetus[i] == UInt32.MaxValue) offsetus[i] = 0; + offsetus[i] |= (uint)(1 << i); + } + if (Helpers.TEOffsetShort(FaceTextures[i].OffsetV) != Helpers.TEOffsetShort(DefaultTexture.OffsetV)) + { + if (offsetvs[i] == UInt32.MaxValue) offsetvs[i] = 0; + offsetvs[i] |= (uint)(1 << i); + } + if (Helpers.TERotationShort(FaceTextures[i].Rotation) != Helpers.TERotationShort(DefaultTexture.Rotation)) + { + if (rotations[i] == UInt32.MaxValue) rotations[i] = 0; + rotations[i] |= (uint)(1 << i); + } + if (FaceTextures[i].material != DefaultTexture.material) + { + if (materials[i] == UInt32.MaxValue) materials[i] = 0; + materials[i] |= (uint)(1 << i); + } + if (FaceTextures[i].media != DefaultTexture.media) + { + if (medias[i] == UInt32.MaxValue) medias[i] = 0; + medias[i] |= (uint)(1 << i); + } + if (Helpers.TEGlowByte(FaceTextures[i].Glow) != Helpers.TEGlowByte(DefaultTexture.Glow)) + { + if (glows[i] == UInt32.MaxValue) glows[i] = 0; + glows[i] |= (uint)(1 << i); + } + if (FaceTextures[i].MaterialID != DefaultTexture.MaterialID) + { + if (materialIDs[i] == UInt32.MaxValue) materialIDs[i] = 0; + materialIDs[i] |= (uint)(1 << i); + } + } + + #endregion Bitfield Setup + + #region Texture + binWriter.Write(DefaultTexture.TextureID.GetBytes()); + for (int i = 0; i < textures.Length; i++) + { + if (textures[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(textures[i])); + binWriter.Write(FaceTextures[i].TextureID.GetBytes()); + } + } + binWriter.Write((byte)0); + #endregion Texture + + #region Color + // Serialize the color bytes inverted to optimize for zerocoding + binWriter.Write(DefaultTexture.RGBA.GetBytes(true)); + for (int i = 0; i < rgbas.Length; i++) + { + if (rgbas[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(rgbas[i])); + // Serialize the color bytes inverted to optimize for zerocoding + binWriter.Write(FaceTextures[i].RGBA.GetBytes(true)); + } + } + binWriter.Write((byte)0); + #endregion Color + + #region RepeatU + binWriter.Write(DefaultTexture.RepeatU); + for (int i = 0; i < repeatus.Length; i++) + { + if (repeatus[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(repeatus[i])); + binWriter.Write(FaceTextures[i].RepeatU); + } + } + binWriter.Write((byte)0); + #endregion RepeatU + + #region RepeatV + binWriter.Write(DefaultTexture.RepeatV); + for (int i = 0; i < repeatvs.Length; i++) + { + if (repeatvs[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(repeatvs[i])); + binWriter.Write(FaceTextures[i].RepeatV); + } + } + binWriter.Write((byte)0); + #endregion RepeatV + + #region OffsetU + binWriter.Write(Helpers.TEOffsetShort(DefaultTexture.OffsetU)); + for (int i = 0; i < offsetus.Length; i++) + { + if (offsetus[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(offsetus[i])); + binWriter.Write(Helpers.TEOffsetShort(FaceTextures[i].OffsetU)); + } + } + binWriter.Write((byte)0); + #endregion OffsetU + + #region OffsetV + binWriter.Write(Helpers.TEOffsetShort(DefaultTexture.OffsetV)); + for (int i = 0; i < offsetvs.Length; i++) + { + if (offsetvs[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(offsetvs[i])); + binWriter.Write(Helpers.TEOffsetShort(FaceTextures[i].OffsetV)); + } + } + binWriter.Write((byte)0); + #endregion OffsetV + + #region Rotation + binWriter.Write(Helpers.TERotationShort(DefaultTexture.Rotation)); + for (int i = 0; i < rotations.Length; i++) + { + if (rotations[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(rotations[i])); + binWriter.Write(Helpers.TERotationShort(FaceTextures[i].Rotation)); + } + } + binWriter.Write((byte)0); + #endregion Rotation + + #region Material + binWriter.Write(DefaultTexture.material); + for (int i = 0; i < materials.Length; i++) + { + if (materials[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(materials[i])); + binWriter.Write(FaceTextures[i].material); + } + } + binWriter.Write((byte)0); + #endregion Material + + #region Media + binWriter.Write(DefaultTexture.media); + for (int i = 0; i < medias.Length; i++) + { + if (medias[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(medias[i])); + binWriter.Write(FaceTextures[i].media); + } + } + binWriter.Write((byte)0); + #endregion Media + + #region Glow + binWriter.Write(Helpers.TEGlowByte(DefaultTexture.Glow)); + for (int i = 0; i < glows.Length; i++) + { + if (glows[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(glows[i])); + binWriter.Write(Helpers.TEGlowByte(FaceTextures[i].Glow)); + } + } + binWriter.Write((byte)0); + #endregion Glow + + #region MaterialID + binWriter.Write(DefaultTexture.MaterialID.GetBytes()); + for (int i = 0; i < materialIDs.Length; i++) + { + if (materialIDs[i] != UInt32.MaxValue) + { + binWriter.Write(GetFaceBitfieldBytes(materialIDs[i])); + binWriter.Write(FaceTextures[i].MaterialID.GetBytes()); + } + } + #endregion MaterialID + + return memStream.ToArray(); + } + } + } + + public override int GetHashCode() + { + int hashCode = DefaultTexture != null ? DefaultTexture.GetHashCode() : 0; + for (int i = 0; i < FaceTextures.Length; i++) + { + if (FaceTextures[i] != null) + hashCode ^= FaceTextures[i].GetHashCode(); + } + return hashCode; + } + + /// + /// + /// + /// + public override string ToString() + { + string output = String.Empty; + + output += "Default Face: " + DefaultTexture.ToString() + Environment.NewLine; + + for (int i = 0; i < FaceTextures.Length; i++) + { + if (FaceTextures[i] != null) + output += "Face " + i + ": " + FaceTextures[i].ToString() + Environment.NewLine; + } + + return output; + } + + #region Helpers + + private void InitializeArray(ref uint[] array) + { + for (int i = 0; i < array.Length; i++) + array[i] = UInt32.MaxValue; + } + + private bool ReadFaceBitfield(byte[] data, ref int pos, ref uint faceBits, ref uint bitfieldSize) + { + faceBits = 0; + bitfieldSize = 0; + + if (pos >= data.Length) + return false; + + byte b = 0; + do + { + b = data[pos]; + faceBits = (faceBits << 7) | (uint)(b & 0x7F); + bitfieldSize += 7; + pos++; + } + while ((b & 0x80) != 0); + + return (faceBits != 0); + } + + private byte[] GetFaceBitfieldBytes(uint bitfield) + { + int byteLength = 0; + uint tmpBitfield = bitfield; + while (tmpBitfield != 0) + { + tmpBitfield >>= 7; + byteLength++; + } + + if (byteLength == 0) + return new byte[1] { 0 }; + + byte[] bytes = new byte[byteLength]; + for (int i = 0; i < byteLength; i++) + { + bytes[i] = (byte)((bitfield >> (7 * (byteLength - i - 1))) & 0x7F); + if (i < byteLength - 1) + bytes[i] |= 0x80; + } + return bytes; + } + + #endregion Helpers + } + + /// + /// Controls the texture animation of a particular prim + /// + public struct TextureAnimation + { + /// + public TextureAnimMode Flags; + /// + public uint Face; + /// + public uint SizeX; + /// + public uint SizeY; + /// + public float Start; + /// + public float Length; + /// + public float Rate; + + /// + /// + /// + /// + /// + public TextureAnimation(byte[] data, int pos) + { + if (data.Length >= 16) + { + Flags = (TextureAnimMode)((uint)data[pos++]); + Face = (uint)data[pos++]; + SizeX = (uint)data[pos++]; + SizeY = (uint)data[pos++]; + + Start = Utils.BytesToFloat(data, pos); + Length = Utils.BytesToFloat(data, pos + 4); + Rate = Utils.BytesToFloat(data, pos + 8); + } + else + { + Flags = 0; + Face = 0; + SizeX = 0; + SizeY = 0; + + Start = 0.0f; + Length = 0.0f; + Rate = 0.0f; + } + } + + /// + /// + /// + /// + public byte[] GetBytes() + { + byte[] data = new byte[16]; + int pos = 0; + + data[pos++] = (byte)Flags; + data[pos++] = (byte)Face; + data[pos++] = (byte)SizeX; + data[pos++] = (byte)SizeY; + + Utils.FloatToBytes(Start).CopyTo(data, pos); + Utils.FloatToBytes(Length).CopyTo(data, pos + 4); + Utils.FloatToBytes(Rate).CopyTo(data, pos + 4); + + return data; + } + + public OSD GetOSD() + { + OSDMap map = new OSDMap(); + + map["face"] = OSD.FromInteger(Face); + map["flags"] = OSD.FromInteger((uint)Flags); + map["length"] = OSD.FromReal(Length); + map["rate"] = OSD.FromReal(Rate); + map["size_x"] = OSD.FromInteger(SizeX); + map["size_y"] = OSD.FromInteger(SizeY); + map["start"] = OSD.FromReal(Start); + + return map; + } + + public static TextureAnimation FromOSD(OSD osd) + { + TextureAnimation anim = new TextureAnimation(); + OSDMap map = osd as OSDMap; + + if (map != null) + { + anim.Face = map["face"].AsUInteger(); + anim.Flags = (TextureAnimMode)map["flags"].AsUInteger(); + anim.Length = (float)map["length"].AsReal(); + anim.Rate = (float)map["rate"].AsReal(); + anim.SizeX = map["size_x"].AsUInteger(); + anim.SizeY = map["size_y"].AsUInteger(); + anim.Start = (float)map["start"].AsReal(); + } + + return anim; + } + } + + #endregion Subclasses + + #region Public Members + + /// + public TextureEntry Textures; + /// + public TextureAnimation TextureAnim; + + #endregion Public Members + } +} diff --git a/OpenMetaverse/ProtocolManager.cs b/OpenMetaverse/ProtocolManager.cs new file mode 100644 index 0000000..4e45c4f --- /dev/null +++ b/OpenMetaverse/ProtocolManager.cs @@ -0,0 +1,689 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using OpenMetaverse; + +namespace OpenMetaverse +{ + /// + /// + /// + public enum FieldType + { + /// + U8, + /// + U16, + /// + U32, + /// + U64, + /// + S8, + /// + S16, + /// + S32, + /// + F32, + /// + F64, + /// + UUID, + /// + BOOL, + /// + Vector3, + /// + Vector3d, + /// + Vector4, + /// + Quaternion, + /// + IPADDR, + /// + IPPORT, + /// + Variable, + /// + Fixed, + /// + Single, + /// + Multiple + } + + /// + /// + /// + public class MapField : IComparable + { + /// + public int KeywordPosition; + /// + public string Name; + /// + public FieldType Type; + /// + public int Count; + + /// + /// + /// + /// + /// + public int CompareTo(object obj) + { + MapField temp = (MapField)obj; + + if (this.KeywordPosition > temp.KeywordPosition) + { + return 1; + } + else + { + if(temp.KeywordPosition == this.KeywordPosition) + { + return 0; + } + else + { + return -1; + } + } + } + } + + /// + /// + /// + public class MapBlock : IComparable + { + /// + public int KeywordPosition; + /// + public string Name; + /// + public int Count; + /// + public List Fields; + + /// + /// + /// + /// + /// + public int CompareTo(object obj) + { + MapBlock temp = (MapBlock)obj; + + if (this.KeywordPosition > temp.KeywordPosition) + { + return 1; + } + else + { + if(temp.KeywordPosition == this.KeywordPosition) + { + return 0; + } + else + { + return -1; + } + } + } + } + + /// + /// + /// + public class MapPacket + { + /// + public ushort ID; + /// + public string Name; + /// + public PacketFrequency Frequency; + /// + public bool Trusted; + /// + public bool Encoded; + /// + public List Blocks; + } + + /// + /// + /// + public class ProtocolManager + { + /// + public Dictionary TypeSizes; + /// + public Dictionary KeywordPositions; + /// + public MapPacket[] LowMaps; + /// + public MapPacket[] MediumMaps; + /// + public MapPacket[] HighMaps; + + private GridClient Client; + + /// + /// + /// + /// + /// + public ProtocolManager(string mapFile, GridClient client) + { + Client = client; + + // Initialize the map arrays + LowMaps = new MapPacket[65536]; + MediumMaps = new MapPacket[256]; + HighMaps = new MapPacket[256]; + + // Build the type size hash table + TypeSizes = new Dictionary(); + TypeSizes.Add(FieldType.U8, 1); + TypeSizes.Add(FieldType.U16, 2); + TypeSizes.Add(FieldType.U32, 4); + TypeSizes.Add(FieldType.U64, 8); + TypeSizes.Add(FieldType.S8, 1); + TypeSizes.Add(FieldType.S16, 2); + TypeSizes.Add(FieldType.S32, 4); + TypeSizes.Add(FieldType.F32, 4); + TypeSizes.Add(FieldType.F64, 8); + TypeSizes.Add(FieldType.UUID, 16); + TypeSizes.Add(FieldType.BOOL, 1); + TypeSizes.Add(FieldType.Vector3, 12); + TypeSizes.Add(FieldType.Vector3d, 24); + TypeSizes.Add(FieldType.Vector4, 16); + TypeSizes.Add(FieldType.Quaternion, 16); + TypeSizes.Add(FieldType.IPADDR, 4); + TypeSizes.Add(FieldType.IPPORT, 2); + TypeSizes.Add(FieldType.Variable, -1); + TypeSizes.Add(FieldType.Fixed, -2); + + KeywordPositions = new Dictionary(); + LoadMapFile(mapFile); + } + + /// + /// + /// + /// + /// + public MapPacket Command(string command) + { + foreach (MapPacket map in HighMaps) + { + if (map != null) + { + if (command == map.Name) + { + return map; + } + } + } + + foreach (MapPacket map in MediumMaps) + { + if (map != null) + { + if (command == map.Name) + { + return map; + } + } + } + + foreach (MapPacket map in LowMaps) + { + if (map != null) + { + if (command == map.Name) + { + return map; + } + } + } + + throw new Exception("Cannot find map for command \"" + command + "\""); + } + + /// + /// + /// + /// + /// + public MapPacket Command(byte[] data) + { + ushort command; + + if (data.Length < 5) + { + return null; + } + + if (data[4] == 0xFF) + { + if ((byte)data[5] == 0xFF) + { + // Low frequency + command = (ushort)(data[6] * 256 + data[7]); + return Command(command, PacketFrequency.Low); + } + else + { + // Medium frequency + command = (ushort)data[5]; + return Command(command, PacketFrequency.Medium); + } + } + else + { + // High frequency + command = (ushort)data[4]; + return Command(command, PacketFrequency.High); + } + } + + /// + /// + /// + /// + /// + /// + public MapPacket Command(ushort command, PacketFrequency frequency) + { + switch (frequency) + { + case PacketFrequency.High: + return HighMaps[command]; + case PacketFrequency.Medium: + return MediumMaps[command]; + case PacketFrequency.Low: + return LowMaps[command]; + } + + throw new Exception("Cannot find map for command \"" + command + "\" with frequency \"" + frequency + "\""); + } + + /// + /// + /// + public void PrintMap() + { + PrintOneMap(LowMaps, "Low "); + PrintOneMap(MediumMaps, "Medium"); + PrintOneMap(HighMaps, "High "); + } + + /// + /// + /// + /// + /// + private void PrintOneMap(MapPacket[] map, string frequency) { + int i; + + for (i = 0; i < map.Length; ++i) + { + if (map[i] != null) + { + Console.WriteLine("{0} {1,5} - {2} - {3} - {4}", frequency, i, map[i].Name, + map[i].Trusted ? "Trusted" : "Untrusted", + map[i].Encoded ? "Unencoded" : "Zerocoded"); + + foreach (MapBlock block in map[i].Blocks) + { + if (block.Count == -1) + { + Console.WriteLine("\t{0,4} {1} (Variable)", block.KeywordPosition, block.Name); + } + else + { + Console.WriteLine("\t{0,4} {1} ({2})", block.KeywordPosition, block.Name, block.Count); + } + + foreach (MapField field in block.Fields) + { + Console.WriteLine("\t\t{0,4} {1} ({2} / {3})", field.KeywordPosition, field.Name, + field.Type, field.Count); + } + } + } + } + } + + /// + /// + /// + /// + /// + public static void DecodeMapFile(string mapFile, string outputFile) + { + byte magicKey = 0; + byte[] buffer = new byte[2048]; + int nread; + + try + { + using (BinaryReader map = new BinaryReader(new FileStream(mapFile, FileMode.Open))) + { + using (BinaryWriter output = new BinaryWriter(new FileStream(outputFile, FileMode.CreateNew))) + { + while ((nread = map.Read(buffer, 0, 2048)) != 0) + { + for (int i = 0; i < nread; ++i) + { + buffer[i] ^= magicKey; + magicKey += 43; + } + + output.Write(buffer, 0, nread); + } + } + } + } + catch (Exception e) + { + throw new Exception("Map file error", e); + } + } + + /// + /// + /// + /// + private void LoadMapFile(string mapFile) + { + ushort low = 1; + ushort medium = 1; + ushort high = 1; + + // Load the protocol map file + try + { + using (FileStream map = new FileStream(mapFile, FileMode.Open, FileAccess.Read)) + { + using (StreamReader r = new StreamReader(map)) + { + r.BaseStream.Seek(0, SeekOrigin.Begin); + string newline; + string trimmedline; + bool inPacket = false; + bool inBlock = false; + MapPacket currentPacket = null; + MapBlock currentBlock = null; + char[] trimArray = new char[] { ' ', '\t' }; + + // While not at the end of the file + while (r.Peek() > -1) + { + #region ParseMap + + newline = r.ReadLine(); + trimmedline = System.Text.RegularExpressions.Regex.Replace(newline, @"\s+", " "); + trimmedline = trimmedline.Trim(trimArray); + + if (!inPacket) + { + // Outside of all packet blocks + + if (trimmedline == "{") + { + inPacket = true; + } + } + else + { + // Inside of a packet block + + if (!inBlock) + { + // Inside a packet block, outside of the blocks + + if (trimmedline == "{") + { + inBlock = true; + } + else if (trimmedline == "}") + { + // Reached the end of the packet + currentPacket.Blocks.Sort(); + inPacket = false; + } + else + { + // The packet header + #region ParsePacketHeader + + // Splice the string in to tokens + string[] tokens = trimmedline.Split(new char[] { ' ', '\t' }); + + if (tokens.Length > 3) + { + //Hash packet name to insure correct keyword ordering + KeywordPosition(tokens[0]); + + if (tokens[1] == "Fixed") + { + // Remove the leading "0x" + if (tokens[2].Substring(0, 2) == "0x") + { + tokens[2] = tokens[2].Substring(2, tokens[2].Length - 2); + } + + uint fixedID = UInt32.Parse(tokens[2], System.Globalization.NumberStyles.HexNumber); + // Truncate the id to a short + fixedID ^= 0xFFFF0000; + LowMaps[fixedID] = new MapPacket(); + LowMaps[fixedID].ID = (ushort)fixedID; + LowMaps[fixedID].Frequency = PacketFrequency.Low; + LowMaps[fixedID].Name = tokens[0]; + LowMaps[fixedID].Trusted = (tokens[3] == "Trusted"); + LowMaps[fixedID].Encoded = (tokens[4] == "Zerocoded"); + LowMaps[fixedID].Blocks = new List(); + + currentPacket = LowMaps[fixedID]; + } + else if (tokens[1] == "Low") + { + LowMaps[low] = new MapPacket(); + LowMaps[low].ID = low; + LowMaps[low].Frequency = PacketFrequency.Low; + LowMaps[low].Name = tokens[0]; + LowMaps[low].Trusted = (tokens[2] == "Trusted"); + LowMaps[low].Encoded = (tokens[3] == "Zerocoded"); + LowMaps[low].Blocks = new List(); + + currentPacket = LowMaps[low]; + + low++; + } + else if (tokens[1] == "Medium") + { + MediumMaps[medium] = new MapPacket(); + MediumMaps[medium].ID = medium; + MediumMaps[medium].Frequency = PacketFrequency.Medium; + MediumMaps[medium].Name = tokens[0]; + MediumMaps[medium].Trusted = (tokens[2] == "Trusted"); + MediumMaps[medium].Encoded = (tokens[3] == "Zerocoded"); + MediumMaps[medium].Blocks = new List(); + + currentPacket = MediumMaps[medium]; + + medium++; + } + else if (tokens[1] == "High") + { + HighMaps[high] = new MapPacket(); + HighMaps[high].ID = high; + HighMaps[high].Frequency = PacketFrequency.High; + HighMaps[high].Name = tokens[0]; + HighMaps[high].Trusted = (tokens[2] == "Trusted"); + HighMaps[high].Encoded = (tokens[3] == "Zerocoded"); + HighMaps[high].Blocks = new List(); + + currentPacket = HighMaps[high]; + + high++; + } + else + { + Logger.Log("Unknown packet frequency", Helpers.LogLevel.Error, Client); + } + } + + #endregion + } + } + else + { + if (trimmedline.Length > 0 && trimmedline.Substring(0, 1) == "{") + { + // A field + #region ParseField + + MapField field = new MapField(); + + // Splice the string in to tokens + string[] tokens = trimmedline.Split(new char[] { ' ', '\t' }); + + field.Name = tokens[1]; + field.KeywordPosition = KeywordPosition(field.Name); + field.Type = (FieldType)Enum.Parse(typeof(FieldType), tokens[2], true); + + if (tokens[3] != "}") + { + field.Count = Int32.Parse(tokens[3]); + } + else + { + field.Count = 1; + } + + // Save this field to the current block + currentBlock.Fields.Add(field); + + #endregion + } + else if (trimmedline == "}") + { + currentBlock.Fields.Sort(); + inBlock = false; + } + else if (trimmedline.Length != 0 && trimmedline.Substring(0, 2) != "//") + { + // The block header + #region ParseBlockHeader + + currentBlock = new MapBlock(); + + // Splice the string in to tokens + string[] tokens = trimmedline.Split(new char[] { ' ', '\t' }); + + currentBlock.Name = tokens[0]; + currentBlock.KeywordPosition = KeywordPosition(currentBlock.Name); + currentBlock.Fields = new List(); + currentPacket.Blocks.Add(currentBlock); + + if (tokens[1] == "Single") + { + currentBlock.Count = 1; + } + else if (tokens[1] == "Multiple") + { + currentBlock.Count = Int32.Parse(tokens[2]); + } + else if (tokens[1] == "Variable") + { + currentBlock.Count = -1; + } + else + { + Logger.Log("Unknown block frequency", Helpers.LogLevel.Error, Client); + } + + #endregion + } + } + } + + #endregion + } + } + + } + } + catch (Exception e) + { + throw new Exception("Map file parsing error", e); ; + } + } + + private int KeywordPosition(string keyword) + { + if (KeywordPositions.ContainsKey(keyword)) + { + return KeywordPositions[keyword]; + } + + int hash = 0; + for (int i = 1; i < keyword.Length; i++) + { + hash = (hash + (int)(keyword[i])) * 2; + } + hash *= 2; + hash &= 0x1FFF; + + int startHash = hash; + + while (KeywordPositions.ContainsValue(hash)) + { + hash++; + hash &= 0x1FFF; + if (hash == startHash) + { + //Give up looking, went through all values and they were all taken. + throw new Exception("All hash values are taken. Failed to add keyword: " + keyword); + } + } + + KeywordPositions[keyword] = hash; + return hash; + } + } +} diff --git a/OpenMetaverse/Rendering/EndianAwareBinaryReader.cs b/OpenMetaverse/Rendering/EndianAwareBinaryReader.cs new file mode 100644 index 0000000..70822a9 --- /dev/null +++ b/OpenMetaverse/Rendering/EndianAwareBinaryReader.cs @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; + +namespace OpenMetaverse.Rendering +{ + /// + /// Binary reader, which is endian aware + /// + public class EndianAwareBinaryReader : BinaryReader + { + /// What is the format of the source file + public enum SourceFormat + { + BigEndian, //!< The stream is big endian, SPARC, Arm and friends + LittleEndian //!< x86 and friends + } + + private byte[] m_a16 = new byte[2]; //!< Temporary storage area for 2 byte values + private byte[] m_a32 = new byte[4]; //!< Temporary storage area for 4 byte values + private byte[] m_a64 = new byte[8]; //!< Temporary storage area for 8 byte values + + private readonly bool m_shouldReverseOrder; //!< true if the file is in a different endian format than the system + + /// + /// Construct a reader from a stream + /// + /// The stream to read from + public EndianAwareBinaryReader(Stream stream) + : this(stream, SourceFormat.LittleEndian) {} + + /// + /// Construct a reader from a stream + /// + /// The stream to read from + /// What is the format of the file, assumes PC and similar architecture + public EndianAwareBinaryReader(Stream stream, SourceFormat format) + : base(stream) + { + if ((format == SourceFormat.BigEndian && BitConverter.IsLittleEndian) || + (format == SourceFormat.LittleEndian && !BitConverter.IsLittleEndian)) + m_shouldReverseOrder = true; + } + + /// + /// Read a 32 bit integer + /// + /// A 32 bit integer in the system's endianness + public override int ReadInt32() + { + m_a32 = base.ReadBytes(4); + if (m_shouldReverseOrder) + Array.Reverse(m_a32); + return BitConverter.ToInt32(m_a32, 0); + } + + /// + /// Read a 16 bit integer + /// + /// A 16 bit integer in the system's endianness + public override Int16 ReadInt16() + { + m_a16 = base.ReadBytes(2); + if (m_shouldReverseOrder) + Array.Reverse(m_a16); + return BitConverter.ToInt16(m_a16, 0); + } + + /// + /// Read a 64 bit integer + /// + /// A 64 bit integer in the system's endianness + public override Int64 ReadInt64() + { + m_a64 = base.ReadBytes(8); + if (m_shouldReverseOrder) + Array.Reverse(m_a64); + return BitConverter.ToInt64(m_a64, 0); + } + + /// + /// Read an unsigned 32 bit integer + /// + /// A 32 bit unsigned integer in the system's endianness + public override UInt32 ReadUInt32() + { + m_a32 = base.ReadBytes(4); + if (m_shouldReverseOrder) + Array.Reverse(m_a32); + return BitConverter.ToUInt32(m_a32, 0); + } + + /// + /// Read a single precision floating point value + /// + /// A single precision floating point value in the system's endianness + public override float ReadSingle() + { + m_a32 = base.ReadBytes(4); + if (m_shouldReverseOrder) + Array.Reverse(m_a32); + return BitConverter.ToSingle(m_a32, 0); + } + + /// + /// Read a double precision floating point value + /// + /// A double precision floating point value in the system's endianness + public override double ReadDouble() + { + m_a64 = base.ReadBytes(8); + if (m_shouldReverseOrder) + Array.Reverse(m_a64); + return BitConverter.ToDouble(m_a64, 0); + } + + /// + /// Read a UTF-8 string + /// + /// A standard system string + public override string ReadString() + { + using (MemoryStream ms = new MemoryStream()) + { + byte b = ReadByte(); + while (b != 0) + { + ms.WriteByte(b); + b = ReadByte(); + } + return System.Text.Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Position); + } + } + + /// + /// Read a UTF-8 string + /// + /// length of string to read + /// A standard system string + public string ReadString(int size) + { + byte[] buffer = ReadBytes(size); + return System.Text.Encoding.UTF8.GetString(buffer).Trim(); + } + } +} diff --git a/OpenMetaverse/Rendering/LindenMesh.cs b/OpenMetaverse/Rendering/LindenMesh.cs new file mode 100644 index 0000000..a556bab --- /dev/null +++ b/OpenMetaverse/Rendering/LindenMesh.cs @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; + +namespace OpenMetaverse.Rendering +{ + /// + /// Load and handle Linden Lab binary meshes. + /// + /// + /// The exact definition of this file is a bit sketchy, especially concerning skin weights. + /// A good starting point is on the + /// second life wiki + /// + public class LindenMesh + { + const string MeshHeader = "Linden Binary Mesh 1.0"; + const string MorphFooter = "End Morphs"; + public LindenSkeleton Skeleton { get; private set; } //!< The skeleton used to animate this mesh + + #region Mesh Structs + + /// + /// Defines a polygon + /// + public struct Face + { + public short[] Indices; //!< Indices into the vertex array + } + + /// + /// Structure of a vertex, No surprises there, except for the Detail tex coord + /// + /// + /// The skinweights are a tad unconventional. The best explanation found is: + /// >Each weight actually contains two pieces of information. The number to the + /// >left of the decimal point is the index of the joint and also implicitly + /// >indexes to the following joint. The actual weight is to the right of the + /// >decimal point and interpolates between these two joints. The index is into + /// >an "expanded" list of joints, not just a linear array of the joints as + /// >defined in the skeleton file. In particular, any joint that has more than + /// >one child will be repeated in the list for each of its children. + /// + /// Maybe I'm dense, but that description seems to be a bit hard to build an + /// algorithm on. + /// + /// Esentially the weights are compressed into one floating point value. + /// 1. The whole number part is an index into an array of joints + /// 2. The fractional part is the weight that joint has + /// 3. If the fractional part is 0 (x.0000) then the vertex is 100% influenced by the specified joint + /// + public struct Vertex + { + public Vector3 Coord; //!< 3d co-ordinate of the vertex + public Vector3 Normal; //!< Normal of the vertex + public Vector3 BiNormal; //!< Bi normal of the vertex + public Vector2 TexCoord; //!< UV maping of the vertex + public Vector2 DetailTexCoord; //!< Detailed? UV mapping + public float Weight; //!< Used to calculate the skin weights + + /// + /// Provide a nice format for debugging + /// + /// Vertex definition as a string + public override string ToString() + { + return String.Format("Coord: {0} Norm: {1} BiNorm: {2} TexCoord: {3} DetailTexCoord: {4}", Coord, Normal, BiNormal, TexCoord, DetailTexCoord); + } + } + + /// + /// Describes deltas to apply to a vertex in order to morph a vertex + /// + public struct MorphVertex + { + public uint VertexIndex; //!< Index into the vertex list of the vertex to change + public Vector3 Coord; //!< Delta position + public Vector3 Normal; //!< Delta normal + public Vector3 BiNormal; //!< Delta BiNormal + public Vector2 TexCoord; //!< Delta UV mapping + + /// + /// Provide a nice format for debugging + /// + /// MorphVertex definition as a string + public override string ToString() + { + return String.Format("Index: {0} Coord: {1} Norm: {2} BiNorm: {3} TexCoord: {4}", VertexIndex, Coord, Normal, BiNormal, TexCoord); + } + } + + /// + /// Describes a named mesh morph, essentially a named list of MorphVertices + /// + public struct Morph + { + public string Name; //!< Name of the morph + public int NumVertices; //!< Number of vertices to distort + public MorphVertex[] Vertices; //!< The actual list of morph vertices + + /// + /// Provide a nice format for debugging + /// + /// The name of the morph + public override string ToString() + { + return Name; + } + } + + /// + /// Don't really know what this does + /// + public struct VertexRemap + { + public int RemapSource; //!< Source index + public int RemapDestination; //!< Destination index + + /// + /// Provide a nice format for debugging + /// + /// Human friendly format + public override string ToString() + { + return String.Format("{0} -> {1}", RemapSource, RemapDestination); + } + } + #endregion Mesh Structs + + #region reference mesh + /// + /// A reference mesh is one way to implement level of detail + /// + /// + /// Reference meshes are supplemental meshes to full meshes. For all practical + /// purposes almost all lod meshes are implemented as reference meshes, except for + /// 'avatar_eye_1.llm' which for some reason is implemented as a full mesh. + /// + public class ReferenceMesh + { + public float MinPixelWidth; //!< Pixel width on screen before switching to coarser lod + + public string Header; //!< Header - marking the file as a Linden Lab Mesh (llm) + public bool HasWeights; //!< Do the vertices carry any defintions about skin weights + public bool HasDetailTexCoords; //!< Do the vertices carry any defintions about detailed UV mappings + public Vector3 Position; //!< Origin of this mesh + public Vector3 RotationAngles; //!< Used to reconstruct a normalized quarternion (These are *NOT* Euler rotations) + public byte RotationOrder; //!< Not used + public Vector3 Scale; //!< Scaling information + public ushort NumFaces; //!< # of polygons in the mesh + public Face[] Faces; //!< Polygons making up the mesh, the indices are into the full mesh + + + /// + /// Load a mesh from a stream + /// + /// Filename and path of the file containing the reference mesh + public virtual void LoadMesh(string filename) + { + using(FileStream meshStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) + using (EndianAwareBinaryReader reader = new EndianAwareBinaryReader(meshStream)) + { + Header = TrimAt0(reader.ReadString(24)); + if (!String.Equals(Header, MeshHeader)) + throw new FileLoadException("Unrecognized mesh format"); + + // Populate base mesh parameters + HasWeights = (reader.ReadByte() != 0); + HasDetailTexCoords = (reader.ReadByte() != 0); + Position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + RotationAngles = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + RotationOrder = reader.ReadByte(); + Scale = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + NumFaces = reader.ReadUInt16(); + + Faces = new Face[NumFaces]; + + for (int i = 0; i < NumFaces; i++) + Faces[i].Indices = new[] { reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16() }; + } + } + } + + /// + /// Level of Detail mesh + /// + [Obsolete("Renamed to: ReferenceMesh")] + public class LODMesh + { + public float MinPixelWidth; + + protected string _header; + protected bool _hasWeights; + protected bool _hasDetailTexCoords; + protected Vector3 _position; + protected Vector3 _rotationAngles; + protected byte _rotationOrder; + protected Vector3 _scale; + protected ushort _numFaces; + protected Face[] _faces; + + public virtual void LoadMesh(string filename) + { + byte[] buffer = File.ReadAllBytes(filename); + BitPack input = new BitPack(buffer, 0); + + _header = TrimAt0(input.UnpackString(24)); + if (!String.Equals(_header, MeshHeader)) + return; + + // Populate base mesh variables + _hasWeights = (input.UnpackByte() != 0); + _hasDetailTexCoords = (input.UnpackByte() != 0); + _position = new Vector3(input.UnpackFloat(), input.UnpackFloat(), input.UnpackFloat()); + _rotationAngles = new Vector3(input.UnpackFloat(), input.UnpackFloat(), input.UnpackFloat()); + _rotationOrder = input.UnpackByte(); + _scale = new Vector3(input.UnpackFloat(), input.UnpackFloat(), input.UnpackFloat()); + _numFaces = input.UnpackUShort(); + + _faces = new Face[_numFaces]; + + for (int i = 0; i < _numFaces; i++) + _faces[i].Indices = new short[] { input.UnpackShort(), input.UnpackShort(), input.UnpackShort() }; + } + } + #endregion lod mesh + + public float MinPixelWidth; //!< Width of redered avatar, before moving to a coarser LOD + + public string Name { get; protected set; } //!< The name of this mesh + public string Header { get; protected set; } //!< The header marker contained in the .llm file + public bool HasWeights { get; protected set; } //!< Does the file contain skin weights? + public bool HasDetailTexCoords { get; protected set; } //!< Does the file contain detailed UV mapings + public Vector3 Position { get; protected set; } //!< Origin of this mesh + public Vector3 RotationAngles { get; protected set; } //!< Rotation - This is a compressed quaternion + //public byte RotationOrder + public Vector3 Scale { get; protected set; } //!< Scale of this mesh + public ushort NumVertices { get; protected set; } //!< # of vertices in the file + public Vertex[] Vertices { get; protected set; } //!< The actual vertices defining the 3d shape + public ushort NumFaces { get; protected set; } //!< # of polygons in the file + public Face[] Faces { get; protected set; } //!< The polgon defintion + public ushort NumSkinJoints { get; protected set; } //!< # of joints influencing the mesh + public string[] SkinJoints { get; protected set; } //!< Named list of joints + public int NumRemaps { get; protected set; } //!< # of vertex remaps + public VertexRemap[] VertexRemaps { get; protected set; } //!< The actual vertex remapping list + + // lods can either be Reference meshes or full LindenMeshes + // so we cannot use a collection of specialized classes + public SortedList LodMeshes { get; protected set; } //!< The LOD meshes, available for this mesh + + public Morph[] Morphs; //!< The morphs this file contains + + /// + /// Construct a linden mesh with the given name + /// + /// the name of the mesh + public LindenMesh(string name) + : this(name, null) { } + + /// + /// Construct a linden mesh with the given name + /// + /// the name of the mesh + /// The skeleton governing mesh deformation + public LindenMesh(string name, LindenSkeleton skeleton) + { + Name = name; + Skeleton = skeleton; + LodMeshes = new SortedList(); + + if (Skeleton == null) + Skeleton = LindenSkeleton.Load(); + } + + /// + /// Load the mesh from a stream + /// + /// The filename and path of the file containing the mesh data + public virtual void LoadMesh(string filename) + { + using(FileStream meshData = new FileStream(filename, FileMode.Open, FileAccess.Read)) + using (EndianAwareBinaryReader reader = new EndianAwareBinaryReader(meshData)) + { + Header = TrimAt0(reader.ReadString(24)); + if (!String.Equals(Header, MeshHeader)) + throw new FileLoadException("Unrecognized mesh format"); + + // Populate base mesh parameters + HasWeights = (reader.ReadByte() != 0); + HasDetailTexCoords = (reader.ReadByte() != 0); + Position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + RotationAngles = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + /* RotationOrder = */ reader.ReadByte(); + Scale = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + + // Populate the vertex array + NumVertices = reader.ReadUInt16(); + Vertices = new Vertex[NumVertices]; + for (int i = 0; i < NumVertices; i++) + Vertices[i].Coord = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + + for (int i = 0; i < NumVertices; i++) + Vertices[i].Normal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + + for (int i = 0; i < NumVertices; i++) + Vertices[i].BiNormal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + + for (int i = 0; i < NumVertices; i++) + Vertices[i].TexCoord = new Vector2(reader.ReadSingle(), reader.ReadSingle()); + + if (HasDetailTexCoords) + { + for (int i = 0; i < NumVertices; i++) + Vertices[i].DetailTexCoord = new Vector2(reader.ReadSingle(), reader.ReadSingle()); + } + + if (HasWeights) + { + for (int i = 0; i < NumVertices; i++) + Vertices[i].Weight = reader.ReadSingle(); + } + + NumFaces = reader.ReadUInt16(); + Faces = new Face[NumFaces]; + + for (int i = 0; i < NumFaces; i++) + Faces[i].Indices = new[] { reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16() }; + + if (HasWeights) + { + NumSkinJoints = reader.ReadUInt16(); + SkinJoints = new string[NumSkinJoints]; + + for (int i = 0; i < NumSkinJoints; i++) + { + SkinJoints[i] = TrimAt0(reader.ReadString(64)); + } + } + else + { + NumSkinJoints = 0; + SkinJoints = new string[0]; + } + + // Grab morphs + List morphs = new List(); + string morphName = TrimAt0(reader.ReadString(64)); + + while (morphName != MorphFooter) + { + if (reader.BaseStream.Position + 48 >= reader.BaseStream.Length) + throw new FileLoadException("Encountered end of file while parsing morphs"); + + Morph morph = new Morph(); + morph.Name = morphName; + morph.NumVertices = reader.ReadInt32(); + morph.Vertices = new MorphVertex[morph.NumVertices]; + + for (int i = 0; i < morph.NumVertices; i++) + { + morph.Vertices[i].VertexIndex = reader.ReadUInt32(); + morph.Vertices[i].Coord = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + morph.Vertices[i].Normal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + morph.Vertices[i].BiNormal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + morph.Vertices[i].TexCoord = new Vector2(reader.ReadSingle(), reader.ReadSingle()); + } + + morphs.Add(morph); + + // Grab the next name + morphName = TrimAt0(reader.ReadString(64)); + } + + Morphs = morphs.ToArray(); + + // Check if there are remaps or if we're at the end of the file + if (reader.BaseStream.Position < reader.BaseStream.Length - 1) + { + NumRemaps = reader.ReadInt32(); + VertexRemaps = new VertexRemap[NumRemaps]; + + for (int i = 0; i < NumRemaps; i++) + { + VertexRemaps[i].RemapSource = reader.ReadInt32(); + VertexRemaps[i].RemapDestination = reader.ReadInt32(); + } + } + else + { + NumRemaps = 0; + VertexRemaps = new VertexRemap[0]; + } + } + + // uncompress the skin weights + if (Skeleton != null) + { + // some meshes aren't weighted, which doesn't make much sense. + // we check for left and right eyeballs, and assign them a 100% + // to their respective bone + List expandedJointList = Skeleton.BuildExpandedJointList(SkinJoints); + if (expandedJointList.Count == 0) + { + if (Name == "eyeBallLeftMesh") + { + expandedJointList.AddRange(new[] { "mEyeLeft", "mSkull" }); + } + else if (Name == "eyeBallRightMesh") + { + expandedJointList.AddRange(new[] { "mEyeRight", "mSkull" }); + } + } + + if (expandedJointList.Count > 0) + ExpandCompressedSkinWeights(expandedJointList); + } + } + + #region Skin weight + + /// + /// Layout of one skinweight element + /// + public struct SkinWeightElement + { + public string Bone1; // Name of the first bone that influences the vertex + public string Bone2; // Name of the second bone that influences the vertex + public float Weight1; // Weight with whitch the first bone influences the vertex + public float Weight2; // Weight with whitch the second bone influences the vertex + } + + /// List of skinweights, in the same order as the mesh vertices + public List SkinWeights = new List(); + + /// + /// Decompress the skinweights + /// + /// the expanded joint list, used to index which bones should influece the vertex + void ExpandCompressedSkinWeights(List expandedJointList) + { + for (int i = 0; i < NumVertices; i++) + { + int boneIndex = (int)Math.Floor(Vertices[i].Weight); // Whole number part is the index + float boneWeight = (Vertices[i].Weight - boneIndex); // fractional part it the weight + + if (boneIndex == 0) // Special case for dealing with eye meshes, which doesn't have any weights + { + SkinWeights.Add(new SkinWeightElement { Bone1 = expandedJointList[0], Weight1 = 1, Bone2 = expandedJointList[1], Weight2 = 0 }); + } + else if (boneIndex < expandedJointList.Count) + { + string bone1 = expandedJointList[boneIndex - 1]; + string bone2 = expandedJointList[boneIndex]; + SkinWeights.Add(new SkinWeightElement { Bone1 = bone1, Weight1 = 1 - boneWeight, Bone2 = bone2, Weight2 = boneWeight }); + } + else + { // this should add a weight where the "invalid" Joint has a weight of zero + SkinWeights.Add(new SkinWeightElement + { + Bone1 = expandedJointList[boneIndex - 1], + Weight1 = 1 - boneWeight, + Bone2 = "mPelvis", + Weight2 = boneWeight + }); + } + } + } + #endregion Skin weight + + [Obsolete("Use LoadLodMesh")] + public virtual void LoadLODMesh(int level, string filename) + { + if (filename == "avatar_eye_1.llm") + throw new ArgumentException("Eyballs are not LOD Meshes", "filename"); + + LODMesh lod = new LODMesh(); + lod.LoadMesh(filename); + LodMeshes[level] = lod; + } + + public virtual object LoadLodMesh(int level, string filename) + { + if (filename != "avatar_eye_1.llm") + { + ReferenceMesh refMesh = new ReferenceMesh(); + refMesh.LoadMesh(filename); + LodMeshes[level] = refMesh; + return refMesh; + } + + LindenMesh fullMesh = new LindenMesh(""); + fullMesh.LoadMesh(filename); + LodMeshes[level] = fullMesh; + return fullMesh; + } + + /// + /// Load a reference mesh from a given stream + /// + /// The lod level of this reference mesh + /// the name and path of the file containing the mesh data + /// the loaded reference mesh + public virtual ReferenceMesh LoadReferenceMesh(int lodLevel, string filename) + { + if (filename == "avatar_eye_1.llm") + throw new ArgumentException("Eyballs are not LOD Meshes", "filename"); + + ReferenceMesh reference = new ReferenceMesh(); + reference.LoadMesh(filename); + LodMeshes[lodLevel] = lodLevel; + return reference; + } + + /// + /// Trim a string at the first occurence of NUL + /// + /// + /// The llm file uses null terminated strings (C/C++ style), this is where + /// the conversion is made. + /// + /// The string to trim + /// A standard .Net string + public static string TrimAt0(string s) + { + int pos = s.IndexOf("\0"); + + if (pos >= 0) + return s.Substring(0, pos); + + return s; + } + } +} diff --git a/OpenMetaverse/Rendering/LindenSkeleton.Ext.cs b/OpenMetaverse/Rendering/LindenSkeleton.Ext.cs new file mode 100644 index 0000000..22265a5 --- /dev/null +++ b/OpenMetaverse/Rendering/LindenSkeleton.Ext.cs @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Serialization; + +namespace OpenMetaverse.Rendering +{ + /// + /// load the 'avatar_skeleton.xml' + /// + /// + /// Partial class which extends the auto-generated 'LindenSkeleton.Xsd.cs'.eton.xsd + /// + public partial class LindenSkeleton + { + /// + /// Load a skeleton from a given file. + /// + /// + /// We use xml scema validation on top of the xml de-serializer, since the schema has + /// some stricter checks than the de-serializer provides. E.g. the vector attributes + /// are guaranteed to hold only 3 float values. This reduces the need for error checking + /// while working with the loaded skeleton. + /// + /// A valid recursive skeleton + public static LindenSkeleton Load() + { + return Load(null); + } + + /// + /// Load a skeleton from a given file. + /// + /// + /// We use xml scema validation on top of the xml de-serializer, since the schema has + /// some stricter checks than the de-serializer provides. E.g. the vector attributes + /// are guaranteed to hold only 3 float values. This reduces the need for error checking + /// while working with the loaded skeleton. + /// + /// The path to the skeleton definition file + /// A valid recursive skeleton + public static LindenSkeleton Load(string fileName) + { + if (fileName == null) + fileName = System.IO.Path.Combine(Settings.RESOURCE_DIR, "avatar_skeleton.xml"); + + LindenSkeleton result; + + using (FileStream skeletonData = new FileStream(fileName, FileMode.Open, FileAccess.Read)) + using (XmlReader reader = XmlReader.Create(skeletonData)) + { + XmlSerializer ser = new XmlSerializer(typeof(LindenSkeleton)); + result = (LindenSkeleton)ser.Deserialize(reader); + } + return result; + } + + /// + /// Build and "expanded" list of joints + /// + /// + /// The algorithm is based on this description: + /// + /// >An "expanded" list of joints, not just a + /// >linear array of the joints as defined in the skeleton file. + /// >In particular, any joint that has more than one child will + /// >be repeated in the list for each of its children. + /// + /// The list should only take these joint names in consideration + /// An "expanded" joints list as a flat list of bone names + public List BuildExpandedJointList(IEnumerable jointsFilter) + { + List expandedJointList = new List(); + + // not really sure about this algorithm, but it seems to fit the bill: + // and the mesh doesn't seem to be overly distorted + if(bone.bone != null) + foreach (Joint child in bone.bone) + ExpandJoint(bone, child, expandedJointList, jointsFilter); + + return expandedJointList; + } + + /// + /// Expand one joint + /// + /// The parent of the joint we are operating on + /// The joint we are supposed to expand + /// Joint list that we will extend upon + /// The expanded list should only contain these joints + private void ExpandJoint(Joint parentJoint, Joint currentJoint, List expandedJointList, IEnumerable jointsFilter) + { + // does the mesh reference this joint + if (jointsFilter.Contains(currentJoint.name)) + { + if (expandedJointList.Count > 0 && parentJoint != null && + parentJoint.name == expandedJointList[expandedJointList.Count - 1]) + expandedJointList.Add(currentJoint.name); + else + { + if (parentJoint != null) + expandedJointList.Add(parentJoint.name); + else + expandedJointList.Add(currentJoint.name); // only happens on the root joint + + expandedJointList.Add(currentJoint.name); + } + } + + // recurse the joint hierarchy + if(currentJoint.bone != null) + foreach (Joint child in currentJoint.bone) + ExpandJoint(currentJoint, child, expandedJointList, jointsFilter); + } + } +} diff --git a/OpenMetaverse/Rendering/LindenSkeleton.Xsd.cs b/OpenMetaverse/Rendering/LindenSkeleton.Xsd.cs new file mode 100644 index 0000000..013d338 --- /dev/null +++ b/OpenMetaverse/Rendering/LindenSkeleton.Xsd.cs @@ -0,0 +1,244 @@ +namespace OpenMetaverse.Rendering +{ + //------------------------------------------------------------------------------ + // + // This code was generated by a tool. + // Runtime Version:4.0.30319.18444 + // + // Changes to this file may cause incorrect behavior and will be lost if + // the code is regenerated. + // + //------------------------------------------------------------------------------ + + // + // This source code was auto-generated by xsd, Version=4.0.30319.1. + // + + using System.Xml.Serialization; + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] + [System.SerializableAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [XmlRoot("linden_skeleton", Namespace = "", IsNullable = false)] + public partial class LindenSkeleton + { + + private Joint boneField; + + private float versionField; + + private bool versionFieldSpecified; + + private string num_bonesField; + + private string num_collision_volumesField; + + /// + public Joint bone + { + get + { + return this.boneField; + } + set + { + this.boneField = value; + } + } + + /// + [XmlAttribute()] + public float version + { + get + { + return this.versionField; + } + set + { + this.versionField = value; + } + } + + /// + [XmlIgnore()] + public bool versionSpecified + { + get + { + return this.versionFieldSpecified; + } + set + { + this.versionFieldSpecified = value; + } + } + + /// + [XmlAttribute(DataType = "positiveInteger")] + public string num_bones + { + get + { + return this.num_bonesField; + } + set + { + this.num_bonesField = value; + } + } + + /// + [XmlAttribute(DataType = "positiveInteger")] + public string num_collision_volumes + { + get + { + return this.num_collision_volumesField; + } + set + { + this.num_collision_volumesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] + [System.SerializableAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class Joint : JointBase + { + + private CollisionVolume[] collision_volumeField; + + private Joint[] boneField; + + private float[] pivotField; + + /// + [XmlElement("collision_volume")] + public CollisionVolume[] collision_volume + { + get + { + return this.collision_volumeField; + } + set + { + this.collision_volumeField = value; + } + } + + /// + [XmlElement("bone")] + public Joint[] bone + { + get + { + return this.boneField; + } + set + { + this.boneField = value; + } + } + + /// + [XmlAttribute()] + public float[] pivot + { + get + { + return this.pivotField; + } + set + { + this.pivotField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] + [System.SerializableAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CollisionVolume : JointBase + { + } + + /// + [XmlInclude(typeof(Joint))] + [XmlInclude(typeof(CollisionVolume))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] + [System.SerializableAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class JointBase + { + + private string nameField; + + private float[] posField; + + private float[] rotField; + + private float[] scaleField; + + /// + [XmlAttribute(DataType = "token")] + public string name + { + get + { + return this.nameField; + } + set + { + this.nameField = value; + } + } + + /// + [XmlAttribute()] + public float[] pos + { + get + { + return this.posField; + } + set + { + this.posField = value; + } + } + + /// + [XmlAttribute()] + public float[] rot + { + get + { + return this.rotField; + } + set + { + this.rotField = value; + } + } + + /// + [XmlAttribute()] + public float[] scale + { + get + { + return this.scaleField; + } + set + { + this.scaleField = value; + } + } + } +} diff --git a/OpenMetaverse/Rendering/Rendering.cs b/OpenMetaverse/Rendering/Rendering.cs new file mode 100644 index 0000000..285ca56 --- /dev/null +++ b/OpenMetaverse/Rendering/Rendering.cs @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; + +// The common elements shared between rendering plugins are defined here + +namespace OpenMetaverse.Rendering +{ + #region Enums + + public enum FaceType : ushort + { + PathBegin = 0x1 << 0, + PathEnd = 0x1 << 1, + InnerSide = 0x1 << 2, + ProfileBegin = 0x1 << 3, + ProfileEnd = 0x1 << 4, + OuterSide0 = 0x1 << 5, + OuterSide1 = 0x1 << 6, + OuterSide2 = 0x1 << 7, + OuterSide3 = 0x1 << 8 + } + + [Flags] + public enum FaceMask + { + Single = 0x0001, + Cap = 0x0002, + End = 0x0004, + Side = 0x0008, + Inner = 0x0010, + Outer = 0x0020, + Hollow = 0x0040, + Open = 0x0080, + Flat = 0x0100, + Top = 0x0200, + Bottom = 0x0400 + } + + public enum DetailLevel + { + Low = 0, + Medium = 1, + High = 2, + Highest = 3 + } + + #endregion Enums + + #region Structs + + [StructLayout(LayoutKind.Explicit)] + public struct Vertex : IEquatable + { + [FieldOffset(0)] + public Vector3 Position; + [FieldOffset(12)] + public Vector3 Normal; + [FieldOffset(24)] + public Vector2 TexCoord; + + public override string ToString() + { + return String.Format("P: {0} N: {1} T: {2}", Position, Normal, TexCoord); + } + + public override int GetHashCode() + { + int hash = Position.GetHashCode(); + hash = hash * 31 + Normal.GetHashCode(); + hash = hash * 31 + TexCoord.GetHashCode(); + return hash; + } + + public static bool operator ==(Vertex value1, Vertex value2) + { + return value1.Position == value2.Position + && value1.Normal == value2.Normal + && value1.TexCoord == value2.TexCoord; + } + + public static bool operator !=(Vertex value1, Vertex value2) + { + return !(value1 == value2); + } + + public override bool Equals(object obj) + { + return (obj is Vertex) ? this == (Vertex)obj : false; + } + + public bool Equals(Vertex other) + { + return this == other; + } + } + + public struct ProfileFace + { + public int Index; + public int Count; + public float ScaleU; + public bool Cap; + public bool Flat; + public FaceType Type; + + public override string ToString() + { + return Type.ToString(); + } + }; + + public struct Profile + { + public float MinX; + public float MaxX; + public bool Open; + public bool Concave; + public int TotalOutsidePoints; + public List Positions; + public List Faces; + } + + public struct PathPoint + { + public Vector3 Position; + public Vector2 Scale; + public Quaternion Rotation; + public float TexT; + } + + public struct Path + { + public List Points; + public bool Open; + } + + public struct Face + { + // Only used for Inner/Outer faces + public int BeginS; + public int BeginT; + public int NumS; + public int NumT; + + public int ID; + public Vector3 Center; + public Vector3 MinExtent; + public Vector3 MaxExtent; + public List Vertices; + public List Indices; + public List Edge; + public FaceMask Mask; + public Primitive.TextureEntryFace TextureFace; + public object UserData; + + public override string ToString() + { + return Mask.ToString(); + } + } + + #endregion Structs + + #region Exceptions + + public class RenderingException : Exception + { + public RenderingException(string message) + : base(message) + { + } + + public RenderingException(string message, Exception innerException) + : base(message, innerException) + { + } + } + + #endregion Exceptions + + #region Mesh Classes + + public class Mesh + { + public Primitive Prim; + public Path Path; + public Profile Profile; + + public override string ToString() + { + if (Prim.Properties != null && !String.IsNullOrEmpty(Prim.Properties.Name)) + { + return Prim.Properties.Name; + } + else + { + return String.Format("{0} ({1})", Prim.LocalID, Prim.PrimData); + } + } + } + + /// + /// Contains all mesh faces that belong to a prim + /// + public class FacetedMesh : Mesh + { + /// List of primitive faces + public List Faces; + + /// + /// Decodes mesh asset into FacetedMesh + /// + /// Mesh primitive + /// Asset retrieved from the asset server + /// Level of detail + /// Resulting decoded FacetedMesh + /// True if mesh asset decoding was successful + public static bool TryDecodeFromAsset(Primitive prim, AssetMesh meshAsset, DetailLevel LOD, out FacetedMesh mesh) + { + mesh = null; + + try + { + if (!meshAsset.Decode()) + { + return false; + } + + OSDMap MeshData = meshAsset.MeshData; + + mesh = new FacetedMesh(); + + mesh.Faces = new List(); + mesh.Prim = prim; + mesh.Profile.Faces = new List(); + mesh.Profile.Positions = new List(); + mesh.Path.Points = new List(); + + OSD facesOSD = null; + + switch (LOD) + { + default: + case DetailLevel.Highest: + facesOSD = MeshData["high_lod"]; + break; + + case DetailLevel.High: + facesOSD = MeshData["medium_lod"]; + break; + + case DetailLevel.Medium: + facesOSD = MeshData["low_lod"]; + break; + + case DetailLevel.Low: + facesOSD = MeshData["lowest_lod"]; + break; + } + + if (facesOSD == null || !(facesOSD is OSDArray)) + { + return false; + } + + OSDArray decodedMeshOsdArray = (OSDArray)facesOSD; + + for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++) + { + OSD subMeshOsd = decodedMeshOsdArray[faceNr]; + + // Decode each individual face + if (subMeshOsd is OSDMap) + { + Face oface = new Face(); + oface.ID = faceNr; + oface.Vertices = new List(); + oface.Indices = new List(); + oface.TextureFace = prim.Textures.GetFace((uint)faceNr); + + OSDMap subMeshMap = (OSDMap)subMeshOsd; + + Vector3 posMax; + Vector3 posMin; + + // If PositionDomain is not specified, the default is from -0.5 to 0.5 + if (subMeshMap.ContainsKey("PositionDomain")) + { + posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"]; + posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"]; + } + else + { + posMax = new Vector3(0.5f, 0.5f, 0.5f); + posMin = new Vector3(-0.5f, -0.5f, -0.5f); + } + + // Vertex positions + byte[] posBytes = subMeshMap["Position"]; + + // Normals + byte[] norBytes = null; + if (subMeshMap.ContainsKey("Normal")) + { + norBytes = subMeshMap["Normal"]; + } + + // UV texture map + Vector2 texPosMax = Vector2.Zero; + Vector2 texPosMin = Vector2.Zero; + byte[] texBytes = null; + if (subMeshMap.ContainsKey("TexCoord0")) + { + texBytes = subMeshMap["TexCoord0"]; + texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"]; + texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"]; + } + + // Extract the vertex position data + // If present normals and texture coordinates too + for (int i = 0; i < posBytes.Length; i += 6) + { + ushort uX = Utils.BytesToUInt16(posBytes, i); + ushort uY = Utils.BytesToUInt16(posBytes, i + 2); + ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); + + Vertex vx = new Vertex(); + + vx.Position = new Vector3( + Utils.UInt16ToFloat(uX, posMin.X, posMax.X), + Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y), + Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z)); + + if (norBytes != null && norBytes.Length >= i + 4) + { + ushort nX = Utils.BytesToUInt16(norBytes, i); + ushort nY = Utils.BytesToUInt16(norBytes, i + 2); + ushort nZ = Utils.BytesToUInt16(norBytes, i + 4); + + vx.Normal = new Vector3( + Utils.UInt16ToFloat(nX, posMin.X, posMax.X), + Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y), + Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z)); + } + + var vertexIndexOffset = oface.Vertices.Count * 4; + + if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4) + { + ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset); + ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2); + + vx.TexCoord = new Vector2( + Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X), + Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y)); + } + + oface.Vertices.Add(vx); + } + + byte[] triangleBytes = subMeshMap["TriangleList"]; + for (int i = 0; i < triangleBytes.Length; i += 6) + { + ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i)); + oface.Indices.Add(v1); + ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2)); + oface.Indices.Add(v2); + ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4)); + oface.Indices.Add(v3); + } + + mesh.Faces.Add(oface); + } + } + + } + catch (Exception ex) + { + Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning); + return false; + } + + return true; + } + } + + public class SimpleMesh : Mesh + { + public List Vertices; + public List Indices; + + public SimpleMesh() + { + } + + public SimpleMesh(SimpleMesh mesh) + { + this.Indices = new List(mesh.Indices); + this.Path.Open = mesh.Path.Open; + this.Path.Points = new List(mesh.Path.Points); + this.Prim = mesh.Prim; + this.Profile.Concave = mesh.Profile.Concave; + this.Profile.Faces = new List(mesh.Profile.Faces); + this.Profile.MaxX = mesh.Profile.MaxX; + this.Profile.MinX = mesh.Profile.MinX; + this.Profile.Open = mesh.Profile.Open; + this.Profile.Positions = new List(mesh.Profile.Positions); + this.Profile.TotalOutsidePoints = mesh.Profile.TotalOutsidePoints; + this.Vertices = new List(mesh.Vertices); + } + } + + #endregion Mesh Classes + + #region Plugin Loading + + public static class RenderingLoader + { + public static List ListRenderers(string path) + { + List plugins = new List(); + string[] files = Directory.GetFiles(path, "OpenMetaverse.Rendering.*.dll"); + + foreach (string f in files) + { + try + { + Assembly a = Assembly.LoadFrom(f); + System.Type[] types = a.GetTypes(); + foreach (System.Type type in types) + { + if (type.GetInterface("IRendering") != null) + { + if (type.GetCustomAttributes(typeof(RendererNameAttribute), false).Length == 1) + { + plugins.Add(f); + } + else + { + Logger.Log("Rendering plugin does not support the [RendererName] attribute: " + f, + Helpers.LogLevel.Warning); + } + + break; + } + } + } + catch (Exception e) + { + Logger.Log(String.Format("Unrecognized rendering plugin {0}: {1}", f, e.Message), + Helpers.LogLevel.Warning, e); + } + } + + return plugins; + } + + public static IRendering LoadRenderer(string filename) + { + try + { + Assembly a = Assembly.LoadFrom(filename); + System.Type[] types = a.GetTypes(); + foreach (System.Type type in types) + { + if (type.GetInterface("IRendering") != null) + { + if (type.GetCustomAttributes(typeof(RendererNameAttribute), false).Length == 1) + { + return (IRendering)Activator.CreateInstance(type); + } + else + { + throw new RenderingException( + "Rendering plugin does not support the [RendererName] attribute"); + } + } + } + + throw new RenderingException( + "Rendering plugin does not support the IRendering interface"); + } + catch (Exception e) + { + throw new RenderingException("Failed loading rendering plugin: " + e.Message, e); + } + } + } + + #endregion Plugin Loading +} diff --git a/OpenMetaverse/Settings.cs b/OpenMetaverse/Settings.cs new file mode 100644 index 0000000..12a8603 --- /dev/null +++ b/OpenMetaverse/Settings.cs @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + /// + /// Class for controlling various system settings. + /// + /// Some values are readonly because they affect things that + /// happen when the GridClient object is initialized, so changing them at + /// runtime won't do any good. Non-readonly values may affect things that + /// happen at login or dynamically + public class Settings + { + #region Login/Networking Settings + + /// Main grid login server + public const string AGNI_LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; + + /// Beta grid login server + public const string ADITI_LOGIN_SERVER = "https://login.aditi.lindenlab.com/cgi-bin/login.cgi"; + + /// The relative directory where external resources are kept + public static string RESOURCE_DIR = "openmetaverse_data"; + + /// Login server to connect to + public string LOGIN_SERVER = AGNI_LOGIN_SERVER; + + /// IP Address the client will bind to + public static System.Net.IPAddress BIND_ADDR = System.Net.IPAddress.Any; + + /// Use XML-RPC Login or LLSD Login, default is XML-RPC Login + public bool USE_LLSD_LOGIN = false; + + /// + /// Maximum number of HTTP connections to open to a particular endpoint. + /// + /// + /// An endpoint is defined as a commbination of network address and port. This is used for Caps. + /// This is a static variable which applies to all instances. + /// + public static int MAX_HTTP_CONNECTIONS = 32; + + #endregion + + #region Inventory + + /// + /// InventoryManager requests inventory information on login, + /// GridClient initializes an Inventory store for main inventory. + /// + public const bool ENABLE_INVENTORY_STORE = true; + /// + /// InventoryManager requests library information on login, + /// GridClient initializes an Inventory store for the library. + /// + public const bool ENABLE_LIBRARY_STORE = true; + /// + /// Use Caps for fetching inventory where available + /// + public bool HTTP_INVENTORY = true; + + #endregion + + #region Timeouts and Intervals + + /// Number of milliseconds before an asset transfer will time + /// out + public int TRANSFER_TIMEOUT = 90 * 1000; + + /// Number of milliseconds before a teleport attempt will time + /// out + public int TELEPORT_TIMEOUT = 40 * 1000; + + /// Number of milliseconds before NetworkManager.Logout() will + /// time out + public int LOGOUT_TIMEOUT = 5 * 1000; + + /// Number of milliseconds before a CAPS call will time out + /// Setting this too low will cause web requests time out and + /// possibly retry repeatedly + public int CAPS_TIMEOUT = 60 * 1000; + + /// Number of milliseconds for xml-rpc to timeout + public int LOGIN_TIMEOUT = 60 * 1000; + + /// Milliseconds before a packet is assumed lost and resent + public int RESEND_TIMEOUT = 4000; + + /// Milliseconds without receiving a packet before the + /// connection to a simulator is assumed lost + public int SIMULATOR_TIMEOUT = 30 * 1000; + + /// Milliseconds to wait for a simulator info request through + /// the grid interface + public int MAP_REQUEST_TIMEOUT = 5 * 1000; + + /// Number of milliseconds between sending pings to each sim + public const int PING_INTERVAL = 2200; + + /// Number of milliseconds between sending camera updates + public const int DEFAULT_AGENT_UPDATE_INTERVAL = 500; + + /// Number of milliseconds between updating the current + /// positions of moving, non-accelerating and non-colliding objects + public const int INTERPOLATION_INTERVAL = 250; + + /// Millisecond interval between ticks, where all ACKs are + /// sent out and the age of unACKed packets is checked + public const int NETWORK_TICK_INTERVAL = 500; + + #endregion + #region Sizes + + /// The initial size of the packet inbox, where packets are + /// stored before processing + public const int PACKET_INBOX_SIZE = 100; + /// Maximum size of packet that we want to send over the wire + public const int MAX_PACKET_SIZE = 1200; + /// The maximum value of a packet sequence number before it + /// rolls over back to one + public const int MAX_SEQUENCE = 0xFFFFFF; + /// The maximum size of the sequence number archive, used to + /// check for resent and/or duplicate packets + public static int PACKET_ARCHIVE_SIZE = 1000; + /// Maximum number of queued ACKs to be sent before SendAcks() + /// is forced + public int MAX_PENDING_ACKS = 10; + /// Network stats queue length (seconds) + public int STATS_QUEUE_SIZE = 5; + + #endregion + + #region Experimental options + + /// + /// Primitives will be reused when falling in/out of interest list (and shared between clients) + /// prims returning to interest list do not need re-requested + /// Helps also in not re-requesting prim.Properties for code that checks for a Properties == null per client + /// + public bool CACHE_PRIMITIVES = false; + /// + /// Pool parcel data between clients (saves on requesting multiple times when all clients may need it) + /// + public bool POOL_PARCEL_DATA = false; + /// + /// How long to preserve cached data when no client is connected to a simulator + /// The reason for setting it to something like 2 minutes is in case a client + /// is running back and forth between region edges or a sim is comming and going + /// + public static int SIMULATOR_POOL_TIMEOUT = 2 * 60 * 1000; + + #endregion + + #region Configuration options (mostly booleans) + + /// Enable/disable storing terrain heightmaps in the + /// TerrainManager + public bool STORE_LAND_PATCHES = false; + + /// Enable/disable sending periodic camera updates + public bool SEND_AGENT_UPDATES = true; + + /// Enable/disable automatically setting agent appearance at + /// login and after sim crossing + public bool SEND_AGENT_APPEARANCE = true; + + /// Enable/disable automatically setting the bandwidth throttle + /// after connecting to each simulator + /// The default throttle uses the equivalent of the maximum + /// bandwidth setting in the official client. If you do not set a + /// throttle your connection will by default be throttled well below + /// the minimum values and you may experience connection problems + public bool SEND_AGENT_THROTTLE = true; + + /// Enable/disable the sending of pings to monitor lag and + /// packet loss + public bool SEND_PINGS = true; + + /// Should we connect to multiple sims? This will allow + /// viewing in to neighboring simulators and sim crossings + /// (Experimental) + public bool MULTIPLE_SIMS = true; + + /// If true, all object update packets will be decoded in to + /// native objects. If false, only updates for our own agent will be + /// decoded. Registering an event handler will force objects for that + /// type to always be decoded. If this is disabled the object tracking + /// will have missing or partial prim and avatar information + public bool ALWAYS_DECODE_OBJECTS = true; + + /// If true, when a cached object check is received from the + /// server the full object info will automatically be requested + public bool ALWAYS_REQUEST_OBJECTS = true; + + /// Whether to establish connections to HTTP capabilities + /// servers for simulators + public bool ENABLE_CAPS = true; + + /// Whether to decode sim stats + public bool ENABLE_SIMSTATS = true; + + /// The capabilities servers are currently designed to + /// periodically return a 502 error which signals for the client to + /// re-establish a connection. Set this to true to log those 502 errors + public bool LOG_ALL_CAPS_ERRORS = false; + + /// If true, any reference received for a folder or item + /// the library is not aware of will automatically be fetched + public bool FETCH_MISSING_INVENTORY = true; + + /// If true, and SEND_AGENT_UPDATES is true, + /// AgentUpdate packets will continuously be sent out to give the bot + /// smoother movement and autopiloting + public bool DISABLE_AGENT_UPDATE_DUPLICATE_CHECK = true; + + /// If true, currently visible avatars will be stored + /// in dictionaries inside Simulator.ObjectAvatars. + /// If false, a new Avatar or Primitive object will be created + /// each time an object update packet is received + public bool AVATAR_TRACKING = true; + + /// If true, currently visible avatars will be stored + /// in dictionaries inside Simulator.ObjectPrimitives. + /// If false, a new Avatar or Primitive object will be created + /// each time an object update packet is received + public bool OBJECT_TRACKING = true; + + /// If true, position and velocity will periodically be + /// interpolated (extrapolated, technically) for objects and + /// avatars that are being tracked by the library. This is + /// necessary to increase the accuracy of speed and position + /// estimates for simulated objects + public bool USE_INTERPOLATION_TIMER = true; + + /// + /// If true, utilization statistics will be tracked. There is a minor penalty + /// in CPU time for enabling this option. + /// + public bool TRACK_UTILIZATION = false; + #endregion + #region Parcel Tracking + + /// If true, parcel details will be stored in the + /// Simulator.Parcels dictionary as they are received + public bool PARCEL_TRACKING = true; + + /// + /// If true, an incoming parcel properties reply will automatically send + /// a request for the parcel access list + /// + public bool ALWAYS_REQUEST_PARCEL_ACL = true; + + /// + /// if true, an incoming parcel properties reply will automatically send + /// a request for the traffic count. + /// + public bool ALWAYS_REQUEST_PARCEL_DWELL = true; + + #endregion + #region Asset Cache + + /// + /// If true, images, and other assets downloaded from the server + /// will be cached in a local directory + /// + public bool USE_ASSET_CACHE = true; + + /// Path to store cached texture data + public string ASSET_CACHE_DIR = RESOURCE_DIR + "/cache"; + + /// Maximum size cached files are allowed to take on disk (bytes) + public long ASSET_CACHE_MAX_SIZE = 1024 * 1024 * 1024; // 1GB + + #endregion + #region Misc + + /// Default color used for viewer particle effects + public Color4 DEFAULT_EFFECT_COLOR = new Color4(255, 0, 0, 255); + + /// Cost of uploading an asset + /// Read-only since this value is dynamically fetched at login + public int UPLOAD_COST { get { return priceUpload; } } + + /// Maximum number of times to resend a failed packet + public int MAX_RESEND_COUNT = 3; + + /// Throttle outgoing packet rate + public bool THROTTLE_OUTGOING_PACKETS = true; + + /// UUID of a texture used by some viewers to indentify type of client used + public UUID CLIENT_IDENTIFICATION_TAG = UUID.Zero; + + #endregion + #region Texture Pipeline + + /// + /// Download textures using GetTexture capability when available + /// + public bool USE_HTTP_TEXTURES = true; + + /// The maximum number of concurrent texture downloads allowed + /// Increasing this number will not necessarily increase texture retrieval times due to + /// simulator throttles + public int MAX_CONCURRENT_TEXTURE_DOWNLOADS = 4; + + /// + /// The Refresh timer inteval is used to set the delay between checks for stalled texture downloads + /// + /// This is a static variable which applies to all instances + public static float PIPELINE_REFRESH_INTERVAL = 500.0f; + + /// + /// Textures taking longer than this value will be flagged as timed out and removed from the pipeline + /// + public int PIPELINE_REQUEST_TIMEOUT = 45*1000; + #endregion + + #region Logging Configuration + + /// + /// Get or set the minimum log level to output to the console by default + /// + /// If the library is not compiled with DEBUG defined and this level is set to DEBUG + /// You will get no output on the console. This behavior can be overriden by creating + /// a logger configuration file for log4net + /// + public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.Debug; + + /// Attach avatar names to log messages + public bool LOG_NAMES = true; + + /// Log packet retransmission info + public bool LOG_RESENDS = true; + + /// Log disk cache misses and other info + public bool LOG_DISKCACHE = true; + + #endregion + #region Private Fields + + private GridClient Client; + private int priceUpload = 0; + public static bool SORT_INVENTORY = false; + + /// Constructor + /// Reference to a GridClient object + public Settings(GridClient client) + { + Client = client; + Client.Network.RegisterCallback(Packets.PacketType.EconomyData, EconomyDataHandler); + } + + #endregion + #region Packet Callbacks + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void EconomyDataHandler(object sender, PacketReceivedEventArgs e) + { + EconomyDataPacket econ = (EconomyDataPacket)e.Packet; + + priceUpload = econ.Info.PriceUpload; + } + + #endregion + } +} diff --git a/OpenMetaverse/Simulator.cs b/OpenMetaverse/Simulator.cs new file mode 100644 index 0000000..0010afe --- /dev/null +++ b/OpenMetaverse/Simulator.cs @@ -0,0 +1,1485 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Net; +using System.Net.Sockets; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + #region Enums + + /// + /// Simulator (region) properties + /// + [Flags] + public enum RegionFlags : ulong + { + /// No flags set + None = 0, + /// Agents can take damage and be killed + AllowDamage = 1 << 0, + /// Landmarks can be created here + AllowLandmark = 1 << 1, + /// Home position can be set in this sim + AllowSetHome = 1 << 2, + /// Home position is reset when an agent teleports away + ResetHomeOnTeleport = 1 << 3, + /// Sun does not move + SunFixed = 1 << 4, + /// No object, land, etc. taxes + TaxFree = 1 << 5, + /// Disable heightmap alterations (agents can still plant + /// foliage) + BlockTerraform = 1 << 6, + /// Land cannot be released, sold, or purchased + BlockLandResell = 1 << 7, + /// All content is wiped nightly + Sandbox = 1 << 8, + /// Unknown: Related to the availability of an overview world map tile.(Think mainland images when zoomed out.) + NullLayer = 1 << 9, + /// Unknown: Related to region debug flags. Possibly to skip processing of agent interaction with world. + SkipAgentAction = 1 << 10, + /// Region does not update agent prim interest lists. Internal debugging option. + SkipUpdateInterestList = 1 << 11, + /// No collision detection for non-agent objects + SkipCollisions = 1 << 12, + /// No scripts are ran + SkipScripts = 1 << 13, + /// All physics processing is turned off + SkipPhysics = 1 << 14, + /// Region can be seen from other regions on world map. (Legacy world map option?) + ExternallyVisible = 1 << 15, + /// Region can be seen from mainland on world map. (Legacy world map option?) + MainlandVisible = 1 << 16, + /// Agents not explicitly on the access list can visit the region. + PublicAllowed = 1 << 17, + /// Traffic calculations are not run across entire region, overrides parcel settings. + BlockDwell = 1 << 18, + /// Flight is disabled (not currently enforced by the sim) + NoFly = 1 << 19, + /// Allow direct (p2p) teleporting + AllowDirectTeleport = 1 << 20, + /// Estate owner has temporarily disabled scripting + EstateSkipScripts = 1 << 21, + /// Restricts the usage of the LSL llPushObject function, applies to whole region. + RestrictPushObject = 1 << 22, + /// Deny agents with no payment info on file + DenyAnonymous = 1 << 23, + /// Deny agents with payment info on file + DenyIdentified = 1 << 24, + /// Deny agents who have made a monetary transaction + DenyTransacted = 1 << 25, + /// Parcels within the region may be joined or divided by anyone, not just estate owners/managers. + AllowParcelChanges = 1 << 26, + /// Abuse reports sent from within this region are sent to the estate owner defined email. + AbuseEmailToEstateOwner = 1 << 27, + /// Region is Voice Enabled + AllowVoice = 1 << 28, + /// Removes the ability from parcel owners to set their parcels to show in search. + BlockParcelSearch = 1 << 29, + /// Deny agents who have not been age verified from entering the region. + DenyAgeUnverified = 1 << 30 + + } + + /// + /// Region protocol flags + /// + [Flags] + public enum RegionProtocols : ulong + { + /// Nothing special + None = 0, + /// Region supports Server side Appearance + AgentAppearanceService = 1 << 0, + /// Viewer supports Server side Appearance + SelfAppearanceSupport = 1 << 2 + } + + /// + /// Access level for a simulator + /// + public enum SimAccess : byte + { + /// Unknown or invalid access level + Unknown = 0, + /// Trial accounts allowed + Trial = 7, + /// PG rating + PG = 13, + /// Mature rating + Mature = 21, + /// Adult rating + Adult = 42, + /// Simulator is offline + Down = 254, + /// Simulator does not exist + NonExistent = 255 + } + + #endregion Enums + + /// + /// + /// + public class Simulator : UDPBase, IDisposable + { + #region Structs + /// + /// Simulator Statistics + /// + public struct SimStats + { + /// Total number of packets sent by this simulator to this agent + public long SentPackets; + /// Total number of packets received by this simulator to this agent + public long RecvPackets; + /// Total number of bytes sent by this simulator to this agent + public long SentBytes; + /// Total number of bytes received by this simulator to this agent + public long RecvBytes; + /// Time in seconds agent has been connected to simulator + public int ConnectTime; + /// Total number of packets that have been resent + public int ResentPackets; + /// Total number of resent packets recieved + public int ReceivedResends; + /// Total number of pings sent to this simulator by this agent + public int SentPings; + /// Total number of ping replies sent to this agent by this simulator + public int ReceivedPongs; + /// + /// Incoming bytes per second + /// + /// It would be nice to have this claculated on the fly, but + /// this is far, far easier + public int IncomingBPS; + /// + /// Outgoing bytes per second + /// + /// It would be nice to have this claculated on the fly, but + /// this is far, far easier + public int OutgoingBPS; + /// Time last ping was sent + public int LastPingSent; + /// ID of last Ping sent + public byte LastPingID; + /// + public int LastLag; + /// + public int MissedPings; + /// Current time dilation of this simulator + public float Dilation; + /// Current Frames per second of simulator + public int FPS; + /// Current Physics frames per second of simulator + public float PhysicsFPS; + /// + public float AgentUpdates; + /// + public float FrameTime; + /// + public float NetTime; + /// + public float PhysicsTime; + /// + public float ImageTime; + /// + public float ScriptTime; + /// + public float AgentTime; + /// + public float OtherTime; + /// Total number of objects Simulator is simulating + public int Objects; + /// Total number of Active (Scripted) objects running + public int ScriptedObjects; + /// Number of agents currently in this simulator + public int Agents; + /// Number of agents in neighbor simulators + public int ChildAgents; + /// Number of Active scripts running in this simulator + public int ActiveScripts; + /// + public int LSLIPS; + /// + public int INPPS; + /// + public int OUTPPS; + /// Number of downloads pending + public int PendingDownloads; + /// Number of uploads pending + public int PendingUploads; + /// + public int VirtualSize; + /// + public int ResidentSize; + /// Number of local uploads pending + public int PendingLocalUploads; + /// Unacknowledged bytes in queue + public int UnackedBytes; + } + + #endregion Structs + + #region Public Members + /// A public reference to the client that this Simulator object + /// is attached to + public GridClient Client; + /// A Unique Cache identifier for this simulator + public UUID ID = UUID.Zero; + /// The capabilities for this simulator + public Caps Caps = null; + /// + public ulong Handle; + /// The current version of software this simulator is running + public string SimVersion = String.Empty; + /// + public string Name = String.Empty; + /// A 64x64 grid of parcel coloring values. The values stored + /// in this array are of the type + public byte[] ParcelOverlay = new byte[4096]; + /// + public int ParcelOverlaysReceived; + /// + public float TerrainHeightRange00; + /// + public float TerrainHeightRange01; + /// + public float TerrainHeightRange10; + /// + public float TerrainHeightRange11; + /// + public float TerrainStartHeight00; + /// + public float TerrainStartHeight01; + /// + public float TerrainStartHeight10; + /// + public float TerrainStartHeight11; + /// + public float WaterHeight; + /// + public UUID SimOwner = UUID.Zero; + /// + public UUID TerrainBase0 = UUID.Zero; + /// + public UUID TerrainBase1 = UUID.Zero; + /// + public UUID TerrainBase2 = UUID.Zero; + /// + public UUID TerrainBase3 = UUID.Zero; + /// + public UUID TerrainDetail0 = UUID.Zero; + /// + public UUID TerrainDetail1 = UUID.Zero; + /// + public UUID TerrainDetail2 = UUID.Zero; + /// + public UUID TerrainDetail3 = UUID.Zero; + /// true if your agent has Estate Manager rights on this region + public bool IsEstateManager; + /// + public RegionFlags Flags; + /// + public SimAccess Access; + /// + public float BillableFactor; + /// Statistics information for this simulator and the + /// connection to the simulator, calculated by the simulator itself + /// and the library + public SimStats Stats; + /// The regions Unique ID + public UUID RegionID = UUID.Zero; + /// The physical data center the simulator is located + /// Known values are: + /// + /// Dallas + /// Chandler + /// SF + /// + /// + public string ColoLocation; + /// The CPU Class of the simulator + /// Most full mainland/estate sims appear to be 5, + /// Homesteads and Openspace appear to be 501 + public int CPUClass; + /// The number of regions sharing the same CPU as this one + /// "Full Sims" appear to be 1, Homesteads appear to be 4 + public int CPURatio; + /// The billing product name + /// Known values are: + /// + /// Mainland / Full Region (Sku: 023) + /// Estate / Full Region (Sku: 024) + /// Estate / Openspace (Sku: 027) + /// Estate / Homestead (Sku: 029) + /// Mainland / Homestead (Sku: 129) (Linden Owned) + /// Mainland / Linden Homes (Sku: 131) + /// + /// + public string ProductName; + /// The billing product SKU + /// Known values are: + /// + /// 023 Mainland / Full Region + /// 024 Estate / Full Region + /// 027 Estate / Openspace + /// 029 Estate / Homestead + /// 129 Mainland / Homestead (Linden Owned) + /// 131 Linden Homes / Full Region + /// + /// + public string ProductSku; + + /// + /// Flags indicating which protocols this region supports + /// + public RegionProtocols Protocols; + + + /// The current sequence number for packets sent to this + /// simulator. Must be Interlocked before modifying. Only + /// useful for applications manipulating sequence numbers + public int Sequence; + + /// + /// A thread-safe dictionary containing avatars in a simulator + /// + public InternalDictionary ObjectsAvatars = new InternalDictionary(); + + /// + /// A thread-safe dictionary containing primitives in a simulator + /// + public InternalDictionary ObjectsPrimitives = new InternalDictionary(); + + public readonly TerrainPatch[] Terrain; + + public readonly Vector2[] WindSpeeds; + + /// + /// Provides access to an internal thread-safe dictionary containing parcel + /// information found in this simulator + /// + public InternalDictionary Parcels + { + get + { + if (Client.Settings.POOL_PARCEL_DATA) + { + return DataPool.Parcels; + } + if (_Parcels == null) _Parcels = new InternalDictionary(); + return _Parcels; + } + } + private InternalDictionary _Parcels; + + /// + /// Provides access to an internal thread-safe multidimensional array containing a x,y grid mapped + /// to each 64x64 parcel's LocalID. + /// + public int[,] ParcelMap + { + get + { + lock (this) + { + if (Client.Settings.POOL_PARCEL_DATA) + { + return DataPool.ParcelMap; + } + if (_ParcelMap == null) _ParcelMap = new int[64, 64]; + return _ParcelMap; + } + } + } + + /// + /// Checks simulator parcel map to make sure it has downloaded all data successfully + /// + /// true if map is full (contains no 0's) + public bool IsParcelMapFull() + { + for (int y = 0; y < 64; y++) + { + for (int x = 0; x < 64; x++) + { + if (this.ParcelMap[y, x] == 0) + return false; + } + } + return true; + } + + /// + /// Is it safe to send agent updates to this sim + /// AgentMovementComplete message received + /// + public bool AgentMovementComplete; + + #endregion Public Members + + #region Properties + + /// The IP address and port of the server + public IPEndPoint IPEndPoint { get { return remoteEndPoint; } } + /// Whether there is a working connection to the simulator or + /// not + public bool Connected { get { return connected; } } + /// Coarse locations of avatars in this simulator + public InternalDictionary AvatarPositions { get { return avatarPositions; } } + /// AvatarPositions key representing TrackAgent target + public UUID PreyID { get { return preyID; } } + /// Indicates if UDP connection to the sim is fully established + public bool HandshakeComplete { get { return handshakeComplete; } } + + #endregion Properties + + #region Internal/Private Members + /// Used internally to track sim disconnections + internal bool DisconnectCandidate = false; + /// Event that is triggered when the simulator successfully + /// establishes a connection + internal ManualResetEvent ConnectedEvent = new ManualResetEvent(false); + /// Whether this sim is currently connected or not. Hooked up + /// to the property Connected + internal bool connected; + /// Coarse locations of avatars in this simulator + internal InternalDictionary avatarPositions = new InternalDictionary(); + /// AvatarPositions key representing TrackAgent target + internal UUID preyID = UUID.Zero; + /// Sequence numbers of packets we've received + /// (for duplicate checking) + internal IncomingPacketIDCollection PacketArchive; + /// Packets we sent out that need ACKs from the simulator + internal SortedDictionary NeedAck = new SortedDictionary(); + /// Sequence number for pause/resume + internal int pauseSerial; + /// Indicates if UDP connection to the sim is fully established + internal bool handshakeComplete; + + private NetworkManager Network; + private Queue InBytes, OutBytes; + // ACKs that are queued up to be sent to the simulator + private LocklessQueue PendingAcks = new LocklessQueue(); + private Timer AckTimer; + private Timer PingTimer; + private Timer StatsTimer; + // simulator <> parcel LocalID Map + private int[,] _ParcelMap; + public readonly SimulatorDataPool DataPool; + internal bool DownloadingParcelMap + { + get + { + return Client.Settings.POOL_PARCEL_DATA ? DataPool.DownloadingParcelMap : _DownloadingParcelMap; + } + set + { + if (Client.Settings.POOL_PARCEL_DATA) DataPool.DownloadingParcelMap = value; + _DownloadingParcelMap = value; + } + } + + internal bool _DownloadingParcelMap = false; + + + private ManualResetEvent GotUseCircuitCodeAck = new ManualResetEvent(false); + #endregion Internal/Private Members + + /// + /// + /// + /// Reference to the GridClient object + /// IPEndPoint of the simulator + /// handle of the simulator + public Simulator(GridClient client, IPEndPoint address, ulong handle) + : base(address) + { + Client = client; + if (Client.Settings.POOL_PARCEL_DATA || Client.Settings.CACHE_PRIMITIVES) + { + SimulatorDataPool.SimulatorAdd(this); + DataPool = SimulatorDataPool.GetSimulatorData(Handle); + } + + Handle = handle; + Network = Client.Network; + PacketArchive = new IncomingPacketIDCollection(Settings.PACKET_ARCHIVE_SIZE); + InBytes = new Queue(Client.Settings.STATS_QUEUE_SIZE); + OutBytes = new Queue(Client.Settings.STATS_QUEUE_SIZE); + + if (client.Settings.STORE_LAND_PATCHES) + { + Terrain = new TerrainPatch[16 * 16]; + WindSpeeds = new Vector2[16 * 16]; + } + } + + /// + /// Called when this Simulator object is being destroyed + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public virtual void Dispose(bool disposing) + { + if (disposing) + { + if (AckTimer != null) + AckTimer.Dispose(); + if (PingTimer != null) + PingTimer.Dispose(); + if (StatsTimer != null) + StatsTimer.Dispose(); + if (ConnectedEvent != null) + ConnectedEvent.Close(); + + // Force all the CAPS connections closed for this simulator + if (Caps != null) + Caps.Disconnect(true); + } + } + + /// + /// Attempt to connect to this simulator + /// + /// Whether to move our agent in to this sim or not + /// True if the connection succeeded or connection status is + /// unknown, false if there was a failure + public bool Connect(bool moveToSim) + { + handshakeComplete = false; + + if (connected) + { + UseCircuitCode(true); + if (moveToSim) Client.Self.CompleteAgentMovement(this); + return true; + } + + #region Start Timers + + // Timer for sending out queued packet acknowledgements + if (AckTimer == null) + AckTimer = new Timer(AckTimer_Elapsed, null, Settings.NETWORK_TICK_INTERVAL, Timeout.Infinite); + + // Timer for recording simulator connection statistics + if (StatsTimer == null) + StatsTimer = new Timer(StatsTimer_Elapsed, null, 1000, 1000); + + // Timer for periodically pinging the simulator + if (PingTimer == null && Client.Settings.SEND_PINGS) + PingTimer = new Timer(PingTimer_Elapsed, null, Settings.PING_INTERVAL, Settings.PING_INTERVAL); + + #endregion Start Timers + + Logger.Log("Connecting to " + this.ToString(), Helpers.LogLevel.Info, Client); + + try + { + // Create the UDP connection + Start(); + + // Mark ourselves as connected before firing everything else up + connected = true; + + // Initiate connection + UseCircuitCode(true); + + Stats.ConnectTime = Environment.TickCount; + + // Move our agent in to the sim to complete the connection + if (moveToSim) Client.Self.CompleteAgentMovement(this); + + if (!ConnectedEvent.WaitOne(Client.Settings.LOGIN_TIMEOUT, false)) + { + Logger.Log("Giving up on waiting for RegionHandshake for " + this.ToString(), + Helpers.LogLevel.Warning, Client); + //Remove the simulator from the list, not useful if we haven't recieved the RegionHandshake + lock (Client.Network.Simulators) { + Client.Network.Simulators.Remove(this); + } + } + + if (Client.Settings.SEND_AGENT_THROTTLE) + Client.Throttle.Set(this); + + if (Client.Settings.SEND_AGENT_UPDATES) + Client.Self.Movement.SendUpdate(true, this); + + return true; + } + catch (Exception e) + { + Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); + } + + return false; + } + + /// + /// Initiates connection to the simulator + /// + /// Should we block until ack for this packet is recieved + public void UseCircuitCode(bool waitForAck) + { + // Send the UseCircuitCode packet to initiate the connection + UseCircuitCodePacket use = new UseCircuitCodePacket(); + use.CircuitCode.Code = Network.CircuitCode; + use.CircuitCode.ID = Client.Self.AgentID; + use.CircuitCode.SessionID = Client.Self.SessionID; + + if (waitForAck) + { + GotUseCircuitCodeAck.Reset(); + } + + // Send the initial packet out + SendPacket(use); + + if (waitForAck) + { + if (!GotUseCircuitCodeAck.WaitOne(Client.Settings.LOGIN_TIMEOUT, false)) + { + Logger.Log("Failed to get ACK for UseCircuitCode packet", Helpers.LogLevel.Error, Client); + } + } + } + + public void SetSeedCaps(string seedcaps) + { + if (Caps != null) + { + if (Caps._SeedCapsURI == seedcaps) return; + + Logger.Log("Unexpected change of seed capability", Helpers.LogLevel.Warning, Client); + Caps.Disconnect(true); + Caps = null; + } + + if (Client.Settings.ENABLE_CAPS) + { + // Connect to the new CAPS system + if (!String.IsNullOrEmpty(seedcaps)) + Caps = new Caps(this, seedcaps); + else + Logger.Log("Setting up a sim without a valid capabilities server!", Helpers.LogLevel.Error, Client); + } + + } + + /// + /// Disconnect from this simulator + /// + public void Disconnect(bool sendCloseCircuit) + { + if (connected) + { + connected = false; + + // Destroy the timers + if (AckTimer != null) AckTimer.Dispose(); + if (StatsTimer != null) StatsTimer.Dispose(); + if (PingTimer != null) PingTimer.Dispose(); + + AckTimer = null; + StatsTimer = null; + PingTimer = null; + + // Kill the current CAPS system + if (Caps != null) + { + Caps.Disconnect(true); + Caps = null; + } + + if (sendCloseCircuit) + { + // Try to send the CloseCircuit notice + CloseCircuitPacket close = new CloseCircuitPacket(); + UDPPacketBuffer buf = new UDPPacketBuffer(remoteEndPoint); + byte[] data = close.ToBytes(); + Buffer.BlockCopy(data, 0, buf.Data, 0, data.Length); + buf.DataLength = data.Length; + + AsyncBeginSend(buf); + } + + if (Client.Settings.POOL_PARCEL_DATA || Client.Settings.CACHE_PRIMITIVES) + { + SimulatorDataPool.SimulatorRelease(this); + } + + // Shut the socket communication down + Stop(); + } + } + + /// + /// Instructs the simulator to stop sending update (and possibly other) packets + /// + public void Pause() + { + AgentPausePacket pause = new AgentPausePacket(); + pause.AgentData.AgentID = Client.Self.AgentID; + pause.AgentData.SessionID = Client.Self.SessionID; + pause.AgentData.SerialNum = (uint)Interlocked.Exchange(ref pauseSerial, pauseSerial + 1); + + Client.Network.SendPacket(pause, this); + } + + /// + /// Instructs the simulator to resume sending update packets (unpause) + /// + public void Resume() + { + AgentResumePacket resume = new AgentResumePacket(); + resume.AgentData.AgentID = Client.Self.AgentID; + resume.AgentData.SessionID = Client.Self.SessionID; + resume.AgentData.SerialNum = (uint)Interlocked.Exchange(ref pauseSerial, pauseSerial + 1); + + Client.Network.SendPacket(resume, this); + } + + /// + /// Retrieve the terrain height at a given coordinate + /// + /// Sim X coordinate, valid range is from 0 to 255 + /// Sim Y coordinate, valid range is from 0 to 255 + /// The terrain height at the given point if the + /// lookup was successful, otherwise 0.0f + /// True if the lookup was successful, otherwise false + public bool TerrainHeightAtPoint(int x, int y, out float height) + { + if (Terrain != null && x >= 0 && x < 256 && y >= 0 && y < 256) + { + int patchX = x / 16; + int patchY = y / 16; + x = x % 16; + y = y % 16; + + TerrainPatch patch = Terrain[patchY * 16 + patchX]; + if (patch != null) + { + height = patch.Data[y * 16 + x]; + return true; + } + } + + height = 0.0f; + return false; + } + + #region Packet Sending + + /// + /// Sends a packet + /// + /// Packet to be sent + public void SendPacket(Packet packet) + { + // DEBUG: This can go away after we are sure nothing in the library is trying to do this + if (packet.Header.AppendedAcks || (packet.Header.AckList != null && packet.Header.AckList.Length > 0)) + Logger.Log("Attempting to send packet " + packet.Type + " with ACKs appended before serialization", Helpers.LogLevel.Error); + + if (packet.HasVariableBlocks) + { + byte[][] datas; + try { datas = packet.ToBytesMultiple(); } + catch (NullReferenceException) + { + Logger.Log("Failed to serialize " + packet.Type + " packet to one or more payloads due to a missing block or field. StackTrace: " + + Environment.StackTrace, Helpers.LogLevel.Error); + return; + } + int packetCount = datas.Length; + + if (packetCount > 1) + Logger.DebugLog("Split " + packet.Type + " packet into " + packetCount + " packets"); + + for (int i = 0; i < packetCount; i++) + { + byte[] data = datas[i]; + SendPacketData(data, data.Length, packet.Type, packet.Header.Zerocoded); + } + } + else + { + byte[] data = packet.ToBytes(); + SendPacketData(data, data.Length, packet.Type, packet.Header.Zerocoded); + } + } + + public void SendPacketData(byte[] data, int dataLength, PacketType type, bool doZerocode) + { + UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndPoint, Packet.MTU); + + // Zerocode if needed + if (doZerocode) + { + try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); } + catch (IndexOutOfRangeException) + { + // The packet grew larger than Packet.MTU bytes while zerocoding. + // Remove the MSG_ZEROCODED flag and send the unencoded data + // instead + data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); + Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); + } + } + else + { + Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); + } + buffer.DataLength = dataLength; + + #region Queue or Send + + NetworkManager.OutgoingPacket outgoingPacket = new NetworkManager.OutgoingPacket(this, buffer, type); + + // Send ACK and logout packets directly, everything else goes through the queue + if (Client.Settings.THROTTLE_OUTGOING_PACKETS == false || + type == PacketType.PacketAck || + type == PacketType.LogoutRequest) + { + SendPacketFinal(outgoingPacket); + } + else + { + Network.PacketOutbox.Enqueue(outgoingPacket); + } + + #endregion Queue or Send + + #region Stats Tracking + if (Client.Settings.TRACK_UTILIZATION) + { + Client.Stats.Update(type.ToString(), OpenMetaverse.Stats.Type.Packet, dataLength, 0); + } + #endregion + } + + internal void SendPacketFinal(NetworkManager.OutgoingPacket outgoingPacket) + { + UDPPacketBuffer buffer = outgoingPacket.Buffer; + byte flags = buffer.Data[0]; + bool isResend = (flags & Helpers.MSG_RESENT) != 0; + bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; + + // Keep track of when this packet was sent out (right now) + outgoingPacket.TickCount = Environment.TickCount; + + #region ACK Appending + + int dataLength = buffer.DataLength; + + // Keep appending ACKs until there is no room left in the packet or there are + // no more ACKs to append + uint ackCount = 0; + uint ack; + while (dataLength + 5 < Packet.MTU && PendingAcks.TryDequeue(out ack)) + { + Utils.UIntToBytesBig(ack, buffer.Data, dataLength); + dataLength += 4; + ++ackCount; + } + + if (ackCount > 0) + { + // Set the last byte of the packet equal to the number of appended ACKs + buffer.Data[dataLength++] = (byte)ackCount; + // Set the appended ACKs flag on this packet + buffer.Data[0] |= Helpers.MSG_APPENDED_ACKS; + } + + buffer.DataLength = dataLength; + + #endregion ACK Appending + + if (!isResend) + { + // Not a resend, assign a new sequence number + uint sequenceNumber = (uint)Interlocked.Increment(ref Sequence); + Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); + outgoingPacket.SequenceNumber = sequenceNumber; + + if (isReliable) + { + // Add this packet to the list of ACK responses we are waiting on from the server + lock (NeedAck) NeedAck[sequenceNumber] = outgoingPacket; + } + } + + // Put the UDP payload on the wire + AsyncBeginSend(buffer); + } + + /// + /// + /// + public void SendPing() + { + uint oldestUnacked = 0; + + // Get the oldest NeedAck value, the first entry in the sorted dictionary + lock (NeedAck) + { + if (NeedAck.Count > 0) + { + SortedDictionary.KeyCollection.Enumerator en = NeedAck.Keys.GetEnumerator(); + en.MoveNext(); + oldestUnacked = en.Current; + } + } + + //if (oldestUnacked != 0) + // Logger.DebugLog("Sending ping with oldestUnacked=" + oldestUnacked); + + StartPingCheckPacket ping = new StartPingCheckPacket(); + ping.PingID.PingID = Stats.LastPingID++; + ping.PingID.OldestUnacked = oldestUnacked; + ping.Header.Reliable = false; + SendPacket(ping); + Stats.LastPingSent = Environment.TickCount; + } + + #endregion Packet Sending + + /// + /// Returns Simulator Name as a String + /// + /// + public override string ToString() + { + if (!String.IsNullOrEmpty(Name)) + return String.Format("{0} ({1})", Name, remoteEndPoint); + else + return String.Format("({0})", remoteEndPoint); + } + + /// + /// + /// + /// + public override int GetHashCode() + { + return Handle.GetHashCode(); + } + + /// + /// + /// + /// + /// + public override bool Equals(object obj) + { + Simulator sim = obj as Simulator; + if (sim == null) + return false; + return (remoteEndPoint.Equals(sim.remoteEndPoint)); + } + + public static bool operator ==(Simulator lhs, Simulator rhs) + { + // If both are null, or both are same instance, return true + if (System.Object.ReferenceEquals(lhs, rhs)) + { + return true; + } + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + { + return false; + } + + return lhs.remoteEndPoint.Equals(rhs.remoteEndPoint); + } + + public static bool operator !=(Simulator lhs, Simulator rhs) + { + return !(lhs == rhs); + } + + protected override void PacketReceived(UDPPacketBuffer buffer) + { + Packet packet = null; + + // Check if this packet came from the server we expected it to come from + if (!remoteEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address)) + { + Logger.Log("Received " + buffer.DataLength + " bytes of data from unrecognized source " + + ((IPEndPoint)buffer.RemoteEndPoint).ToString(), Helpers.LogLevel.Warning, Client); + return; + } + + // Update the disconnect flag so this sim doesn't time out + DisconnectCandidate = false; + + #region Packet Decoding + + int packetEnd = buffer.DataLength - 1; + + try + { + packet = Packet.BuildPacket(buffer.Data, ref packetEnd, + // Only allocate a buffer for zerodecoding if the packet is zerocoded + ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[8192] : null); + } + catch (MalformedDataException) + { + Logger.Log(String.Format("Malformed data, cannot parse packet:\n{0}", + Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)), Helpers.LogLevel.Error); + } + + // Fail-safe check + if (packet == null) + { + Logger.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning, Client); + return; + } + + Interlocked.Add(ref Stats.RecvBytes, buffer.DataLength); + Interlocked.Increment(ref Stats.RecvPackets); + + #endregion Packet Decoding + + if (packet.Header.Resent) + Interlocked.Increment(ref Stats.ReceivedResends); + + #region ACK Receiving + + // Handle appended ACKs + if (packet.Header.AppendedAcks && packet.Header.AckList != null) + { + lock (NeedAck) + { + for (int i = 0; i < packet.Header.AckList.Length; i++) + { + if (NeedAck.ContainsKey(packet.Header.AckList[i]) && NeedAck[packet.Header.AckList[i]].Type == PacketType.UseCircuitCode) + { + GotUseCircuitCodeAck.Set(); + } + NeedAck.Remove(packet.Header.AckList[i]); + } + } + } + + // Handle PacketAck packets + if (packet.Type == PacketType.PacketAck) + { + PacketAckPacket ackPacket = (PacketAckPacket)packet; + + lock (NeedAck) + { + for (int i = 0; i < ackPacket.Packets.Length; i++) + { + if (NeedAck.ContainsKey(ackPacket.Packets[i].ID) && NeedAck[ackPacket.Packets[i].ID].Type == PacketType.UseCircuitCode) + { + GotUseCircuitCodeAck.Set(); + } + NeedAck.Remove(ackPacket.Packets[i].ID); + } + } + } + + #endregion ACK Receiving + + if (packet.Header.Reliable) + { + #region ACK Sending + + // Add this packet to the list of ACKs that need to be sent out + uint sequence = (uint)packet.Header.Sequence; + PendingAcks.Enqueue(sequence); + + // Send out ACKs if we have a lot of them + if (PendingAcks.Count >= Client.Settings.MAX_PENDING_ACKS) + SendAcks(); + + #endregion ACK Sending + + // Check the archive of received packet IDs to see whether we already received this packet + if (!PacketArchive.TryEnqueue(packet.Header.Sequence)) + { + if (packet.Header.Resent) + Logger.DebugLog( + string.Format( + "Received a resend of already processed packet #{0}, type: {1} from {2}", + packet.Header.Sequence, packet.Type, Name)); + else + Logger.Log( + string.Format( + "Received a duplicate (not marked as resend) of packet #{0}, type: {1} for {2} from {3}", + packet.Header.Sequence, packet.Type, Client.Self.Name, Name), + Helpers.LogLevel.Warning); + + // Avoid firing a callback twice for the same packet + return; + } + } + + #region Inbox Insertion + + NetworkManager.IncomingPacket incomingPacket; + incomingPacket.Simulator = this; + incomingPacket.Packet = packet; + + Network.PacketInbox.Enqueue(incomingPacket); + + #endregion Inbox Insertion + + #region Stats Tracking + if (Client.Settings.TRACK_UTILIZATION) + { + Client.Stats.Update(packet.Type.ToString(), OpenMetaverse.Stats.Type.Packet, 0, packet.Length); + } + #endregion + } + + protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) + { + // Stats tracking + Interlocked.Add(ref Stats.SentBytes, bytesSent); + Interlocked.Increment(ref Stats.SentPackets); + + Client.Network.RaisePacketSentEvent(buffer.Data, bytesSent, this); + } + + + /// + /// Sends out pending acknowledgements + /// + /// Number of ACKs sent + private int SendAcks() + { + uint ack; + int ackCount = 0; + + if (PendingAcks.TryDequeue(out ack)) + { + List blocks = new List(); + PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); + block.ID = ack; + blocks.Add(block); + + while (PendingAcks.TryDequeue(out ack)) + { + block = new PacketAckPacket.PacketsBlock(); + block.ID = ack; + blocks.Add(block); + } + + PacketAckPacket packet = new PacketAckPacket(); + packet.Header.Reliable = false; + packet.Packets = blocks.ToArray(); + + ackCount = blocks.Count; + SendPacket(packet); + } + + return ackCount; + } + + /// + /// Resend unacknowledged packets + /// + private void ResendUnacked() + { + if (NeedAck.Count > 0) + { + NetworkManager.OutgoingPacket[] array; + + lock (NeedAck) + { + // Create a temporary copy of the outgoing packets array to iterate over + array = new NetworkManager.OutgoingPacket[NeedAck.Count]; + NeedAck.Values.CopyTo(array, 0); + } + + int now = Environment.TickCount; + + // Resend packets + for (int i = 0; i < array.Length; i++) + { + NetworkManager.OutgoingPacket outgoing = array[i]; + + if (outgoing.TickCount != 0 && now - outgoing.TickCount > Client.Settings.RESEND_TIMEOUT) + { + if (outgoing.ResendCount < Client.Settings.MAX_RESEND_COUNT) + { + if (Client.Settings.LOG_RESENDS) + { + Logger.DebugLog(String.Format("Resending {2} packet #{0}, {1}ms have passed", + outgoing.SequenceNumber, now - outgoing.TickCount, outgoing.Type), Client); + } + + // The TickCount will be set to the current time when the packet + // is actually sent out again + outgoing.TickCount = 0; + + // Set the resent flag + outgoing.Buffer.Data[0] = (byte)(outgoing.Buffer.Data[0] | Helpers.MSG_RESENT); + + // Stats tracking + Interlocked.Increment(ref outgoing.ResendCount); + Interlocked.Increment(ref Stats.ResentPackets); + + SendPacketFinal(outgoing); + } + else + { + Logger.DebugLog(String.Format("Dropping packet #{0} after {1} failed attempts", + outgoing.SequenceNumber, outgoing.ResendCount)); + + lock (NeedAck) NeedAck.Remove(outgoing.SequenceNumber); + } + } + } + } + } + + private void AckTimer_Elapsed(object obj) + { + SendAcks(); + ResendUnacked(); + + // Start the ACK handling functions again after NETWORK_TICK_INTERVAL milliseconds + if (null == AckTimer) return; + try { AckTimer.Change(Settings.NETWORK_TICK_INTERVAL, Timeout.Infinite); } + catch (Exception) { } + } + + private void StatsTimer_Elapsed(object obj) + { + long old_in = 0, old_out = 0; + long recv = Stats.RecvBytes; + long sent = Stats.SentBytes; + + if (InBytes.Count >= Client.Settings.STATS_QUEUE_SIZE) + old_in = InBytes.Dequeue(); + if (OutBytes.Count >= Client.Settings.STATS_QUEUE_SIZE) + old_out = OutBytes.Dequeue(); + + InBytes.Enqueue(recv); + OutBytes.Enqueue(sent); + + if (old_in > 0 && old_out > 0) + { + Stats.IncomingBPS = (int)(recv - old_in) / Client.Settings.STATS_QUEUE_SIZE; + Stats.OutgoingBPS = (int)(sent - old_out) / Client.Settings.STATS_QUEUE_SIZE; + //Client.Log("Incoming: " + IncomingBPS + " Out: " + OutgoingBPS + + // " Lag: " + LastLag + " Pings: " + ReceivedPongs + + // "/" + SentPings, Helpers.LogLevel.Debug); + } + } + + private void PingTimer_Elapsed(object obj) + { + SendPing(); + Interlocked.Increment(ref Stats.SentPings); + } + } + + public sealed class IncomingPacketIDCollection + { + readonly uint[] Items; + HashSet hashSet; + int first; + int next; + int capacity; + + public IncomingPacketIDCollection(int capacity) + { + this.capacity = capacity; + Items = new uint[capacity]; + hashSet = new HashSet(); + } + + public bool TryEnqueue(uint ack) + { + lock (hashSet) + { + if (hashSet.Add(ack)) + { + Items[next] = ack; + next = (next + 1) % capacity; + if (next == first) + { + hashSet.Remove(Items[first]); + first = (first + 1) % capacity; + } + + return true; + } + } + + return false; + } + } + + public class SimulatorDataPool + { + private static Timer InactiveSimReaper; + + private static void RemoveOldSims(object state) + { + lock (SimulatorDataPools) + { + int SimTimeout = Settings.SIMULATOR_POOL_TIMEOUT; + List reap = new List(); + foreach (var pool in SimulatorDataPools.Values) + { + if (pool.InactiveSince != DateTime.MaxValue && pool.InactiveSince.AddMilliseconds(SimTimeout) < DateTime.Now) + { + reap.Add(pool.Handle); + } + } + foreach (var hndl in reap) + { + SimulatorDataPools.Remove(hndl); + } + } + } + + public static void SimulatorAdd(Simulator sim) + { + lock (SimulatorDataPools) + { + if (InactiveSimReaper == null) + { + InactiveSimReaper = new Timer(RemoveOldSims, null, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3)); + } + SimulatorDataPool pool = GetSimulatorData(sim.Handle); + if (pool.ActiveClients < 1) pool.ActiveClients = 1; else pool.ActiveClients++; + pool.InactiveSince = DateTime.MaxValue; + } + } + public static void SimulatorRelease(Simulator sim) + { + ulong hndl = sim.Handle; + lock (SimulatorDataPools) + { + SimulatorDataPool dataPool = GetSimulatorData(hndl); + dataPool.ActiveClients--; + if (dataPool.ActiveClients <= 0) + { + dataPool.InactiveSince = DateTime.Now; + } + } + } + + static public Dictionary SimulatorDataPools = new Dictionary(); + + /// + /// Simulator handle + /// + readonly public ulong Handle; + /// + /// Number of GridClients using this datapool + /// + public int ActiveClients; + /// + /// Time that the last client disconnected from the simulator + /// + public DateTime InactiveSince = DateTime.MaxValue; + + #region Pooled Items + /// + /// The cache of prims used and unused in this simulator + /// + public Dictionary PrimCache = new Dictionary(); + + /// + /// Shared parcel info only when POOL_PARCEL_DATA == true + /// + public InternalDictionary Parcels = new InternalDictionary(); + public int[,] ParcelMap = new int[64, 64]; + public bool DownloadingParcelMap = false; + + #endregion Pooled Items + + private SimulatorDataPool(ulong hndl) + { + this.Handle = hndl; + } + + public static SimulatorDataPool GetSimulatorData(ulong hndl) + { + SimulatorDataPool dict; + lock (SimulatorDataPools) + { + if (!SimulatorDataPools.TryGetValue(hndl, out dict)) + { + dict = SimulatorDataPools[hndl] = new SimulatorDataPool(hndl); + } + } + return dict; + } + #region Factories + internal Primitive MakePrimitive(uint localID) + { + var dict = PrimCache; + lock (dict) + { + Primitive prim; + if (!dict.TryGetValue(localID, out prim)) + { + dict[localID] = prim = new Primitive { RegionHandle = Handle, LocalID = localID }; + } + return prim; + } + } + + internal bool NeedsRequest(uint localID) + { + var dict = PrimCache; + lock (dict) return !dict.ContainsKey(localID); + } + #endregion Factories + + internal void ReleasePrims(List removePrims) + { + lock (PrimCache) + { + foreach (uint u in removePrims) + { + Primitive prim; + if (PrimCache.TryGetValue(u, out prim)) prim.ActiveClients--; + } + } + } + } +} diff --git a/OpenMetaverse/SoundManager.cs b/OpenMetaverse/SoundManager.cs new file mode 100644 index 0000000..25ac14f --- /dev/null +++ b/OpenMetaverse/SoundManager.cs @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + /// + /// + /// + public class SoundManager + { + #region Private Members + private readonly GridClient Client; + #endregion + + #region Event Handling + /// The event subscribers, null of no subscribers + private EventHandler m_AttachedSound; + + ///Raises the AttachedSound Event + /// A AttachedSoundEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAttachedSound(AttachedSoundEventArgs e) + { + EventHandler handler = m_AttachedSound; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AttachedSoundLock = new object(); + + /// Raised when the simulator sends us data containing + /// sound + public event EventHandler AttachedSound + { + add { lock (m_AttachedSoundLock) { m_AttachedSound += value; } } + remove { lock (m_AttachedSoundLock) { m_AttachedSound -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_AttachedSoundGainChange; + + ///Raises the AttachedSoundGainChange Event + /// A AttachedSoundGainChangeEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAttachedSoundGainChange(AttachedSoundGainChangeEventArgs e) + { + EventHandler handler = m_AttachedSoundGainChange; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_AttachedSoundGainChangeLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler AttachedSoundGainChange + { + add { lock (m_AttachedSoundGainChangeLock) { m_AttachedSoundGainChange += value; } } + remove { lock (m_AttachedSoundGainChangeLock) { m_AttachedSoundGainChange -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_SoundTrigger; + + ///Raises the SoundTrigger Event + /// A SoundTriggerEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSoundTrigger(SoundTriggerEventArgs e) + { + EventHandler handler = m_SoundTrigger; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SoundTriggerLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler SoundTrigger + { + add { lock (m_SoundTriggerLock) { m_SoundTrigger += value; } } + remove { lock (m_SoundTriggerLock) { m_SoundTrigger -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_PreloadSound; + + ///Raises the PreloadSound Event + /// A PreloadSoundEventArgs object containing + /// the data sent from the simulator + protected virtual void OnPreloadSound(PreloadSoundEventArgs e) + { + EventHandler handler = m_PreloadSound; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_PreloadSoundLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler PreloadSound + { + add { lock (m_PreloadSoundLock) { m_PreloadSound += value; } } + remove { lock (m_PreloadSoundLock) { m_PreloadSound -= value; } } + } + + #endregion + + /// + /// Construct a new instance of the SoundManager class, used for playing and receiving + /// sound assets + /// + /// A reference to the current GridClient instance + public SoundManager(GridClient client) + { + Client = client; + + Client.Network.RegisterCallback(PacketType.AttachedSound, AttachedSoundHandler); + Client.Network.RegisterCallback(PacketType.AttachedSoundGainChange, AttachedSoundGainChangeHandler); + Client.Network.RegisterCallback(PacketType.PreloadSound, PreloadSoundHandler); + Client.Network.RegisterCallback(PacketType.SoundTrigger, SoundTriggerHandler); + } + + #region public methods + + /// + /// Plays a sound in the current region at full volume from avatar position + /// + /// UUID of the sound to be played + public void PlaySound(UUID soundID) + { + SendSoundTrigger(soundID, Client.Self.SimPosition, 1.0f); + } + + /// + /// Plays a sound in the current region at full volume + /// + /// UUID of the sound to be played. + /// position for the sound to be played at. Normally the avatar. + public void SendSoundTrigger(UUID soundID, Vector3 position) + { + SendSoundTrigger(soundID, Client.Self.SimPosition, 1.0f); + } + + /// + /// Plays a sound in the current region + /// + /// UUID of the sound to be played. + /// position for the sound to be played at. Normally the avatar. + /// volume of the sound, from 0.0 to 1.0 + public void SendSoundTrigger(UUID soundID, Vector3 position, float gain) + { + SendSoundTrigger(soundID, Client.Network.CurrentSim.Handle, position, gain); + } + /// + /// Plays a sound in the specified sim + /// + /// UUID of the sound to be played. + /// UUID of the sound to be played. + /// position for the sound to be played at. Normally the avatar. + /// volume of the sound, from 0.0 to 1.0 + public void SendSoundTrigger(UUID soundID, Simulator sim, Vector3 position, float gain) + { + SendSoundTrigger(soundID, sim.Handle, position, gain); + } + + /// + /// Play a sound asset + /// + /// UUID of the sound to be played. + /// handle id for the sim to be played in. + /// position for the sound to be played at. Normally the avatar. + /// volume of the sound, from 0.0 to 1.0 + public void SendSoundTrigger(UUID soundID, ulong handle, Vector3 position, float gain) + { + SoundTriggerPacket soundtrigger = new SoundTriggerPacket(); + soundtrigger.SoundData = new SoundTriggerPacket.SoundDataBlock(); + soundtrigger.SoundData.SoundID = soundID; + soundtrigger.SoundData.ObjectID = UUID.Zero; + soundtrigger.SoundData.OwnerID = UUID.Zero; + soundtrigger.SoundData.ParentID = UUID.Zero; + soundtrigger.SoundData.Handle = handle; + soundtrigger.SoundData.Position = position; + soundtrigger.SoundData.Gain = gain; + + Client.Network.SendPacket(soundtrigger); + } + + #endregion + #region Packet Handlers + + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AttachedSoundHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AttachedSound != null) + { + AttachedSoundPacket sound = (AttachedSoundPacket)e.Packet; + + OnAttachedSound(new AttachedSoundEventArgs(e.Simulator, sound.DataBlock.SoundID, sound.DataBlock.OwnerID, sound.DataBlock.ObjectID, + sound.DataBlock.Gain, (SoundFlags)sound.DataBlock.Flags)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void AttachedSoundGainChangeHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AttachedSoundGainChange != null) + { + AttachedSoundGainChangePacket change = (AttachedSoundGainChangePacket)e.Packet; + OnAttachedSoundGainChange(new AttachedSoundGainChangeEventArgs(e.Simulator, change.DataBlock.ObjectID, change.DataBlock.Gain)); + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void PreloadSoundHandler(object sender, PacketReceivedEventArgs e) + { + if (m_PreloadSound != null) + { + PreloadSoundPacket preload = (PreloadSoundPacket)e.Packet; + + foreach (PreloadSoundPacket.DataBlockBlock data in preload.DataBlock) + { + OnPreloadSound(new PreloadSoundEventArgs(e.Simulator, data.SoundID, data.OwnerID, data.ObjectID)); + } + } + } + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void SoundTriggerHandler(object sender, PacketReceivedEventArgs e) + { + if (m_SoundTrigger != null) + { + SoundTriggerPacket trigger = (SoundTriggerPacket)e.Packet; + OnSoundTrigger(new SoundTriggerEventArgs(e.Simulator, + trigger.SoundData.SoundID, + trigger.SoundData.OwnerID, + trigger.SoundData.ObjectID, + trigger.SoundData.ParentID, + trigger.SoundData.Gain, + trigger.SoundData.Handle, + trigger.SoundData.Position)); + } + } + + #endregion + } + #region EventArgs + + /// Provides data for the event + /// The event occurs when the simulator sends + /// the sound data which emits from an agents attachment + /// + /// The following code example shows the process to subscribe to the event + /// and a stub to handle the data passed from the simulator + /// + /// // Subscribe to the AttachedSound event + /// Client.Sound.AttachedSound += Sound_AttachedSound; + /// + /// // process the data raised in the event here + /// private void Sound_AttachedSound(object sender, AttachedSoundEventArgs e) + /// { + /// // ... Process AttachedSoundEventArgs here ... + /// } + /// + /// + public class AttachedSoundEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly UUID m_SoundID; + private readonly UUID m_OwnerID; + private readonly UUID m_ObjectID; + private readonly float m_Gain; + private readonly SoundFlags m_Flags; + + /// Simulator where the event originated + public Simulator Simulator { get { return m_Simulator; } } + /// Get the sound asset id + public UUID SoundID { get { return m_SoundID; } } + /// Get the ID of the owner + public UUID OwnerID { get { return m_OwnerID; } } + /// Get the ID of the Object + public UUID ObjectID { get { return m_ObjectID; } } + /// Get the volume level + public float Gain { get { return m_Gain; } } + /// Get the + public SoundFlags Flags { get { return m_Flags; } } + + /// + /// Construct a new instance of the SoundTriggerEventArgs class + /// + /// Simulator where the event originated + /// The sound asset id + /// The ID of the owner + /// The ID of the object + /// The volume level + /// The + public AttachedSoundEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID, float gain, SoundFlags flags) + { + this.m_Simulator = sim; + this.m_SoundID = soundID; + this.m_OwnerID = ownerID; + this.m_ObjectID = objectID; + this.m_Gain = gain; + this.m_Flags = flags; + } + } + + /// Provides data for the event + /// The event occurs when an attached sound + /// changes its volume level + public class AttachedSoundGainChangeEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly UUID m_ObjectID; + private readonly float m_Gain; + + /// Simulator where the event originated + public Simulator Simulator { get { return m_Simulator; } } + /// Get the ID of the Object + public UUID ObjectID { get { return m_ObjectID; } } + /// Get the volume level + public float Gain { get { return m_Gain; } } + + /// + /// Construct a new instance of the AttachedSoundGainChangedEventArgs class + /// + /// Simulator where the event originated + /// The ID of the Object + /// The new volume level + public AttachedSoundGainChangeEventArgs(Simulator sim, UUID objectID, float gain) + { + this.m_Simulator = sim; + this.m_ObjectID = objectID; + this.m_Gain = gain; + } + } + + /// Provides data for the event + /// The event occurs when the simulator forwards + /// a request made by yourself or another agent to play either an asset sound or a built in sound + /// + /// Requests to play sounds where the is not one of the built-in + /// will require sending a request to download the sound asset before it can be played + /// + /// + /// The following code example uses the , + /// and + /// properties to display some information on a sound request on the window. + /// + /// // subscribe to the event + /// Client.Sound.SoundTrigger += Sound_SoundTrigger; + /// + /// // play the pre-defined BELL_TING sound + /// Client.Sound.SendSoundTrigger(Sounds.BELL_TING); + /// + /// // handle the response data + /// private void Sound_SoundTrigger(object sender, SoundTriggerEventArgs e) + /// { + /// Console.WriteLine("{0} played the sound {1} at volume {2}", + /// e.OwnerID, e.SoundID, e.Gain); + /// } + /// + /// + public class SoundTriggerEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly UUID m_SoundID; + private readonly UUID m_OwnerID; + private readonly UUID m_ObjectID; + private readonly UUID m_ParentID; + private readonly float m_Gain; + private readonly ulong m_RegionHandle; + private readonly Vector3 m_Position; + + /// Simulator where the event originated + public Simulator Simulator { get { return m_Simulator; } } + /// Get the sound asset id + public UUID SoundID { get { return m_SoundID; } } + /// Get the ID of the owner + public UUID OwnerID { get { return m_OwnerID; } } + /// Get the ID of the Object + public UUID ObjectID { get { return m_ObjectID; } } + /// Get the ID of the objects parent + public UUID ParentID { get { return m_ParentID; } } + /// Get the volume level + public float Gain { get { return m_Gain; } } + /// Get the regionhandle + public ulong RegionHandle { get { return m_RegionHandle; } } + /// Get the source position + public Vector3 Position { get { return m_Position; } } + + /// + /// Construct a new instance of the SoundTriggerEventArgs class + /// + /// Simulator where the event originated + /// The sound asset id + /// The ID of the owner + /// The ID of the object + /// The ID of the objects parent + /// The volume level + /// The regionhandle + /// The source position + public SoundTriggerEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID, UUID parentID, float gain, ulong regionHandle, Vector3 position) + { + this.m_Simulator = sim; + this.m_SoundID = soundID; + this.m_OwnerID = ownerID; + this.m_ObjectID = objectID; + this.m_ParentID = parentID; + this.m_Gain = gain; + this.m_RegionHandle = regionHandle; + this.m_Position = position; + } + } + + /// Provides data for the event + /// The event occurs when the simulator sends + /// the appearance data for an avatar + /// + /// The following code example uses the and + /// properties to display the selected shape of an avatar on the window. + /// + /// // subscribe to the event + /// Client.Avatars.AvatarAppearance += Avatars_AvatarAppearance; + /// + /// // handle the data when the event is raised + /// void Avatars_AvatarAppearance(object sender, AvatarAppearanceEventArgs e) + /// { + /// Console.WriteLine("The Agent {0} is using a {1} shape.", e.AvatarID, (e.VisualParams[31] > 0) : "male" ? "female") + /// } + /// + /// + public class PreloadSoundEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly UUID m_SoundID; + private readonly UUID m_OwnerID; + private readonly UUID m_ObjectID; + + /// Simulator where the event originated + public Simulator Simulator { get { return m_Simulator; } } + /// Get the sound asset id + public UUID SoundID { get { return m_SoundID; } } + /// Get the ID of the owner + public UUID OwnerID { get { return m_OwnerID; } } + /// Get the ID of the Object + public UUID ObjectID { get { return m_ObjectID; } } + + /// + /// Construct a new instance of the PreloadSoundEventArgs class + /// + /// Simulator where the event originated + /// The sound asset id + /// The ID of the owner + /// The ID of the object + public PreloadSoundEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID) + { + this.m_Simulator = sim; + this.m_SoundID = soundID; + this.m_OwnerID = ownerID; + this.m_ObjectID = objectID; + } + } + #endregion +} \ No newline at end of file diff --git a/OpenMetaverse/Sounds.cs b/OpenMetaverse/Sounds.cs new file mode 100644 index 0000000..baf2e34 --- /dev/null +++ b/OpenMetaverse/Sounds.cs @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Collections.Generic; + +namespace OpenMetaverse +{ + /// + /// pre-defined built in sounds + /// + // From http://wiki.secondlife.com/wiki/Client_sounds + public static class Sounds + { + /// + public readonly static UUID BELL_TING = new UUID(" ed124764-705d-d497-167a-182cd9fa2e6c"); + + /// + public readonly static UUID CLICK = new UUID("4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6"); + + /// + public readonly static UUID HEALTH_REDUCTION_FEMALE = new UUID("219c5d93-6c09-31c5-fb3f-c5fe7495c115"); + + /// + public readonly static UUID HEALTH_REDUCTION_MALE = new UUID("e057c244-5768-1056-c37e-1537454eeb62"); + + /// + public readonly static UUID IM_START = new UUID("c825dfbc-9827-7e02-6507-3713d18916c1"); + + /// + public readonly static UUID INSTANT_MESSAGE_NOTIFICATION = new UUID("67cc2844-00f3-2b3c-b991-6418d01e1bb7"); + + /// + public readonly static UUID INVALID_OPERATION = new UUID("4174f859-0d3d-c517-c424-72923dc21f65"); + + /// + public readonly static UUID KEYBOARD_LOOP = new UUID("5e191c7b-8996-9ced-a177-b2ac32bfea06"); + + /// coins + public readonly static UUID MONEY_REDUCTION_COINS = new UUID("77a018af-098e-c037-51a6-178f05877c6f"); + + /// cash register bell + public readonly static UUID MONEY_INCREASE_CASH_REGISTER_BELL = new UUID("104974e3-dfda-428b-99ee-b0d4e748d3a3"); + + /// + public readonly static UUID NULL_KEYSTROKE = new UUID("2ca849ba-2885-4bc3-90ef-d4987a5b983a"); + + /// + public readonly static UUID OBJECT_COLLISION = new UUID("be582e5d-b123-41a2-a150-454c39e961c8"); + + /// rubber + public readonly static UUID OBJECT_COLLISION_RUBBER = new UUID("212b6d1e-8d9c-4986-b3aa-f3c6df8d987d"); + + /// plastic + public readonly static UUID OBJECT_COLLISION_PLASTIC = new UUID("d55c7f3c-e1c3-4ddc-9eff-9ef805d9190e"); + + /// flesh + public readonly static UUID OBJECT_COLLISION_FLESH = new UUID("2d8c6f51-149e-4e23-8413-93a379b42b67"); + + /// wood splintering? + public readonly static UUID OBJECT_COLLISION_WOOD_SPLINTERING = new UUID("6f00669f-15e0-4793-a63e-c03f62fee43a"); + + /// glass break + public readonly static UUID OBJECT_COLLISION_GLASS_BREAK = new UUID("85cda060-b393-48e6-81c8-2cfdfb275351"); + + /// metal clunk + public readonly static UUID OBJECT_COLLISION_METAL_CLUNK = new UUID("d1375446-1c4d-470b-9135-30132433b678"); + + /// whoosh + public readonly static UUID OBJECT_CREATE_WHOOSH = new UUID("3c8fc726-1fd6-862d-fa01-16c5b2568db6"); + + /// shake + public readonly static UUID OBJECT_DELETE_SHAKE = new UUID("0cb7b00a-4c10-6948-84de-a93c09af2ba9"); + + /// + public readonly static UUID OBJECT_REZ = new UUID("f4a0660f-5446-dea2-80b7-6482a082803c"); + + /// ding + public readonly static UUID PIE_MENU_APPEAR_DING = new UUID("8eaed61f-92ff-6485-de83-4dcc938a478e"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT = new UUID("d9f73cf8-17b4-6f7a-1565-7951226c305d"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT1 = new UUID("f6ba9816-dcaf-f755-7b67-51b31b6233e5"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT2 = new UUID("7aff2265-d05b-8b72-63c7-dbf96dc2f21f"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT3 = new UUID("09b2184e-8601-44e2-afbb-ce37434b8ba1"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT4 = new UUID("bbe4c7fc-7044-b05e-7b89-36924a67593c"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT5 = new UUID("d166039b-b4f5-c2ec-4911-c85c727b016c"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT6 = new UUID("242af82b-43c2-9a3b-e108-3b0c7e384981"); + + /// + public readonly static UUID PIE_MENU_SLICE_HIGHLIGHT7 = new UUID("c1f334fb-a5be-8fe7-22b3-29631c21cf0b"); + + /// + public readonly static UUID SNAPSHOT = new UUID("3d09f582-3851-c0e0-f5ba-277ac5c73fb4"); + + /// + public readonly static UUID TELEPORT_TEXTURE_APPLY = new UUID("d7a9a565-a013-2a69-797d-5332baa1a947"); + + /// + public readonly static UUID THUNDER = new UUID("e95c96a5-293c-bb7a-57ad-ce2e785ad85f"); + + /// + public readonly static UUID WINDOW_CLOSE = new UUID("2c346eda-b60c-ab33-1119-b8941916a499"); + + /// + public readonly static UUID WINDOW_OPEN = new UUID("c80260ba-41fd-8a46-768a-6bf236360e3a"); + + /// + public readonly static UUID ZIPPER = new UUID("6cf2be26-90cb-2669-a599-f5ab7698225f"); + + + /// + /// A dictionary containing all pre-defined sounds + /// + /// A dictionary containing the pre-defined sounds, + /// where the key is the sounds ID, and the value is a string + /// containing a name to identify the purpose of the sound + public static Dictionary ToDictionary() + { + Dictionary dict = new Dictionary(); + Type type = typeof(Sounds); + foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Static)) + { + dict.Add((UUID)field.GetValue(type), field.Name); + } + return dict; + } + } +} diff --git a/OpenMetaverse/TerrainCompressor.cs b/OpenMetaverse/TerrainCompressor.cs new file mode 100644 index 0000000..5b8deb7 --- /dev/null +++ b/OpenMetaverse/TerrainCompressor.cs @@ -0,0 +1,852 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + [Serializable] + public class TerrainPatch + { + #region Enums and Structs + + public enum LayerType : byte + { + Land = 0x4C, // 'L' + LandExtended = 0x4D, // 'M' + Water = 0x57, // 'W' + WaterExtended = 0x57, // 'X' + Wind = 0x37, // '7' + WindExtended = 0x39, // '9' + Cloud = 0x38, // '8' + CloudExtended = 0x3A // ':' + } + + public struct GroupHeader + { + public int Stride; + public int PatchSize; + public LayerType Type; + } + + public struct Header + { + public float DCOffset; + public int Range; + public int QuantWBits; + public int PatchIDs; + public uint WordBits; + + public int X + { + get { return PatchIDs >> 5; } + set { PatchIDs += (value << 5); } + } + + public int Y + { + get { return PatchIDs & 0x1F; } + set { PatchIDs |= value & 0x1F; } + } + } + + #endregion Enums and Structs + + /// X position of this patch + public int X; + /// Y position of this patch + public int Y; + /// A 16x16 array of floats holding decompressed layer data + public float[] Data; + } + + public static class TerrainCompressor + { + public const int PATCHES_PER_EDGE = 16; + public const int END_OF_PATCHES = 97; + + private const float OO_SQRT2 = 0.7071067811865475244008443621049f; + private const int STRIDE = 264; + + private const int ZERO_CODE = 0x0; + private const int ZERO_EOB = 0x2; + private const int POSITIVE_VALUE = 0x6; + private const int NEGATIVE_VALUE = 0x7; + + private static readonly float[] DequantizeTable16 = new float[16 * 16]; + private static readonly float[] DequantizeTable32 = new float[16 * 16]; + private static readonly float[] CosineTable16 = new float[16 * 16]; + //private static readonly float[] CosineTable32 = new float[16 * 16]; + private static readonly int[] CopyMatrix16 = new int[16 * 16]; + private static readonly int[] CopyMatrix32 = new int[16 * 16]; + private static readonly float[] QuantizeTable16 = new float[16 * 16]; + + static TerrainCompressor() + { + // Initialize the decompression tables + BuildDequantizeTable16(); + SetupCosines16(); + BuildCopyMatrix16(); + BuildQuantizeTable16(); + } + + public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, TerrainPatch.LayerType type) + { + LayerDataPacket layer = new LayerDataPacket(); + layer.LayerID.Type = (byte)type; + + TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); + header.Stride = STRIDE; + header.PatchSize = 16; + header.Type = type; + + // Should be enough to fit even the most poorly packed data + byte[] data = new byte[patches.Length * 16 * 16 * 2]; + BitPack bitpack = new BitPack(data, 0); + bitpack.PackBits(header.Stride, 16); + bitpack.PackBits(header.PatchSize, 8); + bitpack.PackBits((int)header.Type, 8); + + for (int i = 0; i < patches.Length; i++) + CreatePatch(bitpack, patches[i].Data, patches[i].X, patches[i].Y); + + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + + return layer; + } + + /// + /// Creates a LayerData packet for compressed land data given a full + /// simulator heightmap and an array of indices of patches to compress + /// + /// A 256 * 256 array of floating point values + /// specifying the height at each meter in the simulator + /// Array of indexes in the 16x16 grid of patches + /// for this simulator. For example if 1 and 17 are specified, patches + /// x=1,y=0 and x=1,y=1 are sent + /// + public static LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches) + { + LayerDataPacket layer = new LayerDataPacket(); + layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land; + + TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); + header.Stride = STRIDE; + header.PatchSize = 16; + header.Type = TerrainPatch.LayerType.Land; + + byte[] data = new byte[1536]; + BitPack bitpack = new BitPack(data, 0); + bitpack.PackBits(header.Stride, 16); + bitpack.PackBits(header.PatchSize, 8); + bitpack.PackBits((int)header.Type, 8); + + for (int i = 0; i < patches.Length; i++) + CreatePatchFromHeightmap(bitpack, heightmap, patches[i] % 16, (patches[i] - (patches[i] % 16)) / 16); + + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + + return layer; + } + + public static LayerDataPacket CreateLandPacket(float[] patchData, int x, int y) + { + LayerDataPacket layer = new LayerDataPacket(); + layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land; + + TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); + header.Stride = STRIDE; + header.PatchSize = 16; + header.Type = TerrainPatch.LayerType.Land; + + byte[] data = new byte[1536]; + BitPack bitpack = new BitPack(data, 0); + bitpack.PackBits(header.Stride, 16); + bitpack.PackBits(header.PatchSize, 8); + bitpack.PackBits((int)header.Type, 8); + + CreatePatch(bitpack, patchData, x, y); + + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + + return layer; + } + + public static LayerDataPacket CreateLandPacket(float[,] patchData, int x, int y) + { + LayerDataPacket layer = new LayerDataPacket(); + layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land; + + TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); + header.Stride = STRIDE; + header.PatchSize = 16; + header.Type = TerrainPatch.LayerType.Land; + + byte[] data = new byte[1536]; + BitPack bitpack = new BitPack(data, 0); + bitpack.PackBits(header.Stride, 16); + bitpack.PackBits(header.PatchSize, 8); + bitpack.PackBits((int)header.Type, 8); + + CreatePatch(bitpack, patchData, x, y); + + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + + return layer; + } + + public static void CreatePatch(BitPack output, float[] patchData, int x, int y) + { + if (patchData.Length != 16 * 16) + throw new ArgumentException("Patch data must be a 16x16 array"); + + TerrainPatch.Header header = PrescanPatch(patchData); + header.QuantWBits = 136; + header.PatchIDs = (y & 0x1F); + header.PatchIDs += (x << 5); + + // NOTE: No idea what prequant and postquant should be or what they do + int[] patch = CompressPatch(patchData, header, 10); + int wbits = EncodePatchHeader(output, header, patch); + EncodePatch(output, patch, 0, wbits); + } + + public static void CreatePatch(BitPack output, float[,] patchData, int x, int y) + { + if (patchData.Length != 16 * 16) + throw new ArgumentException("Patch data must be a 16x16 array"); + + TerrainPatch.Header header = PrescanPatch(patchData); + header.QuantWBits = 136; + header.PatchIDs = (y & 0x1F); + header.PatchIDs += (x << 5); + + // NOTE: No idea what prequant and postquant should be or what they do + int[] patch = CompressPatch(patchData, header, 10); + int wbits = EncodePatchHeader(output, header, patch); + EncodePatch(output, patch, 0, wbits); + } + + /// + /// Add a patch of terrain to a BitPacker + /// + /// BitPacker to write the patch to + /// Heightmap of the simulator, must be a 256 * + /// 256 float array + /// X offset of the patch to create, valid values are + /// from 0 to 15 + /// Y offset of the patch to create, valid values are + /// from 0 to 15 + public static void CreatePatchFromHeightmap(BitPack output, float[] heightmap, int x, int y) + { + if (heightmap.Length != 256 * 256) + throw new ArgumentException("Heightmap data must be 256x256"); + + if (x < 0 || x > 15 || y < 0 || y > 15) + throw new ArgumentException("X and Y patch offsets must be from 0 to 15"); + + TerrainPatch.Header header = PrescanPatch(heightmap, x, y); + header.QuantWBits = 136; + header.PatchIDs = (y & 0x1F); + header.PatchIDs += (x << 5); + + // NOTE: No idea what prequant and postquant should be or what they do + int[] patch = CompressPatch(heightmap, x, y, header, 10); + int wbits = EncodePatchHeader(output, header, patch); + EncodePatch(output, patch, 0, wbits); + } + + private static TerrainPatch.Header PrescanPatch(float[] patch) + { + TerrainPatch.Header header = new TerrainPatch.Header(); + float zmax = -99999999.0f; + float zmin = 99999999.0f; + + for (int j = 0; j < 16; j++) + { + for (int i = 0; i < 16; i++) + { + float val = patch[j * 16 + i]; + if (val > zmax) zmax = val; + if (val < zmin) zmin = val; + } + } + + header.DCOffset = zmin; + header.Range = (int)((zmax - zmin) + 1.0f); + + return header; + } + + private static TerrainPatch.Header PrescanPatch(float[,] patch) + { + TerrainPatch.Header header = new TerrainPatch.Header(); + float zmax = -99999999.0f; + float zmin = 99999999.0f; + + for (int j = 0; j < 16; j++) + { + for (int i = 0; i < 16; i++) + { + float val = patch[j, i]; + if (val > zmax) zmax = val; + if (val < zmin) zmin = val; + } + } + + header.DCOffset = zmin; + header.Range = (int)((zmax - zmin) + 1.0f); + + return header; + } + + private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY) + { + TerrainPatch.Header header = new TerrainPatch.Header(); + float zmax = -99999999.0f; + float zmin = 99999999.0f; + + for (int j = patchY * 16; j < (patchY + 1) * 16; j++) + { + for (int i = patchX * 16; i < (patchX + 1) * 16; i++) + { + float val = heightmap[j * 256 + i]; + if (val > zmax) zmax = val; + if (val < zmin) zmin = val; + } + } + + header.DCOffset = zmin; + header.Range = (int)((zmax - zmin) + 1.0f); + + return header; + } + + public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) + { + TerrainPatch.Header header = new TerrainPatch.Header(); + + // Quantized word bits + header.QuantWBits = bitpack.UnpackBits(8); + if (header.QuantWBits == END_OF_PATCHES) + return header; + + // DC offset + header.DCOffset = bitpack.UnpackFloat(); + + // Range + header.Range = bitpack.UnpackBits(16); + + // Patch IDs (10 bits) + header.PatchIDs = bitpack.UnpackBits(10); + + // Word bits + header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); + + return header; + } + + private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch) + { + int temp; + int wbits = (header.QuantWBits & 0x0f) + 2; + uint maxWbits = (uint)wbits + 5; + uint minWbits = ((uint)wbits >> 1); + + wbits = (int)minWbits; + + for (int i = 0; i < patch.Length; i++) + { + temp = patch[i]; + + if (temp != 0) + { + // Get the absolute value + if (temp < 0) temp *= -1; + + for (int j = (int)maxWbits; j > (int)minWbits; j--) + { + if ((temp & (1 << j)) != 0) + { + if (j > wbits) wbits = j; + break; + } + } + } + } + + wbits += 1; + + header.QuantWBits &= 0xf0; + + if (wbits > 17 || wbits < 2) + { + Logger.Log("Bits needed per word in EncodePatchHeader() are outside the allowed range", + Helpers.LogLevel.Error); + } + + header.QuantWBits |= (wbits - 2); + + output.PackBits(header.QuantWBits, 8); + output.PackFloat(header.DCOffset); + output.PackBits(header.Range, 16); + output.PackBits(header.PatchIDs, 10); + + return wbits; + } + + private static void IDCTColumn16(float[] linein, float[] lineout, int column) + { + float total; + int usize; + + for (int n = 0; n < 16; n++) + { + total = OO_SQRT2 * linein[column]; + + for (int u = 1; u < 16; u++) + { + usize = u * 16; + total += linein[usize + column] * CosineTable16[usize + n]; + } + + lineout[16 * n + column] = total; + } + } + + private static void IDCTLine16(float[] linein, float[] lineout, int line) + { + const float oosob = 2.0f / 16.0f; + int lineSize = line * 16; + float total; + + for (int n = 0; n < 16; n++) + { + total = OO_SQRT2 * linein[lineSize]; + + for (int u = 1; u < 16; u++) + { + total += linein[lineSize + u] * CosineTable16[u * 16 + n]; + } + + lineout[lineSize + n] = total * oosob; + } + } + + private static void DCTLine16(float[] linein, float[] lineout, int line) + { + float total = 0.0f; + int lineSize = line * 16; + + for (int n = 0; n < 16; n++) + { + total += linein[lineSize + n]; + } + + lineout[lineSize] = OO_SQRT2 * total; + + for (int u = 1; u < 16; u++) + { + total = 0.0f; + + for (int n = 0; n < 16; n++) + { + total += linein[lineSize + n] * CosineTable16[u * 16 + n]; + } + + lineout[lineSize + u] = total; + } + } + + private static void DCTColumn16(float[] linein, int[] lineout, int column) + { + float total = 0.0f; + const float oosob = 2.0f / 16.0f; + + for (int n = 0; n < 16; n++) + { + total += linein[16 * n + column]; + } + + lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); + + for (int u = 1; u < 16; u++) + { + total = 0.0f; + + for (int n = 0; n < 16; n++) + { + total += linein[16 * n + column] * CosineTable16[u * 16 + n]; + } + + lineout[CopyMatrix16[16 * u + column]] = (int)(total * oosob * QuantizeTable16[16 * u + column]); + } + } + + public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) + { + int temp; + for (int n = 0; n < size * size; n++) + { + // ? + temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Value or EOB + temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Value + temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Negative + temp = bitpack.UnpackBits((int)header.WordBits); + patches[n] = temp * -1; + } + else + { + // Positive + temp = bitpack.UnpackBits((int)header.WordBits); + patches[n] = temp; + } + } + else + { + // Set the rest to zero + // TODO: This might not be necessary + for (int o = n; o < size * size; o++) + { + patches[o] = 0; + } + break; + } + } + else + { + patches[n] = 0; + } + } + } + + private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) + { + int temp; + bool eob; + + if (postquant > 16 * 16 || postquant < 0) + { + Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); + return; + } + + if (postquant != 0) patch[16 * 16 - postquant] = 0; + + for (int i = 0; i < 16 * 16; i++) + { + eob = false; + temp = patch[i]; + + if (temp == 0) + { + eob = true; + + for (int j = i; j < 16 * 16 - postquant; j++) + { + if (patch[j] != 0) + { + eob = false; + break; + } + } + + if (eob) + { + output.PackBits(ZERO_EOB, 2); + return; + } + else + { + output.PackBits(ZERO_CODE, 1); + } + } + else + { + if (temp < 0) + { + temp *= -1; + + if (temp > (1 << wbits)) temp = (1 << wbits); + + output.PackBits(NEGATIVE_VALUE, 3); + output.PackBits(temp, wbits); + } + else + { + if (temp > (1 << wbits)) temp = (1 << wbits); + + output.PackBits(POSITIVE_VALUE, 3); + output.PackBits(temp, wbits); + } + } + } + } + + public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group) + { + float[] block = new float[group.PatchSize * group.PatchSize]; + float[] output = new float[group.PatchSize * group.PatchSize]; + int prequant = (header.QuantWBits >> 4) + 2; + int quantize = 1 << prequant; + float ooq = 1.0f / (float)quantize; + float mult = ooq * (float)header.Range; + float addval = mult * (float)(1 << (prequant - 1)) + header.DCOffset; + + if (group.PatchSize == 16) + { + for (int n = 0; n < 16 * 16; n++) + { + block[n] = patches[CopyMatrix16[n]] * DequantizeTable16[n]; + } + + float[] ftemp = new float[16 * 16]; + + for (int o = 0; o < 16; o++) + IDCTColumn16(block, ftemp, o); + for (int o = 0; o < 16; o++) + IDCTLine16(ftemp, block, o); + } + else + { + for (int n = 0; n < 32 * 32; n++) + { + block[n] = patches[CopyMatrix32[n]] * DequantizeTable32[n]; + } + + Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error); + } + + for (int j = 0; j < block.Length; j++) + { + output[j] = block[j] * mult + addval; + } + + return output; + } + + private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant) + { + float[] block = new float[16 * 16]; + int wordsize = prequant; + float oozrange = 1.0f / (float)header.Range; + float range = (float)(1 << prequant); + float premult = oozrange * range; + float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult; + + header.QuantWBits = wordsize - 2; + header.QuantWBits |= (prequant - 2) << 4; + + int k = 0; + for (int j = 0; j < 16; j++) + { + for (int i = 0; i < 16; i++) + block[k++] = patchData[j * 16 + i] * premult - sub; + } + + float[] ftemp = new float[16 * 16]; + int[] itemp = new int[16 * 16]; + + for (int o = 0; o < 16; o++) + DCTLine16(block, ftemp, o); + for (int o = 0; o < 16; o++) + DCTColumn16(ftemp, itemp, o); + + return itemp; + } + + private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant) + { + float[] block = new float[16 * 16]; + int wordsize = prequant; + float oozrange = 1.0f / (float)header.Range; + float range = (float)(1 << prequant); + float premult = oozrange * range; + float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult; + + header.QuantWBits = wordsize - 2; + header.QuantWBits |= (prequant - 2) << 4; + + int k = 0; + for (int j = 0; j < 16; j++) + { + for (int i = 0; i < 16; i++) + block[k++] = patchData[j, i] * premult - sub; + } + + float[] ftemp = new float[16 * 16]; + int[] itemp = new int[16 * 16]; + + for (int o = 0; o < 16; o++) + DCTLine16(block, ftemp, o); + for (int o = 0; o < 16; o++) + DCTColumn16(ftemp, itemp, o); + + return itemp; + } + + private static int[] CompressPatch(float[] heightmap, int patchX, int patchY, TerrainPatch.Header header, int prequant) + { + float[] block = new float[16 * 16]; + int wordsize = prequant; + float oozrange = 1.0f / (float)header.Range; + float range = (float)(1 << prequant); + float premult = oozrange * range; + float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult; + + header.QuantWBits = wordsize - 2; + header.QuantWBits |= (prequant - 2) << 4; + + int k = 0; + for (int j = patchY * 16; j < (patchY + 1) * 16; j++) + { + for (int i = patchX * 16; i < (patchX + 1) * 16; i++) + block[k++] = heightmap[j * 256 + i] * premult - sub; + } + + float[] ftemp = new float[16 * 16]; + int[] itemp = new int[16 * 16]; + + for (int o = 0; o < 16; o++) + DCTLine16(block, ftemp, o); + for (int o = 0; o < 16; o++) + DCTColumn16(ftemp, itemp, o); + + return itemp; + } + + + #region Initialization + + private static void BuildDequantizeTable16() + { + for (int j = 0; j < 16; j++) + { + for (int i = 0; i < 16; i++) + { + DequantizeTable16[j * 16 + i] = 1.0f + 2.0f * (float)(i + j); + } + } + } + + private static void BuildQuantizeTable16() + { + for (int j = 0; j < 16; j++) + { + for (int i = 0; i < 16; i++) + { + QuantizeTable16[j * 16 + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j)); + } + } + } + + private static void SetupCosines16() + { + const float hposz = (float)Math.PI * 0.5f / 16.0f; + + for (int u = 0; u < 16; u++) + { + for (int n = 0; n < 16; n++) + { + CosineTable16[u * 16 + n] = (float)Math.Cos((2.0f * (float)n + 1.0f) * (float)u * hposz); + } + } + } + + private static void BuildCopyMatrix16() + { + bool diag = false; + bool right = true; + int i = 0; + int j = 0; + int count = 0; + + while (i < 16 && j < 16) + { + CopyMatrix16[j * 16 + i] = count++; + + if (!diag) + { + if (right) + { + if (i < 16 - 1) i++; + else j++; + + right = false; + diag = true; + } + else + { + if (j < 16 - 1) j++; + else i++; + + right = true; + diag = true; + } + } + else + { + if (right) + { + i++; + j--; + if (i == 16 - 1 || j == 0) diag = false; + } + else + { + i--; + j++; + if (j == 16 - 1 || i == 0) diag = false; + } + } + } + } + + #endregion Initialization + } +} diff --git a/OpenMetaverse/TerrainManager.cs b/OpenMetaverse/TerrainManager.cs new file mode 100644 index 0000000..913155a --- /dev/null +++ b/OpenMetaverse/TerrainManager.cs @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + public class TerrainManager + { + #region EventHandling + /// The event subscribers. null if no subcribers + private EventHandler m_LandPatchReceivedEvent; + + /// Raises the LandPatchReceived event + /// A LandPatchReceivedEventArgs object containing the + /// data returned from the simulator + protected virtual void OnLandPatchReceived(LandPatchReceivedEventArgs e) + { + EventHandler handler = m_LandPatchReceivedEvent; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_LandPatchReceivedLock = new object(); + + /// Raised when the simulator responds sends + public event EventHandler LandPatchReceived + { + add { lock (m_LandPatchReceivedLock) { m_LandPatchReceivedEvent += value; } } + remove { lock (m_LandPatchReceivedLock) { m_LandPatchReceivedEvent -= value; } } + } + #endregion + + private GridClient Client; + + /// + /// Default constructor + /// + /// + public TerrainManager(GridClient client) + { + Client = client; + Client.Network.RegisterCallback(PacketType.LayerData, LayerDataHandler); + } + + private void DecompressLand(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) + { + int x; + int y; + int[] patches = new int[32 * 32]; + int count = 0; + + while (true) + { + TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); + + if (header.QuantWBits == TerrainCompressor.END_OF_PATCHES) + break; + + x = header.X; + y = header.Y; + + if (x >= TerrainCompressor.PATCHES_PER_EDGE || y >= TerrainCompressor.PATCHES_PER_EDGE) + { + Logger.Log(String.Format( + "Invalid LayerData land packet, x={0}, y={1}, dc_offset={2}, range={3}, quant_wbits={4}, patchids={5}, count={6}", + x, y, header.DCOffset, header.Range, header.QuantWBits, header.PatchIDs, count), + Helpers.LogLevel.Warning, Client); + return; + } + + // Decode this patch + TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); + + // Decompress this patch + float[] heightmap = TerrainCompressor.DecompressPatch(patches, header, group); + + count++; + + try { OnLandPatchReceived(new LandPatchReceivedEventArgs(simulator, x, y, group.PatchSize, heightmap)); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + + if (Client.Settings.STORE_LAND_PATCHES) + { + TerrainPatch patch = new TerrainPatch(); + patch.Data = heightmap; + patch.X = x; + patch.Y = y; + simulator.Terrain[y * 16 + x] = patch; + } + } + } + + private void DecompressWind(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) + { + int[] patches = new int[32 * 32]; + + // Ignore the simulator stride value + group.Stride = group.PatchSize; + + // Each wind packet contains the wind speeds and direction for the entire simulator + // stored as two float arrays. The first array is the X value of the wind speed at + // each 16x16m block, second is the Y value. + // wind_speed = distance(x,y to 0,0) + // wind_direction = vec2(x,y) + + // X values + TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); + TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); + float[] xvalues = TerrainCompressor.DecompressPatch(patches, header, group); + + // Y values + header = TerrainCompressor.DecodePatchHeader(bitpack); + TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); + float[] yvalues = TerrainCompressor.DecompressPatch(patches, header, group); + + if (simulator.Client.Settings.STORE_LAND_PATCHES) + { + for (int i = 0; i < 256; i++) + simulator.WindSpeeds[i] = new Vector2(xvalues[i], yvalues[i]); + } + } + + private void DecompressCloud(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) + { + // FIXME: + } + + private void LayerDataHandler(object sender, PacketReceivedEventArgs e) + { + LayerDataPacket layer = (LayerDataPacket)e.Packet; + BitPack bitpack = new BitPack(layer.LayerData.Data, 0); + TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); + TerrainPatch.LayerType type = (TerrainPatch.LayerType)layer.LayerID.Type; + + // Stride + header.Stride = bitpack.UnpackBits(16); + // Patch size + header.PatchSize = bitpack.UnpackBits(8); + // Layer type + header.Type = (TerrainPatch.LayerType)bitpack.UnpackBits(8); + + switch (type) + { + case TerrainPatch.LayerType.Land: + if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES) + DecompressLand(e.Simulator, bitpack, header); + break; + case TerrainPatch.LayerType.Water: + Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client); + break; + case TerrainPatch.LayerType.Wind: + DecompressWind(e.Simulator, bitpack, header); + break; + case TerrainPatch.LayerType.Cloud: + DecompressCloud(e.Simulator, bitpack, header); + break; + default: + Logger.Log("Unrecognized LayerData type " + type.ToString(), Helpers.LogLevel.Warning, Client); + break; + } + } + } + + #region EventArgs classes + // Provides data for LandPatchReceived + public class LandPatchReceivedEventArgs : EventArgs + { + private readonly Simulator m_Simulator; + private readonly int m_X; + private readonly int m_Y; + private readonly int m_PatchSize; + private readonly float[] m_HeightMap; + + /// Simulator from that sent tha data + public Simulator Simulator { get { return m_Simulator; } } + /// Sim coordinate of the patch + public int X { get { return m_X; } } + /// Sim coordinate of the patch + public int Y { get { return m_Y; } } + /// Size of tha patch + public int PatchSize { get { return m_PatchSize; } } + /// Heightmap for the patch + public float[] HeightMap { get { return m_HeightMap; } } + + public LandPatchReceivedEventArgs(Simulator simulator, int x, int y, int patchSize, float[] heightMap) + { + this.m_Simulator = simulator; + this.m_X = x; + this.m_Y = y; + this.m_PatchSize = patchSize; + this.m_HeightMap = heightMap; + } + } + #endregion +} diff --git a/OpenMetaverse/TexturePipeline.cs b/OpenMetaverse/TexturePipeline.cs new file mode 100644 index 0000000..d48dcc6 --- /dev/null +++ b/OpenMetaverse/TexturePipeline.cs @@ -0,0 +1,824 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#define DEBUG_TIMING + +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse.Packets; +using OpenMetaverse.Assets; + +namespace OpenMetaverse +{ + /// + /// The current status of a texture request as it moves through the pipeline or final result of a texture request. + /// + public enum TextureRequestState + { + /// The initial state given to a request. Requests in this state + /// are waiting for an available slot in the pipeline + Pending, + /// A request that has been added to the pipeline and the request packet + /// has been sent to the simulator + Started, + /// A request that has received one or more packets back from the simulator + Progress, + /// A request that has received all packets back from the simulator + Finished, + /// A request that has taken longer than + /// to download OR the initial packet containing the packet information was never received + Timeout, + /// The texture request was aborted by request of the agent + Aborted, + /// The simulator replied to the request that it was not able to find the requested texture + NotFound + } + /// + /// A callback fired to indicate the status or final state of the requested texture. For progressive + /// downloads this will fire each time new asset data is returned from the simulator. + /// + /// The indicating either Progress for textures not fully downloaded, + /// or the final result of the request after it has been processed through the TexturePipeline + /// The object containing the Assets ID, raw data + /// and other information. For progressive rendering the will contain + /// the data from the beginning of the file. For failed, aborted and timed out requests it will contain + /// an empty byte array. + public delegate void TextureDownloadCallback(TextureRequestState state, AssetTexture assetTexture); + + /// + /// Texture request download handler, allows a configurable number of download slots which manage multiple + /// concurrent texture downloads from the + /// + /// This class makes full use of the internal + /// system for full texture downloads. + public class TexturePipeline + { +#if DEBUG_TIMING // Timing globals + /// The combined time it has taken for all textures requested sofar. This includes the amount of time the + /// texture spent waiting for a download slot, and the time spent retrieving the actual texture from the Grid + public static TimeSpan TotalTime; + /// The amount of time the request spent in the state + public static TimeSpan NetworkTime; + /// The total number of bytes transferred since the TexturePipeline was started + public static int TotalBytes; +#endif + /// + /// A request task containing information and status of a request as it is processed through the + /// + private class TaskInfo + { + /// The current which identifies the current status of the request + public TextureRequestState State; + /// The Unique Request ID, This is also the Asset ID of the texture being requested + public UUID RequestID; + /// The slot this request is occupying in the threadpoolSlots array + public int RequestSlot; + /// The ImageType of the request. + public ImageType Type; + + /// The callback to fire when the request is complete, will include + /// the and the + /// object containing the result data + public List Callbacks; + /// If true, indicates the callback will be fired whenever new data is returned from the simulator. + /// This is used to progressively render textures as portions of the texture are received. + public bool ReportProgress; +#if DEBUG_TIMING + /// The time the request was added to the the PipeLine + public DateTime StartTime; + /// The time the request was sent to the simulator + public DateTime NetworkTime; +#endif + /// An object that maintains the data of an request thats in-process. + public ImageDownload Transfer; + } + + /// A dictionary containing all pending and in-process transfer requests where the Key is both the RequestID + /// and also the Asset Texture ID, and the value is an object containing the current state of the request and also + /// the asset data as it is being re-assembled + private readonly Dictionary _Transfers; + /// Holds the reference to the client object + private readonly GridClient _Client; + /// Maximum concurrent texture requests allowed at a time + private readonly int maxTextureRequests; + /// An array of objects used to manage worker request threads + private readonly AutoResetEvent[] resetEvents; + /// An array of worker slots which shows the availablity status of the slot + private readonly int[] threadpoolSlots; + /// The primary thread which manages the requests. + private Thread downloadMaster; + /// true if the TexturePipeline is currently running + bool _Running; + /// A synchronization object used by the primary thread + private object lockerObject = new object(); + /// A refresh timer used to increase the priority of stalled requests + private System.Timers.Timer RefreshDownloadsTimer; + + /// Current number of pending and in-process transfers + public int TransferCount { get { return _Transfers.Count; } } + + /// + /// Default constructor, Instantiates a new copy of the TexturePipeline class + /// + /// Reference to the instantiated object + public TexturePipeline(GridClient client) + { + _Client = client; + + maxTextureRequests = client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS; + + resetEvents = new AutoResetEvent[maxTextureRequests]; + threadpoolSlots = new int[maxTextureRequests]; + + _Transfers = new Dictionary(); + + // Pre-configure autoreset events and threadpool slots + for (int i = 0; i < maxTextureRequests; i++) + { + resetEvents[i] = new AutoResetEvent(true); + threadpoolSlots[i] = -1; + } + + // Handle client connected and disconnected events + client.Network.LoginProgress += delegate(object sender, LoginProgressEventArgs e) { + if (e.Status == LoginStatus.Success) + { + Startup(); + } + }; + + client.Network.Disconnected += delegate { Shutdown(); }; + } + + /// + /// Initialize callbacks required for the TexturePipeline to operate + /// + public void Startup() + { + if (_Running) + return; + + if (downloadMaster == null) + { + // Instantiate master thread that manages the request pool + downloadMaster = new Thread(DownloadThread); + downloadMaster.Name = "TexturePipeline"; + downloadMaster.IsBackground = true; + } + + _Running = true; + + _Client.Network.RegisterCallback(PacketType.ImageData, ImageDataHandler); + _Client.Network.RegisterCallback(PacketType.ImagePacket, ImagePacketHandler); + _Client.Network.RegisterCallback(PacketType.ImageNotInDatabase, ImageNotInDatabaseHandler); + downloadMaster.Start(); + if (RefreshDownloadsTimer == null) + { + RefreshDownloadsTimer = new System.Timers.Timer(Settings.PIPELINE_REFRESH_INTERVAL); + RefreshDownloadsTimer.Elapsed += RefreshDownloadsTimer_Elapsed; + RefreshDownloadsTimer.Start(); + } + } + + /// + /// Shutdown the TexturePipeline and cleanup any callbacks or transfers + /// + public void Shutdown() + { + if (!_Running) + return; +#if DEBUG_TIMING + Logger.Log(String.Format("Combined Execution Time: {0}, Network Execution Time {1}, Network {2}K/sec, Image Size {3}", + TotalTime, NetworkTime, Math.Round(TotalBytes / NetworkTime.TotalSeconds / 60, 2), TotalBytes), Helpers.LogLevel.Debug); +#endif + if(null != RefreshDownloadsTimer) RefreshDownloadsTimer.Dispose(); + RefreshDownloadsTimer = null; + + if (downloadMaster != null && downloadMaster.IsAlive) + { + downloadMaster.Abort(); + } + downloadMaster = null; + + _Client.Network.UnregisterCallback(PacketType.ImageNotInDatabase, ImageNotInDatabaseHandler); + _Client.Network.UnregisterCallback(PacketType.ImageData, ImageDataHandler); + _Client.Network.UnregisterCallback(PacketType.ImagePacket, ImagePacketHandler); + + lock (_Transfers) + _Transfers.Clear(); + + for (int i = 0; i < resetEvents.Length; i++) + if (resetEvents[i] != null) + resetEvents[i].Set(); + + _Running = false; + } + + private void RefreshDownloadsTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + lock (_Transfers) + { + foreach (TaskInfo transfer in _Transfers.Values) + { + if (transfer.State == TextureRequestState.Progress) + { + ImageDownload download = transfer.Transfer; + + // Find the first missing packet in the download + ushort packet = 0; + lock (download) if (download.PacketsSeen != null && download.PacketsSeen.Count > 0) + packet = GetFirstMissingPacket(download.PacketsSeen); + + if (download.TimeSinceLastPacket > 5000) + { + // We're not receiving data for this texture fast enough, bump up the priority by 5% + download.Priority *= 1.05f; + + download.TimeSinceLastPacket = 0; + RequestImage(download.ID, download.ImageType, download.Priority, download.DiscardLevel, packet); + } + if (download.TimeSinceLastPacket > _Client.Settings.PIPELINE_REQUEST_TIMEOUT) + { + resetEvents[transfer.RequestSlot].Set(); + } + } + } + } + } + + /// + /// Request a texture asset from the simulator using the system to + /// manage the requests and re-assemble the image from the packets received from the simulator + /// + /// The of the texture asset to download + /// The of the texture asset. + /// Use for most textures, or for baked layer texture assets + /// A float indicating the requested priority for the transfer. Higher priority values tell the simulator + /// to prioritize the request before lower valued requests. An image already being transferred using the can have + /// its priority changed by resending the request with the new priority value + /// Number of quality layers to discard. + /// This controls the end marker of the data sent + /// The packet number to begin the request at. A value of 0 begins the request + /// from the start of the asset texture + /// The callback to fire when the image is retrieved. The callback + /// will contain the result of the request and the texture asset data + /// If true, the callback will be fired for each chunk of the downloaded image. + /// The callback asset parameter will contain all previously received chunks of the texture asset starting + /// from the beginning of the request + public void RequestTexture(UUID textureID, ImageType imageType, float priority, int discardLevel, uint packetStart, TextureDownloadCallback callback, bool progressive) + { + if (textureID == UUID.Zero) + return; + + if (callback != null) + { + if (_Client.Assets.Cache.HasAsset(textureID)) + { + ImageDownload image = new ImageDownload(); + image.ID = textureID; + image.AssetData = _Client.Assets.Cache.GetCachedAssetBytes(textureID); + image.Size = image.AssetData.Length; + image.Transferred = image.AssetData.Length; + image.ImageType = imageType; + image.AssetType = AssetType.Texture; + image.Success = true; + + callback(TextureRequestState.Finished, new AssetTexture(image.ID, image.AssetData)); + + _Client.Assets.FireImageProgressEvent(image.ID, image.Transferred, image.Size); + } + else + { + lock (_Transfers) + { + TaskInfo request; + + if (_Transfers.TryGetValue(textureID, out request)) + { + request.Callbacks.Add(callback); + } + else + { + request = new TaskInfo(); + request.State = TextureRequestState.Pending; + request.RequestID = textureID; + request.ReportProgress = progressive; + request.RequestSlot = -1; + request.Type = imageType; + + request.Callbacks = new List(); + request.Callbacks.Add(callback); + + ImageDownload downloadParams = new ImageDownload(); + downloadParams.ID = textureID; + downloadParams.Priority = priority; + downloadParams.ImageType = imageType; + downloadParams.DiscardLevel = discardLevel; + + request.Transfer = downloadParams; +#if DEBUG_TIMING + request.StartTime = DateTime.UtcNow; +#endif + _Transfers.Add(textureID, request); + } + } + } + } + } + + /// + /// Sends the actual request packet to the simulator + /// + /// The image to download + /// Type of the image to download, either a baked + /// avatar texture or a normal texture + /// Priority level of the download. Default is + /// 1,013,000.0f + /// Number of quality layers to discard. + /// This controls the end marker of the data sent + /// Packet number to start the download at. + /// This controls the start marker of the data sent + /// Sending a priority of 0 and a discardlevel of -1 aborts + /// download + private void RequestImage(UUID imageID, ImageType type, float priority, int discardLevel, uint packetNum) + { + // Priority == 0 && DiscardLevel == -1 means cancel the transfer + if (priority.Equals(0) && discardLevel.Equals(-1)) + { + AbortTextureRequest(imageID); + } + else + { + TaskInfo task; + if (TryGetTransferValue(imageID, out task)) + { + if (task.Transfer.Simulator != null) + { + // Already downloading, just updating the priority + float percentComplete = ((float)task.Transfer.Transferred / (float)task.Transfer.Size) * 100f; + if (Single.IsNaN(percentComplete)) + percentComplete = 0f; + + if (percentComplete > 0f) + Logger.DebugLog(String.Format("Updating priority on image transfer {0} to {1}, {2}% complete", + imageID, task.Transfer.Priority, Math.Round(percentComplete, 2))); + } + else + { + ImageDownload transfer = task.Transfer; + transfer.Simulator = _Client.Network.CurrentSim; + } + + // Build and send the request packet + RequestImagePacket request = new RequestImagePacket(); + request.AgentData.AgentID = _Client.Self.AgentID; + request.AgentData.SessionID = _Client.Self.SessionID; + request.RequestImage = new RequestImagePacket.RequestImageBlock[1]; + request.RequestImage[0] = new RequestImagePacket.RequestImageBlock(); + request.RequestImage[0].DiscardLevel = (sbyte)discardLevel; + request.RequestImage[0].DownloadPriority = priority; + request.RequestImage[0].Packet = packetNum; + request.RequestImage[0].Image = imageID; + request.RequestImage[0].Type = (byte)type; + + _Client.Network.SendPacket(request, _Client.Network.CurrentSim); + } + else + { + Logger.Log("Received texture download request for a texture that isn't in the download queue: " + imageID, Helpers.LogLevel.Warning); + } + } + } + + /// + /// Cancel a pending or in process texture request + /// + /// The texture assets unique ID + public void AbortTextureRequest(UUID textureID) + { + TaskInfo task; + if (TryGetTransferValue(textureID, out task)) + { + // this means we've actually got the request assigned to the threadpool + if (task.State == TextureRequestState.Progress) + { + RequestImagePacket request = new RequestImagePacket(); + request.AgentData.AgentID = _Client.Self.AgentID; + request.AgentData.SessionID = _Client.Self.SessionID; + request.RequestImage = new RequestImagePacket.RequestImageBlock[1]; + request.RequestImage[0] = new RequestImagePacket.RequestImageBlock(); + request.RequestImage[0].DiscardLevel = -1; + request.RequestImage[0].DownloadPriority = 0; + request.RequestImage[0].Packet = 0; + request.RequestImage[0].Image = textureID; + request.RequestImage[0].Type = (byte)task.Type; + _Client.Network.SendPacket(request); + + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Aborted, new AssetTexture(textureID, Utils.EmptyBytes)); + + _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, task.Transfer.Size); + + resetEvents[task.RequestSlot].Set(); + + RemoveTransfer(textureID); + } + else + { + RemoveTransfer(textureID); + + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Aborted, new AssetTexture(textureID, Utils.EmptyBytes)); + + _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, task.Transfer.Size); + } + } + } + + /// + /// Master Download Thread, Queues up downloads in the threadpool + /// + private void DownloadThread() + { + int slot; + + while (_Running) + { + // find free slots + int pending = 0; + int active = 0; + + TaskInfo nextTask = null; + + lock (_Transfers) + { + foreach (KeyValuePair request in _Transfers) + { + if (request.Value.State == TextureRequestState.Pending) + { + nextTask = request.Value; + ++pending; + } + else if (request.Value.State == TextureRequestState.Progress) + { + ++active; + } + } + } + + if (pending > 0 && active <= maxTextureRequests) + { + slot = -1; + // find available slot for reset event + lock (lockerObject) + { + for (int i = 0; i < threadpoolSlots.Length; i++) + { + if (threadpoolSlots[i] == -1) + { + // found a free slot + threadpoolSlots[i] = 1; + slot = i; + break; + } + } + } + + // -1 = slot not available + if (slot != -1 && nextTask != null) + { + nextTask.State = TextureRequestState.Started; + nextTask.RequestSlot = slot; + + //Logger.DebugLog(String.Format("Sending Worker thread new download request {0}", slot)); + WorkPool.QueueUserWorkItem(TextureRequestDoWork, nextTask); + continue; + } + } + + // Queue was empty or all download slots are inuse, let's give up some CPU time + Thread.Sleep(500); + } + + Logger.Log("Texture pipeline shutting down", Helpers.LogLevel.Info); + } + + + /// + /// The worker thread that sends the request and handles timeouts + /// + /// A object containing the request details + private void TextureRequestDoWork(Object threadContext) + { + TaskInfo task = (TaskInfo)threadContext; + + task.State = TextureRequestState.Progress; + +#if DEBUG_TIMING + task.NetworkTime = DateTime.UtcNow; +#endif + // Find the first missing packet in the download + ushort packet = 0; + lock (task.Transfer) if (task.Transfer.PacketsSeen != null && task.Transfer.PacketsSeen.Count > 0) + packet = GetFirstMissingPacket(task.Transfer.PacketsSeen); + + // Request the texture + RequestImage(task.RequestID, task.Type, task.Transfer.Priority, task.Transfer.DiscardLevel, packet); + + // Set starting time + task.Transfer.TimeSinceLastPacket = 0; + + // Don't release this worker slot until texture is downloaded or timeout occurs + if (!resetEvents[task.RequestSlot].WaitOne()) + { + // Timed out + Logger.Log("Worker " + task.RequestSlot + " timeout waiting for texture " + task.RequestID + " to download got " + + task.Transfer.Transferred + " of " + task.Transfer.Size, Helpers.LogLevel.Warning); + + AssetTexture texture = new AssetTexture(task.RequestID, task.Transfer.AssetData); + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Timeout, texture); + + _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, task.Transfer.Size); + + RemoveTransfer(task.RequestID); + } + + // Free up this download slot + lock (lockerObject) + threadpoolSlots[task.RequestSlot] = -1; + } + + private ushort GetFirstMissingPacket(SortedList packetsSeen) + { + ushort packet = 0; + + lock (packetsSeen) + { + bool first = true; + foreach (KeyValuePair packetSeen in packetsSeen) + { + if (first) + { + // Initially set this to the earliest packet received in the transfer + packet = packetSeen.Value; + first = false; + } + else + { + ++packet; + + // If there is a missing packet in the list, break and request the download + // resume here + if (packetSeen.Value != packet) + { + --packet; + break; + } + } + } + + ++packet; + } + + return packet; + } + + #region Raw Packet Handlers + + /// + /// Handle responses from the simulator that tell us a texture we have requested is unable to be located + /// or no longer exists. This will remove the request from the pipeline and free up a slot if one is in use + /// + /// The sender + /// The EventArgs object containing the packet data + protected void ImageNotInDatabaseHandler(object sender, PacketReceivedEventArgs e) + { + ImageNotInDatabasePacket imageNotFoundData = (ImageNotInDatabasePacket)e.Packet; + TaskInfo task; + + if (TryGetTransferValue(imageNotFoundData.ImageID.ID, out task)) + { + // cancel acive request and free up the threadpool slot + if (task.State == TextureRequestState.Progress) + resetEvents[task.RequestSlot].Set(); + + // fire callback to inform the caller + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.NotFound, new AssetTexture(imageNotFoundData.ImageID.ID, Utils.EmptyBytes)); + + resetEvents[task.RequestSlot].Set(); + + RemoveTransfer(imageNotFoundData.ImageID.ID); + } + else + { + Logger.Log("Received an ImageNotFound packet for an image we did not request: " + imageNotFoundData.ImageID.ID, Helpers.LogLevel.Warning); + } + } + + /// + /// Handles the remaining Image data that did not fit in the initial ImageData packet + /// + /// The sender + /// The EventArgs object containing the packet data + protected void ImagePacketHandler(object sender, PacketReceivedEventArgs e) + { + ImagePacketPacket image = (ImagePacketPacket)e.Packet; + TaskInfo task; + + if (TryGetTransferValue(image.ImageID.ID, out task)) + { + if (task.Transfer.Size == 0) + { + // We haven't received the header yet, block until it's received or times out + task.Transfer.HeaderReceivedEvent.WaitOne(1000 * 5, false); + + if (task.Transfer.Size == 0) + { + Logger.Log("Timed out while waiting for the image header to download for " + + task.Transfer.ID, Helpers.LogLevel.Warning, _Client); + + RemoveTransfer(task.Transfer.ID); + resetEvents[task.RequestSlot].Set(); // free up request slot + + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Timeout, new AssetTexture(task.RequestID, task.Transfer.AssetData)); + + return; + } + } + + // The header is downloaded, we can insert this data in to the proper position + // Only insert if we haven't seen this packet before + lock (task.Transfer) + { + if (!task.Transfer.PacketsSeen.ContainsKey(image.ImageID.Packet)) + { + task.Transfer.PacketsSeen[image.ImageID.Packet] = image.ImageID.Packet; + Buffer.BlockCopy(image.ImageData.Data, 0, task.Transfer.AssetData, + task.Transfer.InitialDataSize + (1000 * (image.ImageID.Packet - 1)), + image.ImageData.Data.Length); + task.Transfer.Transferred += image.ImageData.Data.Length; + } + } + + task.Transfer.TimeSinceLastPacket = 0; + + if (task.Transfer.Transferred >= task.Transfer.Size) + { +#if DEBUG_TIMING + DateTime stopTime = DateTime.UtcNow; + TimeSpan requestDuration = stopTime - task.StartTime; + + TimeSpan networkDuration = stopTime - task.NetworkTime; + + TotalTime += requestDuration; + NetworkTime += networkDuration; + TotalBytes += task.Transfer.Size; + + Logger.Log( + String.Format( + "Transfer Complete {0} [{1}] Total Request Time: {2}, Download Time {3}, Network {4}Kb/sec, Image Size {5} bytes", + task.RequestID, task.RequestSlot, requestDuration, networkDuration, + Math.Round(task.Transfer.Size/networkDuration.TotalSeconds/60, 2), task.Transfer.Size), + Helpers.LogLevel.Debug); +#endif + + task.Transfer.Success = true; + RemoveTransfer(task.Transfer.ID); + resetEvents[task.RequestSlot].Set(); // free up request slot + _Client.Assets.Cache.SaveAssetToCache(task.RequestID, task.Transfer.AssetData); + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Finished, new AssetTexture(task.RequestID, task.Transfer.AssetData)); + + _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, task.Transfer.Size); + } + else + { + if (task.ReportProgress) + { + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Progress, + new AssetTexture(task.RequestID, task.Transfer.AssetData)); + } + _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, + task.Transfer.Size); + } + } + } + + /// + /// Handle the initial ImageDataPacket sent from the simulator + /// + /// The sender + /// The EventArgs object containing the packet data + protected void ImageDataHandler(object sender, PacketReceivedEventArgs e) + { + ImageDataPacket data = (ImageDataPacket)e.Packet; + TaskInfo task; + + if (TryGetTransferValue(data.ImageID.ID, out task)) + { + // reset the timeout interval since we got data + task.Transfer.TimeSinceLastPacket = 0; + + lock (task.Transfer) if (task.Transfer.Size == 0) + { + task.Transfer.Codec = (ImageCodec)data.ImageID.Codec; + task.Transfer.PacketCount = data.ImageID.Packets; + task.Transfer.Size = (int)data.ImageID.Size; + task.Transfer.AssetData = new byte[task.Transfer.Size]; + task.Transfer.AssetType = AssetType.Texture; + task.Transfer.PacketsSeen = new SortedList(); + Buffer.BlockCopy(data.ImageData.Data, 0, task.Transfer.AssetData, 0, data.ImageData.Data.Length); + task.Transfer.InitialDataSize = data.ImageData.Data.Length; + task.Transfer.Transferred += data.ImageData.Data.Length; + } + + task.Transfer.HeaderReceivedEvent.Set(); + + if (task.Transfer.Transferred >= task.Transfer.Size) + { +#if DEBUG_TIMING + DateTime stopTime = DateTime.UtcNow; + TimeSpan requestDuration = stopTime - task.StartTime; + + TimeSpan networkDuration = stopTime - task.NetworkTime; + + TotalTime += requestDuration; + NetworkTime += networkDuration; + TotalBytes += task.Transfer.Size; + + Logger.Log( + String.Format( + "Transfer Complete {0} [{1}] Total Request Time: {2}, Download Time {3}, Network {4}Kb/sec, Image Size {5} bytes", + task.RequestID, task.RequestSlot, requestDuration, networkDuration, + Math.Round(task.Transfer.Size/networkDuration.TotalSeconds/60, 2), task.Transfer.Size), + Helpers.LogLevel.Debug); +#endif + task.Transfer.Success = true; + RemoveTransfer(task.RequestID); + resetEvents[task.RequestSlot].Set(); + + _Client.Assets.Cache.SaveAssetToCache(task.RequestID, task.Transfer.AssetData); + + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Finished, new AssetTexture(task.RequestID, task.Transfer.AssetData)); + + _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, task.Transfer.Size); + } + else + { + if (task.ReportProgress) + { + foreach (TextureDownloadCallback callback in task.Callbacks) + callback(TextureRequestState.Progress, + new AssetTexture(task.RequestID, task.Transfer.AssetData)); + } + + _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, + task.Transfer.Size); + } + } + } + + #endregion + + private bool TryGetTransferValue(UUID textureID, out TaskInfo task) + { + lock (_Transfers) + return _Transfers.TryGetValue(textureID, out task); + } + + private bool RemoveTransfer(UUID textureID) + { + lock (_Transfers) + return _Transfers.Remove(textureID); + } + } +} diff --git a/OpenMetaverse/ThreadUtil.cs b/OpenMetaverse/ThreadUtil.cs new file mode 100644 index 0000000..e3937b4 --- /dev/null +++ b/OpenMetaverse/ThreadUtil.cs @@ -0,0 +1,66 @@ +// Written by Peter A. Bromberg, found at +// http://www.eggheadcafe.com/articles/20060727.asp + +using System; +using System.Threading; + +/// +/// +/// +public class ThreadUtil +{ + /// + /// Delegate to wrap another delegate and its arguments + /// + /// + /// + delegate void DelegateWrapper(Delegate d, object[] args); + + /// + /// An instance of DelegateWrapper which calls InvokeWrappedDelegate, + /// which in turn calls the DynamicInvoke method of the wrapped + /// delegate + /// + static DelegateWrapper wrapperInstance = new DelegateWrapper(InvokeWrappedDelegate); + + /// + /// Callback used to call EndInvoke on the asynchronously + /// invoked DelegateWrapper + /// + static AsyncCallback callback = new AsyncCallback(EndWrapperInvoke); + + /// + /// Executes the specified delegate with the specified arguments + /// asynchronously on a thread pool thread + /// + /// + /// + public static void FireAndForget(Delegate d, params object[] args) + { + // Invoke the wrapper asynchronously, which will then + // execute the wrapped delegate synchronously (in the + // thread pool thread) + if (d != null) wrapperInstance.BeginInvoke(d, args, callback, null); + } + + /// + /// Invokes the wrapped delegate synchronously + /// + /// + /// + static void InvokeWrappedDelegate(Delegate d, object[] args) + { + d.DynamicInvoke(args); + } + + /// + /// Calls EndInvoke on the wrapper and Close on the resulting WaitHandle + /// to prevent resource leaks + /// + /// + static void EndWrapperInvoke(IAsyncResult ar) + { + wrapperInstance.EndInvoke(ar); + ar.AsyncWaitHandle.Close(); + } +} diff --git a/OpenMetaverse/UDPBase.cs b/OpenMetaverse/UDPBase.cs new file mode 100644 index 0000000..b21a16f --- /dev/null +++ b/OpenMetaverse/UDPBase.cs @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2006, Clutch, Inc. + * Original Author: Jeff Cesnik + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace OpenMetaverse +{ + /// + /// + /// + public abstract class UDPBase + { + // these abstract methods must be implemented in a derived class to actually do + // something with the packets that are sent and received. + protected abstract void PacketReceived(UDPPacketBuffer buffer); + protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); + + // the port to listen on + protected int udpPort; + + // the remote endpoint to communicate with + protected IPEndPoint remoteEndPoint = null; + + // the UDP socket + private Socket udpSocket; + + // the all important shutdownFlag. + private volatile bool shutdownFlag = true; + + /// + /// Initialize the UDP packet handler in server mode + /// + /// Port to listening for incoming UDP packets on + public UDPBase(int port) + { + udpPort = port; + } + + /// + /// Initialize the UDP packet handler in client mode + /// + /// Remote UDP server to connect to + public UDPBase(IPEndPoint endPoint) + { + remoteEndPoint = endPoint; + udpPort = 0; + } + + /// + /// + /// + public void Start() + { + if (shutdownFlag) + { + const int SIO_UDP_CONNRESET = -1744830452; + + IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); + udpSocket = new Socket( + AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp); + try + { + // this udp socket flag is not supported under mono, + // so we'll catch the exception and continue + udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); + } + catch (SocketException) + { + Logger.DebugLog("UDP SIO_UDP_CONNRESET flag not supported on this platform"); + } + + // On at least Mono 3.2.8, multiple UDP sockets can bind to the same port by default. This means that + // when running multiple connections, two can occasionally bind to the same port, leading to unexpected + // errors as they intercept each others messages. We need to prevent this. This is not allowed by + // default on Windows. + udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + + udpSocket.Bind(ipep); + + // we're not shutting down, we're starting up + shutdownFlag = false; + + // kick off an async receive. The Start() method will return, the + // actual receives will occur asynchronously and will be caught in + // AsyncEndRecieve(). + AsyncBeginReceive(); + } + } + + /// + /// + /// + public void Stop() + { + if (!shutdownFlag) + { + // wait indefinitely for a writer lock. Once this is called, the .NET runtime + // will deny any more reader locks, in effect blocking all other send/receive + // threads. Once we have the lock, we set shutdownFlag to inform the other + // threads that the socket is closed. + shutdownFlag = true; + udpSocket.Close(); + } + } + + /// + /// + /// + public bool IsRunning + { + get { return !shutdownFlag; } + } + + private void AsyncBeginReceive() + { + // allocate a packet buffer + //WrappedObject wrappedBuffer = Pool.CheckOut(); + UDPPacketBuffer buf = new UDPPacketBuffer(); + + if (!shutdownFlag) + { + try + { + // kick off an async read + udpSocket.BeginReceiveFrom( + //wrappedBuffer.Instance.Data, + buf.Data, + 0, + UDPPacketBuffer.BUFFER_SIZE, + SocketFlags.None, + ref buf.RemoteEndPoint, + AsyncEndReceive, + //wrappedBuffer); + buf); + } + catch (SocketException e) + { + if (e.SocketErrorCode == SocketError.ConnectionReset) + { + Logger.Log("SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + udpPort, Helpers.LogLevel.Error); + bool salvaged = false; + while (!salvaged) + { + try + { + udpSocket.BeginReceiveFrom( + //wrappedBuffer.Instance.Data, + buf.Data, + 0, + UDPPacketBuffer.BUFFER_SIZE, + SocketFlags.None, + ref buf.RemoteEndPoint, + AsyncEndReceive, + //wrappedBuffer); + buf); + salvaged = true; + } + catch (SocketException) { } + catch (ObjectDisposedException) { return; } + } + + Logger.Log("Salvaged the UDP listener on port " + udpPort, Helpers.LogLevel.Info); + } + } + catch (ObjectDisposedException) { } + } + } + + private void AsyncEndReceive(IAsyncResult iar) + { + // Asynchronous receive operations will complete here through the call + // to AsyncBeginReceive + if (!shutdownFlag) + { + // start another receive - this keeps the server going! + AsyncBeginReceive(); + + // get the buffer that was created in AsyncBeginReceive + // this is the received data + //WrappedObject wrappedBuffer = (WrappedObject)iar.AsyncState; + //UDPPacketBuffer buffer = wrappedBuffer.Instance; + UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + + try + { + // get the length of data actually read from the socket, store it with the + // buffer + buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); + + // call the abstract method PacketReceived(), passing the buffer that + // has just been filled from the socket read. + PacketReceived(buffer); + } + catch (SocketException) { } + catch (ObjectDisposedException) { } + //finally { wrappedBuffer.Dispose(); } + } + } + + public void AsyncBeginSend(UDPPacketBuffer buf) + { + if (!shutdownFlag) + { + try + { + // Profiling heavily loaded clients was showing better performance with + // synchronous UDP packet sending + udpSocket.SendTo( + buf.Data, + 0, + buf.DataLength, + SocketFlags.None, + buf.RemoteEndPoint); + + //udpSocket.BeginSendTo( + // buf.Data, + // 0, + // buf.DataLength, + // SocketFlags.None, + // buf.RemoteEndPoint, + // AsyncEndSend, + // buf); + } + catch (SocketException) { } + catch (ObjectDisposedException) { } + } + } + + //void AsyncEndSend(IAsyncResult result) + //{ + // try + // { + // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; + // if (!udpSocket.Connected) return; + // int bytesSent = udpSocket.EndSendTo(result); + + // PacketSent(buf, bytesSent); + // } + // catch (SocketException) { } + // catch (ObjectDisposedException) { } + //} + } +} diff --git a/OpenMetaverse/UtilizationStatistics.cs b/OpenMetaverse/UtilizationStatistics.cs new file mode 100644 index 0000000..eadaf20 --- /dev/null +++ b/OpenMetaverse/UtilizationStatistics.cs @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +using System; +using System.Text; +using System.Threading; +using System.Collections.Generic; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.Stats +{ + public enum Type + { + Packet, + Message + } + public class UtilizationStatistics + { + + public class Stat + { + public Type Type; + public long TxCount; + public long RxCount; + public long TxBytes; + public long RxBytes; + + public Stat(Type type, long txCount, long rxCount, long txBytes, long rxBytes) + { + this.Type = type; + this.TxCount = txCount; + this.RxCount = rxCount; + this.TxBytes = txBytes; + this.RxBytes = rxBytes; + } + } + + private Dictionary m_StatsCollection; + + public UtilizationStatistics() + { + m_StatsCollection = new Dictionary(); + } + + internal void Update(string key, Type Type, long txBytes, long rxBytes) + { + lock (m_StatsCollection) + { + if(m_StatsCollection.ContainsKey(key)) + { + Stat stat = m_StatsCollection[key]; + if (rxBytes > 0) + { + Interlocked.Increment(ref stat.RxCount); + Interlocked.Add(ref stat.RxBytes, rxBytes); + } + + if (txBytes > 0) + { + Interlocked.Increment(ref stat.TxCount); + Interlocked.Add(ref stat.TxBytes, txBytes); + } + + } else { + Stat stat; + if (txBytes > 0) + stat = new Stat(Type, 1, 0, txBytes, 0); + else + stat = new Stat(Type, 0, 1, 0, rxBytes); + + m_StatsCollection.Add(key, stat); + } + } + } + + public Dictionary GetStatistics() + { + lock(m_StatsCollection) + { + return new Dictionary(m_StatsCollection); + } + } + } +} diff --git a/OpenMetaverse/Voice/TCPPipe.cs b/OpenMetaverse/Voice/TCPPipe.cs new file mode 100644 index 0000000..4029546 --- /dev/null +++ b/OpenMetaverse/Voice/TCPPipe.cs @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Net.Sockets; + +namespace OpenMetaverse.Voice +{ + public class TCPPipe + { + protected class SocketPacket + { + public System.Net.Sockets.Socket TCPSocket; + public byte[] DataBuffer = new byte[1]; + } + + public delegate void OnReceiveLineCallback(string line); + public delegate void OnDisconnectedCallback(SocketException se); + + public event OnReceiveLineCallback OnReceiveLine; + public event OnDisconnectedCallback OnDisconnected; + + protected Socket _TCPSocket; + protected IAsyncResult _Result; + protected AsyncCallback _Callback; + protected string _Buffer = String.Empty; + + public bool Connected + { + get + { + if (_TCPSocket != null && _TCPSocket.Connected) + return true; + else + return false; + } + } + + public TCPPipe() + { + } + + public SocketException Connect(string address, int port) + { + if (_TCPSocket != null && _TCPSocket.Connected) + Disconnect(); + + try + { + IPAddress ip; + if (!IPAddress.TryParse(address, out ip)) + { + IPAddress[] ips = Dns.GetHostAddresses(address); + ip = ips[0]; + } + _TCPSocket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + IPEndPoint ipEndPoint = new IPEndPoint(ip, port); + _TCPSocket.Connect(ipEndPoint); + if (_TCPSocket.Connected) + { + WaitForData(); + return null; + } + else + { + return new SocketException(10000); + } + } + catch (SocketException se) + { + return se; + } + } + + public void Disconnect() + { + _TCPSocket.Disconnect(true); + } + + public void SendData(byte[] data) + { + if (Connected) + _TCPSocket.Send(data); + else + throw new InvalidOperationException("socket is not connected"); + } + + public void SendLine(string message) + { + if (Connected) + { + byte[] byData = System.Text.Encoding.ASCII.GetBytes(message + "\n"); + _TCPSocket.Send(byData); + } + else + { + throw new InvalidOperationException("socket is not connected"); + } + } + + void WaitForData() + { + try + { + if (_Callback == null) _Callback = new AsyncCallback(OnDataReceived); + SocketPacket packet = new SocketPacket(); + packet.TCPSocket = _TCPSocket; + _Result = _TCPSocket.BeginReceive(packet.DataBuffer, 0, packet.DataBuffer.Length, SocketFlags.None, _Callback, packet); + } + catch (SocketException se) + { + Console.WriteLine(se.Message); + } + } + + static char[] splitNull = { '\0' }; + static string[] splitLines = { "\r", "\n", "\r\n" }; + + void ReceiveData(string data) + { + if (OnReceiveLine == null) return; + + //string[] splitNull = { "\0" }; + string[] line = data.Split(splitNull, StringSplitOptions.None); + _Buffer += line[0]; + //string[] splitLines = { "\r\n", "\r", "\n" }; + string[] lines = _Buffer.Split(splitLines, StringSplitOptions.None); + if (lines.Length > 1) + { + int i; + for (i = 0; i < lines.Length - 1; i++) + { + if (lines[i].Trim().Length > 0) OnReceiveLine(lines[i]); + } + _Buffer = lines[i]; + } + } + + void OnDataReceived(IAsyncResult asyn) + { + try + { + SocketPacket packet = (SocketPacket)asyn.AsyncState; + int end = packet.TCPSocket.EndReceive(asyn); + char[] chars = new char[end + 1]; + System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); + d.GetChars(packet.DataBuffer, 0, end, chars, 0); + System.String data = new System.String(chars); + ReceiveData(data); + WaitForData(); + } + catch (ObjectDisposedException) + { + Console.WriteLine("WARNING: Socket closed unexpectedly"); + } + catch (SocketException se) + { + if (!_TCPSocket.Connected) + { + if (OnDisconnected != null) + OnDisconnected(se); + } + } + } + + } +} diff --git a/OpenMetaverse/Voice/VoiceAccount.cs b/OpenMetaverse/Voice/VoiceAccount.cs new file mode 100644 index 0000000..19e2d6b --- /dev/null +++ b/OpenMetaverse/Voice/VoiceAccount.cs @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.Voice +{ + public partial class VoiceGateway + { + /// + /// This is used to login a specific user account(s). It may only be called after + /// Connector initialization has completed successfully + /// + /// Handle returned from successful Connector ‘create’ request + /// User's account name + /// User's account password + /// Values may be “AutoAnswer” or “VerifyAnswer” + /// "" + /// This is an integer that specifies how often + /// the daemon will send participant property events while in a channel. If this is not set + /// the default will be “on state change”, which means that the events will be sent when + /// the participant starts talking, stops talking, is muted, is unmuted. + /// The valid values are: + /// 0 – Never + /// 5 – 10 times per second + /// 10 – 5 times per second + /// 50 – 1 time per second + /// 100 – on participant state change (this is the default) + /// false + /// + public int AccountLogin(string ConnectorHandle, string AccountName, string AccountPassword, string AudioSessionAnswerMode, string AccountURI, int ParticipantPropertyFrequency, bool EnableBuddiesAndPresence) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("ConnectorHandle", ConnectorHandle)); + sb.Append(VoiceGateway.MakeXML("AccountName", AccountName)); + sb.Append(VoiceGateway.MakeXML("AccountPassword", AccountPassword)); + sb.Append(VoiceGateway.MakeXML("AudioSessionAnswerMode", AudioSessionAnswerMode)); + sb.Append(VoiceGateway.MakeXML("AccountURI", AccountURI)); + sb.Append(VoiceGateway.MakeXML("ParticipantPropertyFrequency", ParticipantPropertyFrequency.ToString())); + sb.Append(VoiceGateway.MakeXML("EnableBuddiesAndPresence", EnableBuddiesAndPresence ? "true" : "false")); + sb.Append(VoiceGateway.MakeXML("BuddyManagementMode", "Application")); + return Request("Account.Login.1", sb.ToString()); + } + + /// + /// This is used to logout a user session. It should only be called with a valid AccountHandle. + /// + /// Handle returned from successful Connector ‘login’ request + /// + public int AccountLogout(string AccountHandle) + { + string RequestXML = VoiceGateway.MakeXML("AccountHandle", AccountHandle); + return Request("Account.Logout.1", RequestXML); + } + } +} diff --git a/OpenMetaverse/Voice/VoiceAux.cs b/OpenMetaverse/Voice/VoiceAux.cs new file mode 100644 index 0000000..f3add78 --- /dev/null +++ b/OpenMetaverse/Voice/VoiceAux.cs @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.Voice +{ + public partial class VoiceGateway + { + /// + /// This is used to get a list of audio devices that can be used for capture (input) of voice. + /// + /// + public int AuxGetCaptureDevices() + { + return Request("Aux.GetCaptureDevices.1"); + } + + /// + /// This is used to get a list of audio devices that can be used for render (playback) of voice. + /// + public int AuxGetRenderDevices() + { + return Request("Aux.GetRenderDevices.1"); + } + + /// + /// This command is used to select the render device. + /// + /// The name of the device as returned by the Aux.GetRenderDevices command. + public int AuxSetRenderDevice(string RenderDeviceSpecifier) + { + string RequestXML = VoiceGateway.MakeXML("RenderDeviceSpecifier", RenderDeviceSpecifier); + return Request("Aux.SetRenderDevice.1", RequestXML); + } + + /// + /// This command is used to select the capture device. + /// + /// The name of the device as returned by the Aux.GetCaptureDevices command. + public int AuxSetCaptureDevice(string CaptureDeviceSpecifier) + { + string RequestXML = VoiceGateway.MakeXML("CaptureDeviceSpecifier", CaptureDeviceSpecifier); + return Request("Aux.SetCaptureDevice.1", RequestXML); + } + + /// + /// This command is used to start the audio capture process which will cause + /// AuxAudioProperty Events to be raised. These events can be used to display a + /// microphone VU meter for the currently selected capture device. This command + /// should not be issued if the user is on a call. + /// + /// (unused but required) + /// + public int AuxCaptureAudioStart(int Duration) + { + string RequestXML = VoiceGateway.MakeXML("Duration", Duration.ToString()); + return Request("Aux.CaptureAudioStart.1", RequestXML); + } + + /// + /// This command is used to stop the audio capture process. + /// + /// + public int AuxCaptureAudioStop() + { + return Request("Aux.CaptureAudioStop.1"); + } + + /// + /// This command is used to set the mic volume while in the audio tuning process. + /// Once an acceptable mic level is attained, the application must issue a + /// connector set mic volume command to have that level be used while on voice + /// calls. + /// + /// the microphone volume (-100 to 100 inclusive) + /// + public int AuxSetMicLevel(int Level) + { + string RequestXML = VoiceGateway.MakeXML("Level", Level.ToString()); + return Request("Aux.SetMicLevel.1", RequestXML); + } + + /// + /// This command is used to set the speaker volume while in the audio tuning + /// process. Once an acceptable speaker level is attained, the application must + /// issue a connector set speaker volume command to have that level be used while + /// on voice calls. + /// + /// the speaker volume (-100 to 100 inclusive) + /// + public int AuxSetSpeakerLevel(int Level) + { + string RequestXML = VoiceGateway.MakeXML("Level", Level.ToString()); + return Request("Aux.SetSpeakerLevel.1", RequestXML); + } + } +} diff --git a/OpenMetaverse/Voice/VoiceConnector.cs b/OpenMetaverse/Voice/VoiceConnector.cs new file mode 100644 index 0000000..10b75cb --- /dev/null +++ b/OpenMetaverse/Voice/VoiceConnector.cs @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.Voice +{ + public partial class VoiceGateway + { + /// + /// This is used to initialize and stop the Connector as a whole. The Connector + /// Create call must be completed successfully before any other requests are made + /// (typically during application initialization). The shutdown should be called + /// when the application is shutting down to gracefully release resources + /// + /// A string value indicting the Application name + /// URL for the management server + /// LoggingSettings + /// + /// + public int ConnectorCreate(string ClientName, string AccountManagementServer, ushort MinimumPort, + ushort MaximumPort, VoiceLoggingSettings Logging) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("ClientName", ClientName)); + sb.Append(VoiceGateway.MakeXML("AccountManagementServer", AccountManagementServer)); + sb.Append(VoiceGateway.MakeXML("MinimumPort", MinimumPort.ToString())); + sb.Append(VoiceGateway.MakeXML("MaximumPort", MaximumPort.ToString())); + sb.Append(VoiceGateway.MakeXML("Mode", "Normal")); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("Enabled", Logging.Enabled ? "true" : "false")); + sb.Append(VoiceGateway.MakeXML("Folder", Logging.Folder)); + sb.Append(VoiceGateway.MakeXML("FileNamePrefix", Logging.FileNamePrefix)); + sb.Append(VoiceGateway.MakeXML("FileNameSuffix", Logging.FileNameSuffix)); + sb.Append(VoiceGateway.MakeXML("LogLevel", Logging.LogLevel.ToString())); + sb.Append(""); + return Request("Connector.Create.1", sb.ToString()); + } + + /// + /// Shutdown Connector -- Should be called when the application is shutting down + /// to gracefully release resources + /// + /// Handle returned from successful Connector ‘create’ request + public int ConnectorInitiateShutdown(string ConnectorHandle) + { + string RequestXML = VoiceGateway.MakeXML("ConnectorHandle", ConnectorHandle); + return Request("Connector.InitiateShutdown.1", RequestXML); + } + + /// + /// Mute or unmute the microphone + /// + /// Handle returned from successful Connector ‘create’ request + /// true (mute) or false (unmute) + public int ConnectorMuteLocalMic(string ConnectorHandle, bool Mute) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("ConnectorHandle", ConnectorHandle)); + sb.Append(VoiceGateway.MakeXML("Value", Mute ? "true" : "false")); + return Request("Connector.MuteLocalMic.1", sb.ToString()); + } + + /// + /// Mute or unmute the speaker + /// + /// Handle returned from successful Connector ‘create’ request + /// true (mute) or false (unmute) + public int ConnectorMuteLocalSpeaker(string ConnectorHandle, bool Mute) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("ConnectorHandle", ConnectorHandle)); + sb.Append(VoiceGateway.MakeXML("Value", Mute ? "true" : "false")); + return Request("Connector.MuteLocalSpeaker.1", sb.ToString()); + } + + /// + /// Set microphone volume + /// + /// Handle returned from successful Connector ‘create’ request + /// The level of the audio, a number between -100 and 100 where + /// 0 represents ‘normal’ speaking volume + public int ConnectorSetLocalMicVolume(string ConnectorHandle, int Value) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("ConnectorHandle", ConnectorHandle)); + sb.Append(VoiceGateway.MakeXML("Value", Value.ToString())); + return Request("Connector.SetLocalMicVolume.1", sb.ToString()); + } + + /// + /// Set local speaker volume + /// + /// Handle returned from successful Connector ‘create’ request + /// The level of the audio, a number between -100 and 100 where + /// 0 represents ‘normal’ speaking volume + public int ConnectorSetLocalSpeakerVolume(string ConnectorHandle, int Value) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("ConnectorHandle", ConnectorHandle)); + sb.Append(VoiceGateway.MakeXML("Value", Value.ToString())); + return Request("Connector.SetLocalSpeakerVolume.1", sb.ToString()); + } + } +} diff --git a/OpenMetaverse/Voice/VoiceControl.cs b/OpenMetaverse/Voice/VoiceControl.cs new file mode 100644 index 0000000..e14429b --- /dev/null +++ b/OpenMetaverse/Voice/VoiceControl.cs @@ -0,0 +1,1003 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +//#define DEBUG_VOICE + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Threading; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Voice +{ + public partial class VoiceGateway : IDisposable + { + // These states should be in increasing order of 'completeness' + // so that the (int) values can drive a progress bar. + public enum ConnectionState + { + None = 0, + Provisioned, + DaemonStarted, + DaemonConnected, + ConnectorConnected, + AccountLogin, + RegionCapAvailable, + SessionRunning + } + + internal string sipServer = ""; + private string acctServer = "https://www.bhr.vivox.com/api2/"; + private string connectionHandle; + private string accountHandle; + private string sessionHandle; + + // Parameters to Vivox daemon + private string slvoicePath = ""; + private string slvoiceArgs = "-ll 5"; + private string daemonNode = "127.0.0.1"; + private int daemonPort = 37331; + + private string voiceUser; + private string voicePassword; + private string spatialUri; + private string spatialCredentials; + + // Session management + private Dictionary sessions; + private VoiceSession spatialSession; + private Uri currentParcelCap; + private Uri nextParcelCap; + private string regionName; + + // Position update thread + private Thread posThread; + private ManualResetEvent posRestart; + public GridClient Client; + private VoicePosition position; + private Vector3d oldPosition; + private Vector3d oldAt; + + // Audio interfaces + private List inputDevices; + /// + /// List of audio input devices + /// + public List CaptureDevices { get { return inputDevices; } } + private List outputDevices; + /// + /// List of audio output devices + /// + public List PlaybackDevices { get { return outputDevices; } } + private string currentCaptureDevice; + private string currentPlaybackDevice; + private bool testing = false; + + public event EventHandler OnSessionCreate; + public event EventHandler OnSessionRemove; + public delegate void VoiceConnectionChangeCallback(ConnectionState state); + public event VoiceConnectionChangeCallback OnVoiceConnectionChange; + public delegate void VoiceMicTestCallback(float level); + public event VoiceMicTestCallback OnVoiceMicTest; + + public VoiceGateway(GridClient c) + { + Random rand = new Random(); + daemonPort = rand.Next(34000, 44000); + + Client = c; + + sessions = new Dictionary(); + position = new VoicePosition(); + position.UpOrientation = new Vector3d(0.0, 1.0, 0.0); + position.Velocity = new Vector3d(0.0, 0.0, 0.0); + oldPosition = new Vector3d(0, 0, 0); + oldAt = new Vector3d(1, 0, 0); + + slvoiceArgs = " -ll -1"; // Min logging + slvoiceArgs += " -i 127.0.0.1:" + daemonPort.ToString(); + // slvoiceArgs += " -lf " + control.instance.ClientDir; + } + + /// + /// Start up the Voice service. + /// + public void Start() + { + // Start the background thread + if (posThread != null && posThread.IsAlive) + posThread.Abort(); + posThread = new Thread(new ThreadStart(PositionThreadBody)); + posThread.Name = "VoicePositionUpdate"; + posThread.IsBackground = true; + posRestart = new ManualResetEvent(false); + posThread.Start(); + + Client.Network.EventQueueRunning += new EventHandler(Network_EventQueueRunning); + + // Connection events + OnDaemonRunning += + new VoiceGateway.DaemonRunningCallback(connector_OnDaemonRunning); + OnDaemonCouldntRun += + new VoiceGateway.DaemonCouldntRunCallback(connector_OnDaemonCouldntRun); + OnConnectorCreateResponse += + new EventHandler(connector_OnConnectorCreateResponse); + OnDaemonConnected += + new DaemonConnectedCallback(connector_OnDaemonConnected); + OnDaemonCouldntConnect += + new DaemonCouldntConnectCallback(connector_OnDaemonCouldntConnect); + OnAuxAudioPropertiesEvent += + new EventHandler(connector_OnAuxAudioPropertiesEvent); + + // Session events + OnSessionStateChangeEvent += + new EventHandler(connector_OnSessionStateChangeEvent); + OnSessionAddedEvent += + new EventHandler(connector_OnSessionAddedEvent); + + // Session Participants events + OnSessionParticipantUpdatedEvent += + new EventHandler(connector_OnSessionParticipantUpdatedEvent); + OnSessionParticipantAddedEvent += + new EventHandler(connector_OnSessionParticipantAddedEvent); + + // Device events + OnAuxGetCaptureDevicesResponse += + new EventHandler(connector_OnAuxGetCaptureDevicesResponse); + OnAuxGetRenderDevicesResponse += + new EventHandler(connector_OnAuxGetRenderDevicesResponse); + + // Generic status response + OnVoiceResponse += new EventHandler(connector_OnVoiceResponse); + + // Account events + OnAccountLoginResponse += + new EventHandler(connector_OnAccountLoginResponse); + + Logger.Log("Voice initialized", Helpers.LogLevel.Info); + + // If voice provisioning capability is already available, + // proceed with voice startup. Otherwise the EventQueueRunning + // event will do it. + System.Uri vCap = + Client.Network.CurrentSim.Caps.CapabilityURI("ProvisionVoiceAccountRequest"); + if (vCap != null) + RequestVoiceProvision(vCap); + + } + + /// + /// Handle miscellaneous request status + /// + /// + /// + /// ///If something goes wrong, we log it. + void connector_OnVoiceResponse(object sender, VoiceGateway.VoiceResponseEventArgs e) + { + if (e.StatusCode == 0) + return; + + Logger.Log(e.Message + " on " + sender as string, Helpers.LogLevel.Error); + } + + public void Stop() + { + Client.Network.EventQueueRunning -= new EventHandler(Network_EventQueueRunning); + + // Connection events + OnDaemonRunning -= + new VoiceGateway.DaemonRunningCallback(connector_OnDaemonRunning); + OnDaemonCouldntRun -= + new VoiceGateway.DaemonCouldntRunCallback(connector_OnDaemonCouldntRun); + OnConnectorCreateResponse -= + new EventHandler(connector_OnConnectorCreateResponse); + OnDaemonConnected -= + new VoiceGateway.DaemonConnectedCallback(connector_OnDaemonConnected); + OnDaemonCouldntConnect -= + new VoiceGateway.DaemonCouldntConnectCallback(connector_OnDaemonCouldntConnect); + OnAuxAudioPropertiesEvent -= + new EventHandler(connector_OnAuxAudioPropertiesEvent); + + // Session events + OnSessionStateChangeEvent -= + new EventHandler(connector_OnSessionStateChangeEvent); + OnSessionAddedEvent -= + new EventHandler(connector_OnSessionAddedEvent); + + // Session Participants events + OnSessionParticipantUpdatedEvent -= + new EventHandler(connector_OnSessionParticipantUpdatedEvent); + OnSessionParticipantAddedEvent -= + new EventHandler(connector_OnSessionParticipantAddedEvent); + OnSessionParticipantRemovedEvent -= + new EventHandler(connector_OnSessionParticipantRemovedEvent); + + // Tuning events + OnAuxGetCaptureDevicesResponse -= + new EventHandler(connector_OnAuxGetCaptureDevicesResponse); + OnAuxGetRenderDevicesResponse -= + new EventHandler(connector_OnAuxGetRenderDevicesResponse); + + // Account events + OnAccountLoginResponse -= + new EventHandler(connector_OnAccountLoginResponse); + + // Stop the background thread + if (posThread != null) + { + PosUpdating(false); + + if (posThread.IsAlive) + posThread.Abort(); + posThread = null; + } + + // Close all sessions + foreach (VoiceSession s in sessions.Values) + { + if (OnSessionRemove != null) + OnSessionRemove(s, EventArgs.Empty); + s.Close(); + } + + // Clear out lots of state so in case of restart we begin at the beginning. + currentParcelCap = null; + sessions.Clear(); + accountHandle = null; + voiceUser = null; + voicePassword = null; + + SessionTerminate(sessionHandle); + sessionHandle = null; + AccountLogout(accountHandle); + accountHandle = null; + ConnectorInitiateShutdown(connectionHandle); + connectionHandle = null; + StopDaemon(); + } + + /// + /// Cleanup oject resources + /// + public void Dispose() + { + Stop(); + } + + internal string GetVoiceDaemonPath() + { + string myDir = + Path.GetDirectoryName( + (System.Reflection.Assembly.GetEntryAssembly() ?? typeof (VoiceGateway).Assembly).Location); + + if (Environment.OSVersion.Platform != PlatformID.MacOSX && + Environment.OSVersion.Platform != PlatformID.Unix) + { + string localDaemon = Path.Combine(myDir, Path.Combine("voice", "SLVoice.exe")); + + if (File.Exists(localDaemon)) + return localDaemon; + + string progFiles; + if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ProgramFiles(x86)"))) + { + progFiles = Environment.GetEnvironmentVariable("ProgramFiles(x86)"); + } + else + { + progFiles = Environment.GetEnvironmentVariable("ProgramFiles"); + } + + if (System.IO.File.Exists(Path.Combine(progFiles, @"SecondLife" + Path.DirectorySeparatorChar + @"SLVoice.exe"))) + { + return Path.Combine(progFiles, @"SecondLife" + Path.DirectorySeparatorChar + @"SLVoice.exe"); + } + + return Path.Combine(myDir, @"SLVoice.exe"); + + } + else + { + string localDaemon = Path.Combine(myDir, Path.Combine("voice", "SLVoice")); + + if (File.Exists(localDaemon)) + return localDaemon; + + return Path.Combine(myDir,"SLVoice"); + } + } + + void RequestVoiceProvision(System.Uri cap) + { + OpenMetaverse.Http.CapsClient capClient = + new OpenMetaverse.Http.CapsClient(cap); + capClient.OnComplete += + new OpenMetaverse.Http.CapsClient.CompleteCallback(cClient_OnComplete); + OSD postData = new OSD(); + + // STEP 0 + Logger.Log("Requesting voice capability", Helpers.LogLevel.Info); + capClient.BeginGetResponse(postData, OSDFormat.Xml, 10000); + } + + /// + /// Request voice cap when changing regions + /// + void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e) + { + // We only care about the sim we are in. + if (e.Simulator != Client.Network.CurrentSim) + return; + + // Did we provision voice login info? + if (string.IsNullOrEmpty(voiceUser)) + { + // The startup steps are + // 0. Get voice account info + // 1. Start Daemon + // 2. Create TCP connection + // 3. Create Connector + // 4. Account login + // 5. Create session + + // Get the voice provisioning data + System.Uri vCap = + Client.Network.CurrentSim.Caps.CapabilityURI("ProvisionVoiceAccountRequest"); + + // Do we have voice capability? + if (vCap == null) + { + Logger.Log("Null voice capability after event queue running", Helpers.LogLevel.Warning); + } + else + { + RequestVoiceProvision(vCap); + } + + return; + } + else + { + // Change voice session for this region. + ParcelChanged(); + } + } + + + #region Participants + + void connector_OnSessionParticipantUpdatedEvent(object sender, ParticipantUpdatedEventArgs e) + { + VoiceSession s = FindSession(e.SessionHandle, false); + if (s == null) return; + s.ParticipantUpdate(e.URI, e.IsMuted, e.IsSpeaking, e.Volume, e.Energy); + } + + public string SIPFromUUID(UUID id) + { + return "sip:" + + nameFromID(id) + + "@" + + sipServer; + } + + private static string nameFromID(UUID id) + { + string result = null; + + if (id == UUID.Zero) + return result; + + // Prepending this apparently prevents conflicts with reserved names inside the vivox and diamondware code. + result = "x"; + + // Base64 encode and replace the pieces of base64 that are less compatible + // with e-mail local-parts. + // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet" + byte[] encbuff = id.GetBytes(); + result += Convert.ToBase64String(encbuff); + result = result.Replace('+', '-'); + result = result.Replace('/', '_'); + + return result; + } + + void connector_OnSessionParticipantAddedEvent(object sender, ParticipantAddedEventArgs e) + { + VoiceSession s = FindSession(e.SessionHandle, false); + if (s == null) + { + Logger.Log("Orphan participant", Helpers.LogLevel.Error); + return; + } + s.AddParticipant(e.URI); + } + + void connector_OnSessionParticipantRemovedEvent(object sender, ParticipantRemovedEventArgs e) + { + VoiceSession s = FindSession(e.SessionHandle, false); + if (s == null) return; + s.RemoveParticipant(e.URI); + } + #endregion + + #region Sessions + void connector_OnSessionAddedEvent(object sender, SessionAddedEventArgs e) + { + sessionHandle = e.SessionHandle; + + // Create our session context. + VoiceSession s = FindSession(sessionHandle, true); + s.RegionName = regionName; + + spatialSession = s; + + // Tell any user-facing code. + if (OnSessionCreate != null) + OnSessionCreate(s, null); + + Logger.Log("Added voice session in " + regionName, Helpers.LogLevel.Info); + } + + /// + /// Handle a change in session state + /// + void connector_OnSessionStateChangeEvent(object sender, SessionStateChangeEventArgs e) + { + VoiceSession s; + + switch (e.State) + { + case VoiceGateway.SessionState.Connected: + s = FindSession(e.SessionHandle, true); + sessionHandle = e.SessionHandle; + s.RegionName = regionName; + spatialSession = s; + + Logger.Log("Voice connected in " + regionName, Helpers.LogLevel.Info); + // Tell any user-facing code. + if (OnSessionCreate != null) + OnSessionCreate(s, null); + break; + + case VoiceGateway.SessionState.Disconnected: + s = FindSession(sessionHandle, false); + sessions.Remove(sessionHandle); + + if (s != null) + { + Logger.Log("Voice disconnected in " + s.RegionName, Helpers.LogLevel.Info); + + // Inform interested parties + if (OnSessionRemove != null) + OnSessionRemove(s, null); + + if (s == spatialSession) + spatialSession = null; + } + + // The previous session is now ended. Check for a new one and + // start it going. + if (nextParcelCap != null) + { + currentParcelCap = nextParcelCap; + nextParcelCap = null; + RequestParcelInfo(currentParcelCap); + } + break; + } + + + } + + /// + /// Close a voice session + /// + /// + internal void CloseSession(string sessionHandle) + { + if (!sessions.ContainsKey(sessionHandle)) + return; + + PosUpdating(false); + ReportConnectionState(ConnectionState.AccountLogin); + + // Clean up spatial pointers. + VoiceSession s = sessions[sessionHandle]; + if (s.IsSpatial) + { + spatialSession = null; + currentParcelCap = null; + } + + // Remove this session from the master session list + sessions.Remove(sessionHandle); + + // Let any user-facing code clean up. + if (OnSessionRemove != null) + OnSessionRemove(s, null); + + // Tell SLVoice to clean it up as well. + SessionTerminate(sessionHandle); + } + + /// + /// Locate a Session context from its handle + /// + /// Creates the session context if it does not exist. + VoiceSession FindSession(string sessionHandle, bool make) + { + if (sessions.ContainsKey(sessionHandle)) + return sessions[sessionHandle]; + + if (!make) return null; + + // Create a new session and add it to the sessions list. + VoiceSession s = new VoiceSession(this, sessionHandle); + + // Turn on position updating for spatial sessions + // (For now, only spatial sessions are supported) + if (s.IsSpatial) + PosUpdating(true); + + // Register the session by its handle + sessions.Add(sessionHandle, s); + return s; + } + + #endregion + + #region MinorResponses + + void connector_OnAuxAudioPropertiesEvent(object sender, AudioPropertiesEventArgs e) + { + if (OnVoiceMicTest != null) + OnVoiceMicTest(e.MicEnergy); + } + + #endregion + + private void ReportConnectionState(ConnectionState s) + { + if (OnVoiceConnectionChange == null) return; + + OnVoiceConnectionChange(s); + } + + /// + /// Handle completion of main voice cap request. + /// + /// + /// + /// + void cClient_OnComplete(OpenMetaverse.Http.CapsClient client, + OpenMetaverse.StructuredData.OSD result, + Exception error) + { + if (error != null) + { + Logger.Log("Voice cap error " + error.Message, Helpers.LogLevel.Error); + return; + } + + Logger.Log("Voice provisioned", Helpers.LogLevel.Info); + ReportConnectionState(ConnectionState.Provisioned); + + OpenMetaverse.StructuredData.OSDMap pMap = result as OpenMetaverse.StructuredData.OSDMap; + + // We can get back 4 interesting values: + // voice_sip_uri_hostname + // voice_account_server_name (actually a full URI) + // username + // password + if (pMap.ContainsKey("voice_sip_uri_hostname")) + sipServer = pMap["voice_sip_uri_hostname"].AsString(); + if (pMap.ContainsKey("voice_account_server_name")) + acctServer = pMap["voice_account_server_name"].AsString(); + voiceUser = pMap["username"].AsString(); + voicePassword = pMap["password"].AsString(); + + // Start the SLVoice daemon + slvoicePath = GetVoiceDaemonPath(); + + // Test if the executable exists + if (!System.IO.File.Exists(slvoicePath)) + { + Logger.Log("SLVoice is missing", Helpers.LogLevel.Error); + return; + } + + // STEP 1 + StartDaemon(slvoicePath, slvoiceArgs); + } + + #region Daemon + void connector_OnDaemonCouldntConnect() + { + Logger.Log("No voice daemon connect", Helpers.LogLevel.Error); + } + + void connector_OnDaemonCouldntRun() + { + Logger.Log("Daemon not started", Helpers.LogLevel.Error); + } + + /// + /// Daemon has started so connect to it. + /// + void connector_OnDaemonRunning() + { + OnDaemonRunning -= + new VoiceGateway.DaemonRunningCallback(connector_OnDaemonRunning); + + Logger.Log("Daemon started", Helpers.LogLevel.Info); + ReportConnectionState(ConnectionState.DaemonStarted); + + // STEP 2 + ConnectToDaemon(daemonNode, daemonPort); + + } + + /// + /// The daemon TCP connection is open. + /// + void connector_OnDaemonConnected() + { + Logger.Log("Daemon connected", Helpers.LogLevel.Info); + ReportConnectionState(ConnectionState.DaemonConnected); + + // The connector is what does the logging. + VoiceGateway.VoiceLoggingSettings vLog = + new VoiceGateway.VoiceLoggingSettings(); + +#if DEBUG_VOICE + vLog.Enabled = true; + vLog.FileNamePrefix = "OpenmetaverseVoice"; + vLog.FileNameSuffix = ".log"; + vLog.LogLevel = 4; +#endif + // STEP 3 + int reqId = ConnectorCreate( + "V2 SDK", // Magic value keeps SLVoice happy + acctServer, // Account manager server + 30000, 30099, // port range + vLog); + if (reqId < 0) + { + Logger.Log("No voice connector request", Helpers.LogLevel.Error); + } + } + + /// + /// Handle creation of the Connector. + /// + void connector_OnConnectorCreateResponse( + object sender, + VoiceGateway.VoiceConnectorEventArgs e) + { + Logger.Log("Voice daemon protocol started " + e.Message, Helpers.LogLevel.Info); + + connectionHandle = e.Handle; + + if (e.StatusCode != 0) + return; + + // STEP 4 + AccountLogin( + connectionHandle, + voiceUser, + voicePassword, + "VerifyAnswer", // This can also be "AutoAnswer" + "", // Default account management server URI + 10, // Throttle state changes + true); // Enable buddies and presence + } + #endregion + + void connector_OnAccountLoginResponse( + object sender, + VoiceGateway.VoiceAccountEventArgs e) + { + Logger.Log("Account Login " + e.Message, Helpers.LogLevel.Info); + accountHandle = e.AccountHandle; + ReportConnectionState(ConnectionState.AccountLogin); + ParcelChanged(); + } + + #region Audio devices + /// + /// Handle response to audio output device query + /// + void connector_OnAuxGetRenderDevicesResponse( + object sender, + VoiceGateway.VoiceDevicesEventArgs e) + { + outputDevices = e.Devices; + currentPlaybackDevice = e.CurrentDevice; + } + + /// + /// Handle response to audio input device query + /// + void connector_OnAuxGetCaptureDevicesResponse( + object sender, + VoiceGateway.VoiceDevicesEventArgs e) + { + inputDevices = e.Devices; + currentCaptureDevice = e.CurrentDevice; + } + + public string CurrentCaptureDevice + { + get { return currentCaptureDevice; } + set + { + currentCaptureDevice = value; + AuxSetCaptureDevice(value); + } + } + public string PlaybackDevice + { + get { return currentPlaybackDevice; } + set + { + currentPlaybackDevice = value; + AuxSetRenderDevice(value); + } + } + + public int MicLevel + { + set + { + ConnectorSetLocalMicVolume(connectionHandle, value); + } + } + public int SpkrLevel + { + set + { + ConnectorSetLocalSpeakerVolume(connectionHandle, value); + } + } + + public bool MicMute + { + set + { + ConnectorMuteLocalMic(connectionHandle, value); + } + } + + public bool SpkrMute + { + set + { + ConnectorMuteLocalSpeaker(connectionHandle, value); + } + } + + /// + /// Set audio test mode + /// + public bool TestMode + { + get { return testing; } + set + { + testing = value; + if (testing) + { + if (spatialSession != null) + { + spatialSession.Close(); + spatialSession = null; + } + AuxCaptureAudioStart(0); + } + else + { + AuxCaptureAudioStop(); + ParcelChanged(); + } + } + } + #endregion + + + + + /// + /// Set voice channel for new parcel + /// + /// + internal void ParcelChanged() + { + // Get the capability for this parcel. + Caps c = Client.Network.CurrentSim.Caps; + System.Uri pCap = c.CapabilityURI("ParcelVoiceInfoRequest"); + + if (pCap == null) + { + Logger.Log("Null voice capability", Helpers.LogLevel.Error); + return; + } + + // Parcel has changed. If we were already in a spatial session, we have to close it first. + if (spatialSession != null) + { + nextParcelCap = pCap; + CloseSession(spatialSession.Handle); + } + + // Not already in a session, so can start the new one. + RequestParcelInfo(pCap); + } + + private OpenMetaverse.Http.CapsClient parcelCap; + + /// + /// Request info from a parcel capability Uri. + /// + /// + + void RequestParcelInfo(Uri cap) + { + Logger.Log("Requesting region voice info", Helpers.LogLevel.Info); + + parcelCap = new OpenMetaverse.Http.CapsClient(cap); + parcelCap.OnComplete += + new OpenMetaverse.Http.CapsClient.CompleteCallback(pCap_OnComplete); + OSD postData = new OSD(); + + currentParcelCap = cap; + parcelCap.BeginGetResponse(postData, OSDFormat.Xml, 10000); + } + + /// + /// Receive parcel voice cap + /// + /// + /// + /// + void pCap_OnComplete(OpenMetaverse.Http.CapsClient client, + OpenMetaverse.StructuredData.OSD result, + Exception error) + { + parcelCap.OnComplete -= + new OpenMetaverse.Http.CapsClient.CompleteCallback(pCap_OnComplete); + parcelCap = null; + + if (error != null) + { + Logger.Log("Region voice cap " + error.Message, Helpers.LogLevel.Error); + return; + } + + OpenMetaverse.StructuredData.OSDMap pMap = result as OpenMetaverse.StructuredData.OSDMap; + + regionName = pMap["region_name"].AsString(); + ReportConnectionState(ConnectionState.RegionCapAvailable); + + if (pMap.ContainsKey("voice_credentials")) + { + OpenMetaverse.StructuredData.OSDMap cred = + pMap["voice_credentials"] as OpenMetaverse.StructuredData.OSDMap; + + if (cred.ContainsKey("channel_uri")) + spatialUri = cred["channel_uri"].AsString(); + if (cred.ContainsKey("channel_credentials")) + spatialCredentials = cred["channel_credentials"].AsString(); + } + + if (spatialUri == null || spatialUri == "") + { + // "No voice chat allowed here"); + return; + } + + Logger.Log("Voice connecting for region " + regionName, Helpers.LogLevel.Info); + + // STEP 5 + int reqId = SessionCreate( + accountHandle, + spatialUri, // uri + "", // Channel name seems to be always null + spatialCredentials, // spatialCredentials, // session password + true, // Join Audio + false, // Join Text + ""); + if (reqId < 0) + { + Logger.Log("Voice Session ReqID " + reqId.ToString(), Helpers.LogLevel.Error); + } + } + + #region Location Update + /// + /// Tell Vivox where we are standing + /// + /// This has to be called when we move or turn. + internal void UpdatePosition(AgentManager self) + { + // Get position in Global coordinates + Vector3d OMVpos = new Vector3d(self.GlobalPosition); + + // Do not send trivial updates. + if (OMVpos.ApproxEquals(oldPosition, 1.0)) + return; + + oldPosition = OMVpos; + + // Convert to the coordinate space that Vivox uses + // OMV X is East, Y is North, Z is up + // VVX X is East, Y is up, Z is South + position.Position = new Vector3d(OMVpos.X, OMVpos.Z, -OMVpos.Y); + + // TODO Rotate these two vectors + + // Get azimuth from the facing Quaternion. + // By definition, facing.W = Cos( angle/2 ) + double angle = 2.0 * Math.Acos(self.Movement.BodyRotation.W); + + position.LeftOrientation = new Vector3d(-1.0, 0.0, 0.0); + position.AtOrientation = new Vector3d((float)Math.Acos(angle), 0.0, -(float)Math.Asin(angle)); + + SessionSet3DPosition( + sessionHandle, + position, + position); + } + + /// + /// Start and stop updating out position. + /// + /// + internal void PosUpdating(bool go) + { + if (go) + posRestart.Set(); + else + posRestart.Reset(); + } + + private void PositionThreadBody() + { + while (true) + { + posRestart.WaitOne(); + Thread.Sleep(1500); + UpdatePosition(Client.Self); + } + } + #endregion + + } +} diff --git a/OpenMetaverse/Voice/VoiceDefinitions.cs b/OpenMetaverse/Voice/VoiceDefinitions.cs new file mode 100644 index 0000000..21fd722 --- /dev/null +++ b/OpenMetaverse/Voice/VoiceDefinitions.cs @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Xml; +using System.Xml.Serialization; + +namespace OpenMetaverse.Voice +{ + public partial class VoiceGateway + { + #region Enums + + public enum LoginState + { + LoggedOut = 0, + LoggedIn = 1, + Error = 4 + } + + public enum SessionState + { + Idle = 1, + Answering = 2, + InProgress = 3, + Connected = 4, + Disconnected = 5, + Hold = 6, + Refer = 7, + Ringing = 8 + } + + public enum ParticipantState + { + Idle = 1, + Pending = 2, + Incoming = 3, + Answering = 4, + InProgress = 5, + Ringing = 6, + Connected = 7, + Disconnecting = 8, + Disconnected = 9 + } + + public enum ParticipantType + { + User = 0, + Moderator = 1, + Focus = 2 + } + + public enum ResponseType + { + None = 0, + ConnectorCreate, + ConnectorInitiateShutdown, + MuteLocalMic, + MuteLocalSpeaker, + SetLocalMicVolume, + SetLocalSpeakerVolume, + GetCaptureDevices, + GetRenderDevices, + SetRenderDevice, + SetCaptureDevice, + CaptureAudioStart, + CaptureAudioStop, + SetMicLevel, + SetSpeakerLevel, + AccountLogin, + AccountLogout, + RenderAudioStart, + RenderAudioStop, + SessionCreate, + SessionConnect, + SessionTerminate, + SetParticipantVolumeForMe, + SetParticipantMuteForMe, + Set3DPosition + } + #endregion Enums + + #region Logging + + public class VoiceLoggingSettings + { + /// Enable logging + public bool Enabled; + /// The folder where any logs will be created + public string Folder; + /// This will be prepended to beginning of each log file + public string FileNamePrefix; + /// The suffix or extension to be appended to each log file + public string FileNameSuffix; + /// + /// 0: NONE - No logging + /// 1: ERROR - Log errors only + /// 2: WARNING - Log errors and warnings + /// 3: INFO - Log errors, warnings and info + /// 4: DEBUG - Log errors, warnings, info and debug + /// + public int LogLevel; + + /// + /// Constructor for default logging settings + /// + public VoiceLoggingSettings() + { + Enabled = false; + Folder = String.Empty; + FileNamePrefix = "Connector"; + FileNameSuffix = ".log"; + LogLevel = 0; + } + } + + #endregion Logging + + public class VoiceResponseEventArgs : EventArgs + { + public readonly ResponseType Type; + public readonly int ReturnCode; + public readonly int StatusCode; + public readonly string Message; + + // All Voice Response events carry these properties. + public VoiceResponseEventArgs(ResponseType type, int rcode, int scode, string text) + { + this.Type = type; + this.ReturnCode = rcode; + this.StatusCode = scode; + this.Message = text; + } + } + + #region Session Event Args + public class VoiceSessionEventArgs : VoiceResponseEventArgs + { + public readonly string SessionHandle; + + public VoiceSessionEventArgs(int rcode, int scode, string text, string shandle) : + base(ResponseType.SessionCreate, rcode, scode, text) + { + this.SessionHandle = shandle; + } + } + + public class NewSessionEventArgs : EventArgs + { + public readonly string AccountHandle; + public readonly string SessionHandle; + public readonly string URI; + public readonly string Name; + public readonly string AudioMedia; + + public NewSessionEventArgs(string AccountHandle, string SessionHandle, string URI, bool IsChannel, string Name, string AudioMedia) + { + this.AccountHandle = AccountHandle; + this.SessionHandle = SessionHandle; + this.URI = URI; + this.Name = Name; + this.AudioMedia = AudioMedia; + } + } + + public class SessionMediaEventArgs : EventArgs + { + public readonly string SessionHandle; + public readonly bool HasText; + public readonly bool HasAudio; + public readonly bool HasVideo; + public readonly bool Terminated; + + public SessionMediaEventArgs(string SessionHandle, bool HasText, bool HasAudio, bool HasVideo, bool Terminated) + { + this.SessionHandle = SessionHandle; + this.HasText = HasText; + this.HasAudio = HasAudio; + this.HasVideo = HasVideo; + this.Terminated = Terminated; + } + } + + public class SessionStateChangeEventArgs : EventArgs + { + public readonly string SessionHandle; + public readonly int StatusCode; + public readonly string StatusString; + public readonly SessionState State; + public readonly string URI; + public readonly bool IsChannel; + public readonly string ChannelName; + public SessionStateChangeEventArgs(string SessionHandle, int StatusCode, string StatusString, SessionState State, string URI, bool IsChannel, string ChannelName) + { + this.SessionHandle = SessionHandle; + this.StatusCode = StatusCode; + this.StatusString = StatusString; + this.State = State; + this.URI = URI; + this.IsChannel = IsChannel; + this.ChannelName = ChannelName; + } + } + + // Participants + public class ParticipantAddedEventArgs : EventArgs + { + public readonly string SessionHandle; + public readonly string SessionGroupHandle; + public readonly string URI; + public readonly string AccountName; + public readonly string DisplayName; + public readonly ParticipantType Type; + public readonly string Appllication; + public ParticipantAddedEventArgs( + string SessionGroupHandle, + string SessionHandle, + string ParticipantUri, + string AccountName, + string DisplayName, + ParticipantType type, + string Application) + { + this.SessionGroupHandle = SessionGroupHandle; + this.SessionHandle = SessionHandle; + this.URI = ParticipantUri; + this.AccountName = AccountName; + this.DisplayName = DisplayName; + this.Type = type; + this.Appllication = Application; + } + } + + public class ParticipantRemovedEventArgs : EventArgs + { + public readonly string SessionGroupHandle; + public readonly string SessionHandle; + public readonly string URI; + public readonly string AccountName; + public readonly string Reason; + + public ParticipantRemovedEventArgs( + string SessionGroupHandle, + string SessionHandle, + string ParticipantUri, + string AccountName, + string Reason) + { + this.SessionGroupHandle = SessionGroupHandle; + this.SessionHandle = SessionHandle; + this.URI = ParticipantUri; + this.AccountName = AccountName; + this.Reason = Reason; + } + } + + public class ParticipantStateChangeEventArgs : EventArgs + { + public readonly string SessionHandle; + public readonly int StatusCode; + public readonly string StatusString; + public readonly ParticipantState State; + public readonly string URI; + public readonly string AccountName; + public readonly string DisplayName; + public readonly ParticipantType Type; + + public ParticipantStateChangeEventArgs(string SessionHandle, int StatusCode, string StatusString, + ParticipantState State, string ParticipantURI, string AccountName, + string DisplayName, ParticipantType ParticipantType) + { + this.SessionHandle = SessionHandle; + this.StatusCode = StatusCode; + this.StatusString = StatusString; + this.State = State; + this.URI = ParticipantURI; + this.AccountName = AccountName; + this.DisplayName = DisplayName; + this.Type = ParticipantType; + } + } + + public class ParticipantPropertiesEventArgs : EventArgs + { + public readonly string SessionHandle; + public readonly string URI; + public readonly bool IsLocallyMuted; + public readonly bool IsModeratorMuted; + public readonly bool IsSpeaking; + public readonly int Volume; + public readonly float Energy; + + public ParticipantPropertiesEventArgs(string SessionHandle, string ParticipantURI, + bool IsLocallyMuted, bool IsModeratorMuted, bool IsSpeaking, int Volume, float Energy) + { + this.SessionHandle = SessionHandle; + this.URI = ParticipantURI; + this.IsLocallyMuted = IsLocallyMuted; + this.IsModeratorMuted = IsModeratorMuted; + this.IsSpeaking = IsSpeaking; + this.Volume = Volume; + this.Energy = Energy; + } + + } + + public class ParticipantUpdatedEventArgs : EventArgs + { + public readonly string SessionHandle; + public readonly string URI; + public readonly bool IsMuted; + public readonly bool IsSpeaking; + public readonly int Volume; + public readonly float Energy; + + public ParticipantUpdatedEventArgs(string sessionHandle, string URI, bool isMuted, bool isSpeaking, int volume, float energy) + { + this.SessionHandle = sessionHandle; + this.URI = URI; + this.IsMuted = isMuted; + this.IsSpeaking = isSpeaking; + this.Volume = volume; + this.Energy = energy; + } + } + + public class SessionAddedEventArgs : EventArgs + { + public readonly string SessionGroupHandle; + public readonly string SessionHandle; + public readonly string URI; + public readonly bool IsChannel; + public readonly bool IsIncoming; + + public SessionAddedEventArgs(string sessionGroupHandle, string sessionHandle, + string URI, bool isChannel, bool isIncoming) + { + this.SessionGroupHandle = sessionGroupHandle; + this.SessionHandle = sessionHandle; + this.URI = URI; + this.IsChannel = isChannel; + this.IsIncoming = isIncoming; + } + } + + public class SessionRemovedEventArgs : EventArgs + { + public readonly string SessionGroupHandle; + public readonly string SessionHandle; + public readonly string URI; + public SessionRemovedEventArgs( + string SessionGroupHandle, + string SessionHandle, + string Uri) + { + this.SessionGroupHandle = SessionGroupHandle; + this.SessionHandle = SessionHandle; + this.URI = Uri; + } + } + + public class SessionUpdatedEventArgs : EventArgs + { + public readonly string SessionGroupHandle; + public readonly string SessionHandle; + public readonly string URI; + public readonly bool IsMuted; + public readonly int Volume; + public readonly bool TransmitEnabled; + public readonly bool IsFocused; + public SessionUpdatedEventArgs(string SessionGroupHandle, + string SessionHandle, string URI, bool IsMuted, int Volume, + bool TransmitEnabled, bool IsFocused) + { + this.SessionGroupHandle = SessionGroupHandle; + this.SessionHandle = SessionHandle; + this.URI = URI; + this.IsMuted = IsMuted; + this.Volume = Volume; + this.TransmitEnabled = TransmitEnabled; + this.IsFocused = IsFocused; + } + + } + + public class SessionGroupAddedEventArgs : EventArgs + { + public readonly string AccountHandle; + public readonly string SessionGroupHandle; + public readonly string Type; + public SessionGroupAddedEventArgs(string acctHandle, string sessionGroupHandle, string type) + { + this.AccountHandle = acctHandle; + this.SessionGroupHandle = sessionGroupHandle; + this.Type = type; + } + } + #endregion Session Event Args + + #region Connector Delegates + public class VoiceConnectorEventArgs : VoiceResponseEventArgs + { + private readonly string m_Version; + private readonly string m_ConnectorHandle; + public string Version { get { return m_Version; } } + public string Handle { get { return m_ConnectorHandle; } } + + public VoiceConnectorEventArgs(int rcode, int scode, string text, string version, string handle) : + base(ResponseType.ConnectorCreate, rcode, scode, text) + { + m_Version = version; + m_ConnectorHandle = handle; + } + } + + #endregion Connector Delegates + + + #region Aux Event Args + public class VoiceDevicesEventArgs : VoiceResponseEventArgs + { + private readonly string m_CurrentDevice; + private readonly List m_Available; + public string CurrentDevice { get { return m_CurrentDevice; } } + public List Devices { get { return m_Available; } } + + public VoiceDevicesEventArgs(ResponseType type, int rcode, int scode, string text, string current, List avail) : + base(type, rcode, scode, text) + { + m_CurrentDevice = current; + m_Available = avail; + } + } + + + /// Audio Properties Events are sent after audio capture is started. These events are used to display a microphone VU meter + public class AudioPropertiesEventArgs : EventArgs + { + public readonly bool IsMicActive; + public readonly float MicEnergy; + public readonly int MicVolume; + public readonly int SpeakerVolume; + public AudioPropertiesEventArgs(bool MicIsActive, float MicEnergy, int MicVolume, int SpeakerVolume) + { + this.IsMicActive = MicIsActive; + this.MicEnergy = MicEnergy; + this.MicVolume = MicVolume; + this.SpeakerVolume = SpeakerVolume; + } + } + + #endregion Aux Event Args + + #region Account Event Args + public class VoiceAccountEventArgs : VoiceResponseEventArgs + { + private readonly string m_AccountHandle; + public string AccountHandle { get { return m_AccountHandle; } } + + public VoiceAccountEventArgs(int rcode, int scode, string text, string ahandle) : + base(ResponseType.AccountLogin, rcode, scode, text) + { + this.m_AccountHandle = ahandle; + } + } + + public class AccountLoginStateChangeEventArgs : EventArgs + { + public readonly string AccountHandle; + public readonly int StatusCode; + public readonly string StatusString; + public readonly LoginState State; + public AccountLoginStateChangeEventArgs(string AccountHandle, int StatusCode, string StatusString, LoginState State) + { + this.AccountHandle = AccountHandle; + this.StatusCode = StatusCode; + this.StatusString = StatusString; + this.State = State; + } + } + + #endregion Account Event Args + + /// + /// Event for most mundane request reposnses. + /// + public event EventHandler OnVoiceResponse; + + #region Session Events + public event EventHandler OnSessionCreateResponse; + public event EventHandler OnSessionNewEvent; + public event EventHandler OnSessionStateChangeEvent; + public event EventHandler OnSessionParticipantStateChangeEvent; + public event EventHandler OnSessionParticipantPropertiesEvent; + public event EventHandler OnSessionParticipantUpdatedEvent; + public event EventHandler OnSessionParticipantAddedEvent; + public event EventHandler OnSessionParticipantRemovedEvent; + public event EventHandler OnSessionGroupAddedEvent; + public event EventHandler OnSessionAddedEvent; + public event EventHandler OnSessionRemovedEvent; + public event EventHandler OnSessionUpdatedEvent; + public event EventHandler OnSessionMediaEvent; + #endregion Session Events + + #region Connector Events + + /// Response to Connector.Create request + public event EventHandler OnConnectorCreateResponse; + + #endregion Connector Events + + #region Aux Events + + /// Response to Aux.GetCaptureDevices request + public event EventHandler OnAuxGetCaptureDevicesResponse; + /// Response to Aux.GetRenderDevices request + public event EventHandler OnAuxGetRenderDevicesResponse; + + /// Audio Properties Events are sent after audio capture is started. + /// These events are used to display a microphone VU meter + public event EventHandler OnAuxAudioPropertiesEvent; + + #endregion Aux Events + + #region Account Events + + /// Response to Account.Login request + public event EventHandler OnAccountLoginResponse; + + /// This event message is sent whenever the login state of the + /// particular Account has transitioned from one value to another + public event EventHandler OnAccountLoginStateChangeEvent; + + #endregion Account Events + + #region XML Serialization Classes + + private XmlSerializer EventSerializer = new XmlSerializer(typeof(VoiceEvent)); + private XmlSerializer ResponseSerializer = new XmlSerializer(typeof(VoiceResponse)); + + [XmlRoot("Event")] + public class VoiceEvent + { + [XmlAttribute("type")] + public string Type; + public string AccountHandle; + public string Application; + public string StatusCode; + public string StatusString; + public string State; + public string SessionHandle; + public string SessionGroupHandle; + public string URI; + public string Uri; // Yes, they send it with both capitalizations + public string IsChannel; + public string IsIncoming; + public string Incoming; + public string IsMuted; + public string Name; + public string AudioMedia; + public string ChannelName; + public string ParticipantUri; + public string AccountName; + public string DisplayName; + public string ParticipantType; + public string IsLocallyMuted; + public string IsModeratorMuted; + public string IsSpeaking; + public string Volume; + public string Energy; + public string MicIsActive; + public string MicEnergy; + public string MicVolume; + public string SpeakerVolume; + public string HasText; + public string HasAudio; + public string HasVideo; + public string Terminated; + public string Reason; + public string TransmitEnabled; + public string IsFocused; + } + + [XmlRoot("Response")] + public class VoiceResponse + { + [XmlAttribute("requestId")] + public string RequestId; + [XmlAttribute("action")] + public string Action; + public string ReturnCode; + public VoiceResponseResults Results; + public VoiceInputXml InputXml; + } + + public class CaptureDevice + { + public string Device; + } + + public class RenderDevice + { + public string Device; + } + + public class VoiceResponseResults + { + public string VersionID; + public string StatusCode; + public string StatusString; + public string ConnectorHandle; + public string AccountHandle; + public string SessionHandle; + public List CaptureDevices; + public CaptureDevice CurrentCaptureDevice; + public List RenderDevices; + public RenderDevice CurrentRenderDevice; + } + + public class VoiceInputXml + { + public VoiceRequest Request; + } + + [XmlRoot("Request")] + public class VoiceRequest + { + [XmlAttribute("requestId")] + public string RequestId; + [XmlAttribute("action")] + public string Action; + public string RenderDeviceSpecifier; + public string CaptureDeviceSpecifier; + public string Duration; + public string Level; + public string ClientName; + public string AccountManagementServer; + public string MinimumPort; + public string MaximumPort; + public VoiceLoggingSettings Logging; + public string ConnectorHandle; + public string Value; + public string AccountName; + public string AccountPassword; + public string AudioSessionAnswerMode; + public string AccountURI; + public string ParticipantPropertyFrequency; + public string EnableBuddiesAndPresence; + public string URI; + public string Name; + public string Password; + public string JoinAudio; + public string JoinText; + public string PasswordHashAlgorithm; + public string SoundFilePath; + public string Loop; + public string SessionHandle; + public string OrientationType; + public VoicePosition SpeakerPosition; + public VoicePosition ListenerPosition; + public string ParticipantURI; + public string Volume; + } + + #endregion XML Serialization Classes + } + + public class VoicePosition + { + /// Positional vector of the users position + public Vector3d Position; + /// Velocity vector of the position + public Vector3d Velocity; + /// At Orientation (X axis) of the position + public Vector3d AtOrientation; + /// Up Orientation (Y axis) of the position + public Vector3d UpOrientation; + /// Left Orientation (Z axis) of the position + public Vector3d LeftOrientation; + } + +} diff --git a/OpenMetaverse/Voice/VoiceGateway.cs b/OpenMetaverse/Voice/VoiceGateway.cs new file mode 100644 index 0000000..76e4117 --- /dev/null +++ b/OpenMetaverse/Voice/VoiceGateway.cs @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Sockets; +using System.Diagnostics; +using System.Threading; +using System.Text; + +namespace OpenMetaverse.Voice +{ + public partial class VoiceGateway + { + public delegate void DaemonRunningCallback(); + public delegate void DaemonExitedCallback(); + public delegate void DaemonCouldntRunCallback(); + public delegate void DaemonConnectedCallback(); + public delegate void DaemonDisconnectedCallback(); + public delegate void DaemonCouldntConnectCallback(); + + public event DaemonRunningCallback OnDaemonRunning; + public event DaemonExitedCallback OnDaemonExited; + public event DaemonCouldntRunCallback OnDaemonCouldntRun; + public event DaemonConnectedCallback OnDaemonConnected; + public event DaemonDisconnectedCallback OnDaemonDisconnected; + public event DaemonCouldntConnectCallback OnDaemonCouldntConnect; + + public bool DaemonIsRunning { get { return daemonIsRunning; } } + public bool DaemonIsConnected { get { return daemonIsConnected; } } + public int RequestId { get { return requestId; } } + + protected Process daemonProcess; + protected ManualResetEvent daemonLoopSignal = new ManualResetEvent(false); + protected TCPPipe daemonPipe; + protected bool daemonIsRunning = false; + protected bool daemonIsConnected = false; + protected int requestId = 0; + + #region Daemon Management + + /// + /// Starts a thread that keeps the daemon running + /// + /// + /// + public void StartDaemon(string path, string args) + { + StopDaemon(); + daemonLoopSignal.Set(); + + Thread thread = new Thread(new ThreadStart(delegate() + { + while (daemonLoopSignal.WaitOne(500, false)) + { + daemonProcess = new Process(); + daemonProcess.StartInfo.FileName = path; + daemonProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(path); + daemonProcess.StartInfo.Arguments = args; + daemonProcess.StartInfo.UseShellExecute = false; + + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + string ldPath = string.Empty; + try + { + ldPath = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH"); + } + catch { } + string newLdPath = daemonProcess.StartInfo.WorkingDirectory; + if (!string.IsNullOrEmpty(ldPath)) + newLdPath += ":" + ldPath; + daemonProcess.StartInfo.EnvironmentVariables.Add("LD_LIBRARY_PATH", newLdPath); + } + + Logger.DebugLog("Voice folder: " + daemonProcess.StartInfo.WorkingDirectory); + Logger.DebugLog(path + " " + args); + bool ok = true; + + if (!File.Exists(path)) + ok = false; + + if (ok) + { + // Attempt to start the process + if (!daemonProcess.Start()) + ok = false; + } + + if (!ok) + { + daemonIsRunning = false; + daemonLoopSignal.Reset(); + + if (OnDaemonCouldntRun != null) + { + try { OnDaemonCouldntRun(); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } + } + + return; + } + else + { + Thread.Sleep(2000); + daemonIsRunning = true; + if (OnDaemonRunning != null) + { + try { OnDaemonRunning(); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } + } + + Logger.DebugLog("Started voice daemon, waiting for exit..."); + daemonProcess.WaitForExit(); + Logger.DebugLog("Voice daemon exited"); + daemonIsRunning = false; + + if (OnDaemonExited != null) + { + try { OnDaemonExited(); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } + } + } + } + })); + + thread.Name = "VoiceDaemonController"; + thread.IsBackground = true; + thread.Start(); + } + + /// + /// Stops the daemon and the thread keeping it running + /// + public void StopDaemon() + { + daemonLoopSignal.Reset(); + if (daemonProcess != null) + { + try + { + daemonProcess.Kill(); + } + catch (InvalidOperationException ex) + { + Logger.Log("Failed to stop the voice daemon", Helpers.LogLevel.Error, ex); + } + } + } + + /// + /// + /// + /// + /// + /// + public bool ConnectToDaemon(string address, int port) + { + daemonIsConnected = false; + + daemonPipe = new TCPPipe(); + daemonPipe.OnDisconnected += + delegate(SocketException e) + { + if (OnDaemonDisconnected != null) + { + try { OnDaemonDisconnected(); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, null, ex); } + } + }; + daemonPipe.OnReceiveLine += new TCPPipe.OnReceiveLineCallback(daemonPipe_OnReceiveLine); + + SocketException se = daemonPipe.Connect(address, port); + if (se == null) + { + daemonIsConnected = true; + + if (OnDaemonConnected != null) + { + try { OnDaemonConnected(); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } + } + + return true; + } + else + { + daemonIsConnected = false; + + if (OnDaemonCouldntConnect != null) + { + try { OnDaemonCouldntConnect(); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } + } + + Logger.Log("Voice daemon connection failed: " + se.Message, Helpers.LogLevel.Error); + return false; + } + } + + #endregion Daemon Management + + public int Request(string action) + { + return Request(action, null); + } + + public int Request(string action, string requestXML) + { + int returnId = requestId; + if (daemonIsConnected) + { + StringBuilder sb = new StringBuilder(); + sb.Append(String.Format(""); + } + else + { + sb.Append(">"); + sb.Append(requestXML); + sb.Append(""); + } + sb.Append("\n\n\n"); + +#if DEBUG + Logger.Log("Request: " + sb.ToString(), Helpers.LogLevel.Debug); +#endif + try + { + daemonPipe.SendData(Encoding.ASCII.GetBytes(sb.ToString())); + } + catch + { + returnId = -1; + } + + return returnId; + } + else + { + return -1; + } + } + + public static string MakeXML(string name, string text) + { + if (string.IsNullOrEmpty(text)) + return string.Format("<{0} />", name); + else + return string.Format("<{0}>{1}", name, text); + } + + private void daemonPipe_OnReceiveLine(string line) + { +#if DEBUG + Logger.Log(line, Helpers.LogLevel.Debug); +#endif + + if (line.Substring(0, 10) == "(); + + if (rsp.Results.CaptureDevices.Count == 0 || rsp.Results.CurrentCaptureDevice == null) + break; + + foreach (CaptureDevice device in rsp.Results.CaptureDevices) + inputDevices.Add(device.Device); + currentCaptureDevice = rsp.Results.CurrentCaptureDevice.Device; + + if (OnAuxGetCaptureDevicesResponse != null && rsp.Results.CaptureDevices.Count > 0) + { + OnAuxGetCaptureDevicesResponse( + rsp.InputXml.Request, + new VoiceDevicesEventArgs( + ResponseType.GetCaptureDevices, + int.Parse(rsp.ReturnCode), + int.Parse(rsp.Results.StatusCode), + rsp.Results.StatusString, + rsp.Results.CurrentCaptureDevice.Device, + inputDevices)); + } + break; + case "Aux.GetRenderDevices.1": + outputDevices = new List(); + + if (rsp.Results.RenderDevices.Count == 0 || rsp.Results.CurrentRenderDevice == null) + break; + + foreach (RenderDevice device in rsp.Results.RenderDevices) + outputDevices.Add(device.Device); + + + currentPlaybackDevice = rsp.Results.CurrentRenderDevice.Device; + + if (OnAuxGetRenderDevicesResponse != null) + { + OnAuxGetRenderDevicesResponse( + rsp.InputXml.Request, + new VoiceDevicesEventArgs( + ResponseType.GetCaptureDevices, + int.Parse(rsp.ReturnCode), + int.Parse(rsp.Results.StatusCode), + rsp.Results.StatusString, + rsp.Results.CurrentRenderDevice.Device, + outputDevices)); + } + break; + + case "Account.Login.1": + if (OnAccountLoginResponse != null) + { + OnAccountLoginResponse(rsp.InputXml.Request, + new VoiceAccountEventArgs( + int.Parse(rsp.ReturnCode), + int.Parse(rsp.Results.StatusCode), + rsp.Results.StatusString, + rsp.Results.AccountHandle)); + } + break; + + case "Session.Create.1": + if (OnSessionCreateResponse != null) + { + OnSessionCreateResponse( + rsp.InputXml.Request, + new VoiceSessionEventArgs( + int.Parse(rsp.ReturnCode), + int.Parse(rsp.Results.StatusCode), + rsp.Results.StatusString, + rsp.Results.SessionHandle)); + } + break; + + // All the remaining responses below this point just report status, + // so they all share the same Event. Most are useful only for + // detecting coding errors. + case "Connector.InitiateShutdown.1": + genericResponse = ResponseType.ConnectorInitiateShutdown; + break; + case "Aux.SetRenderDevice.1": + genericResponse = ResponseType.SetRenderDevice; + break; + case "Connector.MuteLocalMic.1": + genericResponse = ResponseType.MuteLocalMic; + break; + case "Connector.MuteLocalSpeaker.1": + genericResponse = ResponseType.MuteLocalSpeaker; + break; + case "Connector.SetLocalMicVolume.1": + genericResponse = ResponseType.SetLocalMicVolume; + break; + case "Connector.SetLocalSpeakerVolume.1": + genericResponse = ResponseType.SetLocalSpeakerVolume; + break; + case "Aux.SetCaptureDevice.1": + genericResponse = ResponseType.SetCaptureDevice; + break; + case "Session.RenderAudioStart.1": + genericResponse = ResponseType.RenderAudioStart; + break; + case "Session.RenderAudioStop.1": + genericResponse = ResponseType.RenderAudioStop; + break; + case "Aux.CaptureAudioStart.1": + genericResponse = ResponseType.CaptureAudioStart; + break; + case "Aux.CaptureAudioStop.1": + genericResponse = ResponseType.CaptureAudioStop; + break; + case "Aux.SetMicLevel.1": + genericResponse = ResponseType.SetMicLevel; + break; + case "Aux.SetSpeakerLevel.1": + genericResponse = ResponseType.SetSpeakerLevel; + break; + case "Account.Logout.1": + genericResponse = ResponseType.AccountLogout; + break; + case "Session.Connect.1": + genericResponse = ResponseType.SessionConnect; + break; + case "Session.Terminate.1": + genericResponse = ResponseType.SessionTerminate; + break; + case "Session.SetParticipantVolumeForMe.1": + genericResponse = ResponseType.SetParticipantVolumeForMe; + break; + case "Session.SetParticipantMuteForMe.1": + genericResponse = ResponseType.SetParticipantMuteForMe; + break; + case "Session.Set3DPosition.1": + genericResponse = ResponseType.Set3DPosition; + break; + default: + Logger.Log("Unimplemented response from the voice daemon: " + line, Helpers.LogLevel.Error); + break; + } + + // Send the Response Event for all the simple cases. + if (genericResponse != ResponseType.None && OnVoiceResponse != null) + { + OnVoiceResponse(rsp.InputXml.Request, + new VoiceResponseEventArgs( + genericResponse, + int.Parse(rsp.ReturnCode), + int.Parse(rsp.Results.StatusCode), + rsp.Results.StatusString)); + } + } + else if (line.Substring(0, 7) == "c1_m1000xrjiQgi95QhCzH_D6ZJ8c5A== + break; + + case "MediaStreamUpdatedEvent": + // TODO c1_m1000xrjiQgi95QhCzH_D6ZJ8c5A==_sg0 + // c1_m1000xrjiQgi95QhCzH_D6ZJ8c5A==0 + //01false + + break; + + default: + Logger.Log("Unimplemented event from the voice daemon: " + line, Helpers.LogLevel.Error); + break; + } + } + else + { + Logger.Log("Unrecognized data from the voice daemon: " + line, Helpers.LogLevel.Error); + } + } + } +} diff --git a/OpenMetaverse/Voice/VoiceParticipant.cs b/OpenMetaverse/Voice/VoiceParticipant.cs new file mode 100644 index 0000000..73ed2cd --- /dev/null +++ b/OpenMetaverse/Voice/VoiceParticipant.cs @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace OpenMetaverse.Voice +{ + public class VoiceParticipant + { + private string Sip; + private string AvatarName { get; set; } + private UUID id; + + private bool muted; + private int volume; + private VoiceSession session; + private float energy; + + public float Energy { get { return energy; } } + private bool speaking; + public bool IsSpeaking { get { return speaking; } } + public string URI { get { return Sip; } } + public UUID ID { get { return id; } } + + public VoiceParticipant(string puri, VoiceSession s) + { + id = IDFromName(puri); + Sip = puri; + session = s; + } + + /// + /// Extract the avatar UUID encoded in a SIP URI + /// + /// + /// + public static UUID IDFromName(string inName) + { + // The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com" + // If it is, convert to a bare name before doing the transform. + string name = nameFromsipURI(inName); + + // Doesn't look like a SIP URI, assume it's an actual name. + if (name == null) + name = inName; + + // This will only work if the name is of the proper form. + // As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is: + // "xFnPP04IpREWNkuw1cOXlhw==" + + if ((name.Length == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '=')) + { + // The name appears to have the right form. + + // Reverse the transforms done by nameFromID + string temp = name.Replace('-', '+'); + temp = temp.Replace('_', '/'); + + byte[] binary = Convert.FromBase64String(temp.Substring(1)); + UUID u = UUID.Zero; + u.FromBytes(binary, 0); + return u; + } + + return UUID.Zero; + } + + private static string Encode64(string str) + { + byte[] encbuff = System.Text.Encoding.UTF8.GetBytes(str); + return Convert.ToBase64String(encbuff); + } + private static byte[] Decode64(string str) + { + return Convert.FromBase64String(str); + // return System.Text.Encoding.UTF8.GetString(decbuff); + } + + private static string nameFromsipURI(string uri) + { + Regex sip = new Regex("^sip:([^@]*)@.*$"); + Match m = sip.Match(uri); + if (m.Success) + { + GroupCollection g = m.Groups; + return g[1].Value; + } + + return null; + } + + public string Name + { + get { return AvatarName; } + set { AvatarName = value; } + } + + public bool IsMuted + { + get { return muted; } + set + { + muted = value; + StringBuilder sb = new StringBuilder(); + sb.Append(OpenMetaverse.Voice.VoiceGateway.MakeXML("SessionHandle", session.Handle)); + sb.Append(OpenMetaverse.Voice.VoiceGateway.MakeXML("ParticipantURI", Sip)); + sb.Append(OpenMetaverse.Voice.VoiceGateway.MakeXML("Mute", muted ? "1" : "0")); + session.Connector.Request("Session.SetParticipantMuteForMe.1", sb.ToString()); + } + } + + public int Volume + { + get { return volume; } + set + { + volume = value; + StringBuilder sb = new StringBuilder(); + sb.Append(OpenMetaverse.Voice.VoiceGateway.MakeXML("SessionHandle", session.Handle)); + sb.Append(OpenMetaverse.Voice.VoiceGateway.MakeXML("ParticipantURI", Sip)); + sb.Append(OpenMetaverse.Voice.VoiceGateway.MakeXML("Volume", volume.ToString())); + session.Connector.Request("Session.SetParticipantVolumeForMe.1", sb.ToString()); + } + } + + internal void SetProperties(bool speak, bool mute, float en) + { + speaking = speak; + muted = mute; + energy = en; + } + } +} + diff --git a/OpenMetaverse/Voice/VoiceSession.cs b/OpenMetaverse/Voice/VoiceSession.cs new file mode 100644 index 0000000..92e5512 --- /dev/null +++ b/OpenMetaverse/Voice/VoiceSession.cs @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.Voice +{ + /// + /// Represents a single Voice Session to the Vivox service. + /// + public class VoiceSession + { + private string m_Handle; + private static Dictionary knownParticipants; + public string RegionName; + private bool m_spatial; + public bool IsSpatial { get { return m_spatial; } } + private VoiceGateway connector; + + public VoiceGateway Connector { get { return connector; } } + public string Handle { get { return m_Handle; } } + + public event System.EventHandler OnParticipantAdded; + public event System.EventHandler OnParticipantUpdate; + public event System.EventHandler OnParticipantRemoved; + + public VoiceSession(VoiceGateway conn, string handle) + { + m_Handle = handle; + connector = conn; + + m_spatial = true; + knownParticipants = new Dictionary(); + } + + /// + /// Close this session. + /// + internal void Close() + { + + knownParticipants.Clear(); + } + + internal void ParticipantUpdate(string URI, + bool isMuted, + bool isSpeaking, + int volume, + float energy) + { + lock (knownParticipants) + { + // Locate in this session + VoiceParticipant p = FindParticipant(URI); + if (p == null) return; + + // Set properties + p.SetProperties(isSpeaking, isMuted, energy); + + // Inform interested parties. + if (OnParticipantUpdate != null) + OnParticipantUpdate(p, null); + } + } + + internal void AddParticipant(string URI) + { + lock (knownParticipants) + { + VoiceParticipant p = FindParticipant(URI); + + // We expect that to come back null. If it is not + // null, this is a duplicate + if (p != null) + { + return; + } + + // It was not found, so add it. + p = new VoiceParticipant(URI, this); + knownParticipants.Add(URI, p); + + /* TODO + // Fill in the name. + if (p.Name == null || p.Name.StartsWith("Loading...")) + p.Name = control.instance.getAvatarName(p.ID); + return p; + */ + + // Inform interested parties. + if (OnParticipantAdded != null) + OnParticipantAdded(p, null); + } + } + + internal void RemoveParticipant(string URI) + { + lock (knownParticipants) + { + VoiceParticipant p = FindParticipant(URI); + if (p == null) return; + + // Remove from list for this session. + knownParticipants.Remove(URI); + + // Inform interested parties. + if (OnParticipantRemoved != null) + OnParticipantRemoved(p, null); + } + } + + /// + /// Look up an existing Participants in this session + /// + /// + /// + private VoiceParticipant FindParticipant(string puri) + { + if (knownParticipants.ContainsKey(puri)) + return knownParticipants[puri]; + + return null; + } + + public void Set3DPosition(VoicePosition SpeakerPosition, VoicePosition ListenerPosition) + { + connector.SessionSet3DPosition(m_Handle, SpeakerPosition, ListenerPosition); + } + } + + public partial class VoiceGateway + { + /// + /// Create a Session + /// Sessions typically represent a connection to a media session with one or more + /// participants. This is used to generate an ‘outbound’ call to another user or + /// channel. The specifics depend on the media types involved. A session handle is + /// required to control the local user functions within the session (or remote + /// users if the current account has rights to do so). Currently creating a + /// session automatically connects to the audio media, there is no need to call + /// Session.Connect at this time, this is reserved for future use. + /// + /// Handle returned from successful Connector ‘create’ request + /// This is the URI of the terminating point of the session (ie who/what is being called) + /// This is the display name of the entity being called (user or channel) + /// Only needs to be supplied when the target URI is password protected + /// This indicates the format of the password as passed in. This can either be + /// “ClearText” or “SHA1UserName”. If this element does not exist, it is assumed to be “ClearText”. If it is + /// “SHA1UserName”, the password as passed in is the SHA1 hash of the password and username concatenated together, + /// then base64 encoded, with the final “=” character stripped off. + /// + /// + /// + public int SessionCreate(string AccountHandle, string URI, string Name, string Password, + bool JoinAudio, bool JoinText, string PasswordHashAlgorithm) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("AccountHandle", AccountHandle)); + sb.Append(VoiceGateway.MakeXML("URI", URI)); + sb.Append(VoiceGateway.MakeXML("Name", Name)); + if (Password != null && Password != "") + { + sb.Append(VoiceGateway.MakeXML("Password", Password)); + sb.Append(VoiceGateway.MakeXML("PasswordHashAlgorithm", PasswordHashAlgorithm)); + } + sb.Append(VoiceGateway.MakeXML("ConnectAudio", JoinAudio ? "true" : "false")); + sb.Append(VoiceGateway.MakeXML("ConnectText", JoinText ? "true" : "false")); + sb.Append(VoiceGateway.MakeXML("JoinAudio", JoinAudio ? "true" : "false")); + sb.Append(VoiceGateway.MakeXML("JoinText", JoinText ? "true" : "false")); + sb.Append(VoiceGateway.MakeXML("VoiceFontID", "0")); + + return Request("Session.Create.1", sb.ToString()); + } + + /// + /// Used to accept a call + /// + /// SessionHandle such as received from SessionNewEvent + /// "default" + /// + public int SessionConnect(string SessionHandle, string AudioMedia) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("SessionHandle", SessionHandle)); + sb.Append(VoiceGateway.MakeXML("AudioMedia", AudioMedia)); + return Request("Session.Connect.1", sb.ToString()); + } + + /// + /// This command is used to start the audio render process, which will then play + /// the passed in file through the selected audio render device. This command + /// should not be issued if the user is on a call. + /// + /// The fully qualified path to the sound file. + /// True if the file is to be played continuously and false if it is should be played once. + /// + public int SessionRenderAudioStart(string SoundFilePath, bool Loop) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("SoundFilePath", SoundFilePath)); + sb.Append(VoiceGateway.MakeXML("Loop", Loop ? "1" : "0")); + return Request("Session.RenderAudioStart.1", sb.ToString()); + } + + /// + /// This command is used to stop the audio render process. + /// + /// The fully qualified path to the sound file issued in the start render command. + /// + public int SessionRenderAudioStop(string SoundFilePath) + { + string RequestXML = VoiceGateway.MakeXML("SoundFilePath", SoundFilePath); + return Request("Session.RenderAudioStop.1", RequestXML); + } + + /// + /// This is used to ‘end’ an established session (i.e. hang-up or disconnect). + /// + /// Handle returned from successful Session ‘create’ request or a SessionNewEvent + /// + public int SessionTerminate(string SessionHandle) + { + string RequestXML = VoiceGateway.MakeXML("SessionHandle", SessionHandle); + return Request("Session.Terminate.1", RequestXML); + } + + /// + /// Set the combined speaking and listening position in 3D space. + /// + /// Handle returned from successful Session ‘create’ request or a SessionNewEvent + /// Speaking position + /// Listening position + /// + public int SessionSet3DPosition(string SessionHandle, VoicePosition SpeakerPosition, VoicePosition ListenerPosition) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("SessionHandle", SessionHandle)); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", SpeakerPosition.Position.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.Position.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.Position.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", SpeakerPosition.Velocity.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.Velocity.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.Velocity.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", SpeakerPosition.AtOrientation.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.AtOrientation.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.AtOrientation.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", SpeakerPosition.UpOrientation.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.UpOrientation.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.UpOrientation.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", SpeakerPosition.LeftOrientation.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.LeftOrientation.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.LeftOrientation.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", ListenerPosition.Position.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.Position.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.Position.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", ListenerPosition.Velocity.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.Velocity.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.Velocity.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", ListenerPosition.AtOrientation.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.AtOrientation.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.AtOrientation.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", ListenerPosition.UpOrientation.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.UpOrientation.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.UpOrientation.Z.ToString())); + sb.Append(""); + sb.Append(""); + sb.Append(VoiceGateway.MakeXML("X", ListenerPosition.LeftOrientation.X.ToString())); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.LeftOrientation.Y.ToString())); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.LeftOrientation.Z.ToString())); + sb.Append(""); + sb.Append(""); + return Request("Session.Set3DPosition.1", sb.ToString()); + } + + /// + /// Set User Volume for a particular user. Does not affect how other users hear that user. + /// + /// Handle returned from successful Session ‘create’ request or a SessionNewEvent + /// + /// The level of the audio, a number between -100 and 100 where 0 represents ‘normal’ speaking volume + /// + public int SessionSetParticipantVolumeForMe(string SessionHandle, string ParticipantURI, int Volume) + { + StringBuilder sb = new StringBuilder(); + sb.Append(VoiceGateway.MakeXML("SessionHandle", SessionHandle)); + sb.Append(VoiceGateway.MakeXML("ParticipantURI", ParticipantURI)); + sb.Append(VoiceGateway.MakeXML("Volume", Volume.ToString())); + return Request("Session.SetParticipantVolumeForMe.1", sb.ToString()); + } + } +} diff --git a/OpenMetaverse/WorkPool.cs b/OpenMetaverse/WorkPool.cs new file mode 100644 index 0000000..55d8cf1 --- /dev/null +++ b/OpenMetaverse/WorkPool.cs @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#define SMARTHREADPOOL_REF + +using System; +using System.IO; +using System.Reflection; + +#if SMARTHREADPOOL_REF +using Amib.Threading; +#else +using System.Threading; +#endif + +namespace OpenMetaverse +{ + +// Use statically referenced SmartThreadPool.dll +#if SMARTHREADPOOL_REF + public static class WorkPool + { + internal static SmartThreadPool Pool = null; + + public static bool Init(bool useSmartThredPool) + { + if (Pool == null) + { + STPStartInfo param = new STPStartInfo(); + param.MinWorkerThreads = 2; + param.MaxWorkerThreads = 50; + param.ThreadPoolName = "LibOpenMetaverse Main ThreadPool"; + param.AreThreadsBackground = true; + + Pool = new SmartThreadPool(param); + } + return true; + } + + public static void Shutdown() + { + if (Pool != null) + { + Pool.Shutdown(); + Pool = null; + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback) + { + if (Pool != null) + { + Pool.QueueWorkItem(state => { callback.Invoke(state); return null; }); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(state => callback.Invoke(state)); + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback, object state) + { + if (Pool != null) + { + Pool.QueueWorkItem(sync => { callback.Invoke(sync); return null; }, state); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + } + } + +#else + + // Try to load SmartThreadPool.dll during initialization + // Fallback to System.Threading.ThreadPool if that fails + public static class WorkPoolDynamic + { + internal static object Pool = null; + + private static Type SmartThreadPoolType; + private static Type WorkItemCallbackType; + private static MethodInfo QueueWorkItemFunc, QueueWorkItemFunc2; + private static MethodInfo ShutdownFunc; + private static Func Invoker; + + public static bool Init() + { + try + { + string dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + Assembly assembly = Assembly.LoadFile(Path.Combine(dir, "SmartThreadPool.dll")); + Type STPStartInfo = assembly.GetType("Amib.Threading.STPStartInfo"); + SmartThreadPoolType = assembly.GetType("Amib.Threading.SmartThreadPool"); + WorkItemCallbackType = assembly.GetType("Amib.Threading.WorkItemCallback"); + var param = Activator.CreateInstance(STPStartInfo); + STPStartInfo.GetProperty("MinWorkerThreads").SetValue(param, 2, null); + STPStartInfo.GetProperty("MaxWorkerThreads").SetValue(param, 50, null); + STPStartInfo.GetProperty("ThreadPoolName").SetValue(param, "LibOpenMetaverse Main ThreadPool", null); + STPStartInfo.GetProperty("AreThreadsBackground").SetValue(param, true, null); + STPStartInfo.GetProperty("MinWorkerThreads").SetValue(param, 2, null); + Pool = Activator.CreateInstance(SmartThreadPoolType, new object[] { param }); + QueueWorkItemFunc = SmartThreadPoolType.GetMethod("QueueWorkItem", new Type[] { WorkItemCallbackType }); + QueueWorkItemFunc2 = SmartThreadPoolType.GetMethod("QueueWorkItem", new Type[] { WorkItemCallbackType, typeof(object) }); + ShutdownFunc = SmartThreadPoolType.GetMethod("Shutdown", new Type[] { }); + + Invoker = (inv, state) => + { + inv.Invoke(state); + return null; + }; + + return true; + } + catch + { + Pool = null; + return false; + } + } + + public static void Shutdown() + { + if (Pool != null) + { + ShutdownFunc.Invoke(Pool, null); + Pool = null; + } + } + + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback) + { + if (Pool != null) + { + QueueWorkItemFunc.Invoke(Pool, new object[] { Delegate.CreateDelegate(WorkItemCallbackType, callback, Invoker.Method) }); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(state => callback.Invoke(state)); + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback, object state) + { + if (Pool != null) + { + QueueWorkItemFunc2.Invoke(Pool, new object[] { Delegate.CreateDelegate(WorkItemCallbackType, callback, Invoker.Method), state }); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + } + } + + + public static class WorkPool + { + private static bool UseSmartThreadPool = false; + + public static bool Init(bool useSmartThredPool) + { + if (useSmartThredPool) + { + if (WorkPoolDynamic.Init()) + { + UseSmartThreadPool = true; + return true; + } + return false; + } + return true; + } + + public static void Shutdown() + { + if (UseSmartThreadPool) + { + WorkPoolDynamic.Shutdown(); + UseSmartThreadPool = false; + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback) + { + if (UseSmartThreadPool) + { + WorkPoolDynamic.QueueUserWorkItem(sync => callback.Invoke(sync)); + } + else + { + ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync)); + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback, object state) + { + if (UseSmartThreadPool) + { + WorkPoolDynamic.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + else + { + ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + } + } +#endif +} diff --git a/OpenMetaverse/_Packets_.cs b/OpenMetaverse/_Packets_.cs new file mode 100644 index 0000000..377d3d7 --- /dev/null +++ b/OpenMetaverse/_Packets_.cs @@ -0,0 +1,79290 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the 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.Text; +using OpenMetaverse; + +namespace OpenMetaverse +{ + /// + /// + /// + public enum PacketFrequency : byte + { + /// + Low, + /// + Medium, + /// + High + } +} + +namespace OpenMetaverse.Packets +{ + /// + /// Thrown when a packet could not be successfully deserialized + /// + public class MalformedDataException : ApplicationException + { + /// + /// Default constructor + /// + public MalformedDataException() { } + + /// + /// Constructor that takes an additional error message + /// + /// An error message to attach to this exception + public MalformedDataException(string Message) + : base(Message) + { + this.Source = "Packet decoding"; + } + } + + /// + /// The header of a message template packet. Holds packet flags, sequence + /// number, packet ID, and any ACKs that will be appended at the end of + /// the packet + /// + public struct Header + { + public bool Reliable; + public bool Resent; + public bool Zerocoded; + public bool AppendedAcks; + public uint Sequence; + public ushort ID; + public PacketFrequency Frequency; + public uint[] AckList; + + public void ToBytes(byte[] bytes, ref int i) + { + byte flags = 0; + if (Reliable) flags |= Helpers.MSG_RELIABLE; + if (Resent) flags |= Helpers.MSG_RESENT; + if (Zerocoded) flags |= Helpers.MSG_ZEROCODED; + if (AppendedAcks) flags |= Helpers.MSG_APPENDED_ACKS; + + // Flags + bytes[i++] = flags; + + // Sequence number + Utils.UIntToBytesBig(Sequence, bytes, i); + i += 4; + + // Extra byte + bytes[i++] = 0; + + // Packet ID + switch (Frequency) + { + case PacketFrequency.High: + // 1 byte ID + bytes[i++] = (byte)ID; + break; + case PacketFrequency.Medium: + // 2 byte ID + bytes[i++] = 0xFF; + bytes[i++] = (byte)ID; + break; + case PacketFrequency.Low: + // 4 byte ID + bytes[i++] = 0xFF; + bytes[i++] = 0xFF; + Utils.UInt16ToBytesBig(ID, bytes, i); + i += 2; + break; + } + } + + public void FromBytes(byte[] bytes, ref int pos, ref int packetEnd) + { + this = BuildHeader(bytes, ref pos, ref packetEnd); + } + + /// + /// Convert the AckList to a byte array, used for packet serializing + /// + /// Reference to the target byte array + /// Beginning position to start writing to in the byte + /// array, will be updated with the ending position of the ACK list + public void AcksToBytes(byte[] bytes, ref int i) + { + foreach (uint ack in AckList) + { + Utils.UIntToBytesBig(ack, bytes, i); + i += 4; + } + if (AckList.Length > 0) { bytes[i++] = (byte)AckList.Length; } + } + + /// + /// + /// + /// + /// + /// + /// + public static Header BuildHeader(byte[] bytes, ref int pos, ref int packetEnd) + { + Header header; + byte flags = bytes[pos]; + + header.AppendedAcks = (flags & Helpers.MSG_APPENDED_ACKS) != 0; + header.Reliable = (flags & Helpers.MSG_RELIABLE) != 0; + header.Resent = (flags & Helpers.MSG_RESENT) != 0; + header.Zerocoded = (flags & Helpers.MSG_ZEROCODED) != 0; + header.Sequence = (uint)((bytes[pos + 1] << 24) + (bytes[pos + 2] << 16) + (bytes[pos + 3] << 8) + bytes[pos + 4]); + + // Set the frequency and packet ID number + if (bytes[pos + 6] == 0xFF) + { + if (bytes[pos + 7] == 0xFF) + { + header.Frequency = PacketFrequency.Low; + if (header.Zerocoded && bytes[pos + 8] == 0) + header.ID = bytes[pos + 10]; + else + header.ID = (ushort)((bytes[pos + 8] << 8) + bytes[pos + 9]); + + pos += 10; + } + else + { + header.Frequency = PacketFrequency.Medium; + header.ID = bytes[pos + 7]; + + pos += 8; + } + } + else + { + header.Frequency = PacketFrequency.High; + header.ID = bytes[pos + 6]; + + pos += 7; + } + + header.AckList = null; + CreateAckList(ref header, bytes, ref packetEnd); + + return header; + } + + /// + /// + /// + /// + /// + /// + static void CreateAckList(ref Header header, byte[] bytes, ref int packetEnd) + { + if (header.AppendedAcks) + { + int count = bytes[packetEnd--]; + header.AckList = new uint[count]; + + for (int i = 0; i < count; i++) + { + header.AckList[i] = (uint)( + (bytes[(packetEnd - i * 4) - 3] << 24) | + (bytes[(packetEnd - i * 4) - 2] << 16) | + (bytes[(packetEnd - i * 4) - 1] << 8) | + (bytes[(packetEnd - i * 4) ])); + } + + packetEnd -= (count * 4); + } + } + } + + /// + /// A block of data in a packet. Packets are composed of one or more blocks, + /// each block containing one or more fields + /// + public abstract class PacketBlock + { + /// Current length of the data in this packet + public abstract int Length { get; } + + /// + /// Create a block from a byte array + /// + /// Byte array containing the serialized block + /// Starting position of the block in the byte array. + /// This will point to the data after the end of the block when the + /// call returns + public abstract void FromBytes(byte[] bytes, ref int i); + + /// + /// Serialize this block into a byte array + /// + /// Byte array to serialize this block into + /// Starting position in the byte array to serialize to. + /// This will point to the position directly after the end of the + /// serialized block when the call returns + public abstract void ToBytes(byte[] bytes, ref int i); + } + + public enum PacketType + { + /// A generic value, not an actual packet type + Default, + TestMessage = 65537, + UseCircuitCode = 65539, + TelehubInfo = 65546, + EconomyDataRequest = 65560, + EconomyData = 65561, + AvatarPickerRequest = 65562, + AvatarPickerReply = 65564, + PlacesQuery = 65565, + PlacesReply = 65566, + DirFindQuery = 65567, + DirPlacesQuery = 65569, + DirPlacesReply = 65571, + DirPeopleReply = 65572, + DirEventsReply = 65573, + DirGroupsReply = 65574, + DirClassifiedQuery = 65575, + DirClassifiedReply = 65577, + AvatarClassifiedReply = 65578, + ClassifiedInfoRequest = 65579, + ClassifiedInfoReply = 65580, + ClassifiedInfoUpdate = 65581, + ClassifiedDelete = 65582, + ClassifiedGodDelete = 65583, + DirLandQuery = 65584, + DirLandReply = 65586, + DirPopularQuery = 65587, + DirPopularReply = 65589, + ParcelInfoRequest = 65590, + ParcelInfoReply = 65591, + ParcelObjectOwnersRequest = 65592, + ParcelObjectOwnersReply = 65593, + GroupNoticesListRequest = 65594, + GroupNoticesListReply = 65595, + GroupNoticeRequest = 65596, + TeleportRequest = 65598, + TeleportLocationRequest = 65599, + TeleportLocal = 65600, + TeleportLandmarkRequest = 65601, + TeleportProgress = 65602, + TeleportFinish = 65605, + StartLure = 65606, + TeleportLureRequest = 65607, + TeleportCancel = 65608, + TeleportStart = 65609, + TeleportFailed = 65610, + Undo = 65611, + Redo = 65612, + UndoLand = 65613, + AgentPause = 65614, + AgentResume = 65615, + ChatFromViewer = 65616, + AgentThrottle = 65617, + AgentFOV = 65618, + AgentHeightWidth = 65619, + AgentSetAppearance = 65620, + AgentQuitCopy = 65621, + ImageNotInDatabase = 65622, + RebakeAvatarTextures = 65623, + SetAlwaysRun = 65624, + ObjectDelete = 65625, + ObjectDuplicate = 65626, + ObjectDuplicateOnRay = 65627, + ObjectScale = 65628, + ObjectRotation = 65629, + ObjectFlagUpdate = 65630, + ObjectClickAction = 65631, + ObjectImage = 65632, + ObjectMaterial = 65633, + ObjectShape = 65634, + ObjectExtraParams = 65635, + ObjectOwner = 65636, + ObjectGroup = 65637, + ObjectBuy = 65638, + BuyObjectInventory = 65639, + DerezContainer = 65640, + ObjectPermissions = 65641, + ObjectSaleInfo = 65642, + ObjectName = 65643, + ObjectDescription = 65644, + ObjectCategory = 65645, + ObjectSelect = 65646, + ObjectDeselect = 65647, + ObjectAttach = 65648, + ObjectDetach = 65649, + ObjectDrop = 65650, + ObjectLink = 65651, + ObjectDelink = 65652, + ObjectGrab = 65653, + ObjectGrabUpdate = 65654, + ObjectDeGrab = 65655, + ObjectSpinStart = 65656, + ObjectSpinUpdate = 65657, + ObjectSpinStop = 65658, + ObjectExportSelected = 65659, + ModifyLand = 65660, + VelocityInterpolateOn = 65661, + VelocityInterpolateOff = 65662, + StateSave = 65663, + ReportAutosaveCrash = 65664, + SimWideDeletes = 65665, + TrackAgent = 65666, + ViewerStats = 65667, + ScriptAnswerYes = 65668, + UserReport = 65669, + AlertMessage = 65670, + AgentAlertMessage = 65671, + MeanCollisionAlert = 65672, + ViewerFrozenMessage = 65673, + HealthMessage = 65674, + ChatFromSimulator = 65675, + SimStats = 65676, + RequestRegionInfo = 65677, + RegionInfo = 65678, + GodUpdateRegionInfo = 65679, + RegionHandshake = 65684, + RegionHandshakeReply = 65685, + SimulatorViewerTimeMessage = 65686, + EnableSimulator = 65687, + DisableSimulator = 65688, + TransferRequest = 65689, + TransferInfo = 65690, + TransferAbort = 65691, + RequestXfer = 65692, + AbortXfer = 65693, + AvatarAppearance = 65694, + SetFollowCamProperties = 65695, + ClearFollowCamProperties = 65696, + RequestPayPrice = 65697, + PayPriceReply = 65698, + KickUser = 65699, + GodKickUser = 65701, + EjectUser = 65703, + FreezeUser = 65704, + AvatarPropertiesRequest = 65705, + AvatarPropertiesReply = 65707, + AvatarInterestsReply = 65708, + AvatarGroupsReply = 65709, + AvatarPropertiesUpdate = 65710, + AvatarInterestsUpdate = 65711, + AvatarNotesReply = 65712, + AvatarNotesUpdate = 65713, + AvatarPicksReply = 65714, + EventInfoRequest = 65715, + EventInfoReply = 65716, + EventNotificationAddRequest = 65717, + EventNotificationRemoveRequest = 65718, + EventGodDelete = 65719, + PickInfoReply = 65720, + PickInfoUpdate = 65721, + PickDelete = 65722, + PickGodDelete = 65723, + ScriptQuestion = 65724, + ScriptControlChange = 65725, + ScriptDialog = 65726, + ScriptDialogReply = 65727, + ForceScriptControlRelease = 65728, + RevokePermissions = 65729, + LoadURL = 65730, + ScriptTeleportRequest = 65731, + ParcelOverlay = 65732, + ParcelPropertiesRequestByID = 65733, + ParcelPropertiesUpdate = 65734, + ParcelReturnObjects = 65735, + ParcelSetOtherCleanTime = 65736, + ParcelDisableObjects = 65737, + ParcelSelectObjects = 65738, + EstateCovenantRequest = 65739, + EstateCovenantReply = 65740, + ForceObjectSelect = 65741, + ParcelBuyPass = 65742, + ParcelDeedToGroup = 65743, + ParcelReclaim = 65744, + ParcelClaim = 65745, + ParcelJoin = 65746, + ParcelDivide = 65747, + ParcelRelease = 65748, + ParcelBuy = 65749, + ParcelGodForceOwner = 65750, + ParcelAccessListRequest = 65751, + ParcelAccessListReply = 65752, + ParcelAccessListUpdate = 65753, + ParcelDwellRequest = 65754, + ParcelDwellReply = 65755, + ParcelGodMarkAsContent = 65763, + ViewerStartAuction = 65764, + UUIDNameRequest = 65771, + UUIDNameReply = 65772, + UUIDGroupNameRequest = 65773, + UUIDGroupNameReply = 65774, + ChildAgentDying = 65776, + ChildAgentUnknown = 65777, + GetScriptRunning = 65779, + ScriptRunningReply = 65780, + SetScriptRunning = 65781, + ScriptReset = 65782, + ScriptSensorRequest = 65783, + ScriptSensorReply = 65784, + CompleteAgentMovement = 65785, + AgentMovementComplete = 65786, + LogoutRequest = 65788, + LogoutReply = 65789, + ImprovedInstantMessage = 65790, + RetrieveInstantMessages = 65791, + FindAgent = 65792, + RequestGodlikePowers = 65793, + GrantGodlikePowers = 65794, + GodlikeMessage = 65795, + EstateOwnerMessage = 65796, + GenericMessage = 65797, + MuteListRequest = 65798, + UpdateMuteListEntry = 65799, + RemoveMuteListEntry = 65800, + CopyInventoryFromNotecard = 65801, + UpdateInventoryItem = 65802, + UpdateCreateInventoryItem = 65803, + MoveInventoryItem = 65804, + CopyInventoryItem = 65805, + RemoveInventoryItem = 65806, + ChangeInventoryItemFlags = 65807, + SaveAssetIntoInventory = 65808, + CreateInventoryFolder = 65809, + UpdateInventoryFolder = 65810, + MoveInventoryFolder = 65811, + RemoveInventoryFolder = 65812, + FetchInventoryDescendents = 65813, + InventoryDescendents = 65814, + FetchInventory = 65815, + FetchInventoryReply = 65816, + BulkUpdateInventory = 65817, + RemoveInventoryObjects = 65820, + PurgeInventoryDescendents = 65821, + UpdateTaskInventory = 65822, + RemoveTaskInventory = 65823, + MoveTaskInventory = 65824, + RequestTaskInventory = 65825, + ReplyTaskInventory = 65826, + DeRezObject = 65827, + DeRezAck = 65828, + RezObject = 65829, + RezObjectFromNotecard = 65830, + AcceptFriendship = 65833, + DeclineFriendship = 65834, + TerminateFriendship = 65836, + OfferCallingCard = 65837, + AcceptCallingCard = 65838, + DeclineCallingCard = 65839, + RezScript = 65840, + CreateInventoryItem = 65841, + CreateLandmarkForEvent = 65842, + RegionHandleRequest = 65845, + RegionIDAndHandleReply = 65846, + MoneyTransferRequest = 65847, + MoneyBalanceRequest = 65849, + MoneyBalanceReply = 65850, + RoutedMoneyBalanceReply = 65851, + ActivateGestures = 65852, + DeactivateGestures = 65853, + MuteListUpdate = 65854, + UseCachedMuteList = 65855, + GrantUserRights = 65856, + ChangeUserRights = 65857, + OnlineNotification = 65858, + OfflineNotification = 65859, + SetStartLocationRequest = 65860, + AssetUploadRequest = 65869, + AssetUploadComplete = 65870, + CreateGroupRequest = 65875, + CreateGroupReply = 65876, + UpdateGroupInfo = 65877, + GroupRoleChanges = 65878, + JoinGroupRequest = 65879, + JoinGroupReply = 65880, + EjectGroupMemberRequest = 65881, + EjectGroupMemberReply = 65882, + LeaveGroupRequest = 65883, + LeaveGroupReply = 65884, + InviteGroupRequest = 65885, + GroupProfileRequest = 65887, + GroupProfileReply = 65888, + GroupAccountSummaryRequest = 65889, + GroupAccountSummaryReply = 65890, + GroupAccountDetailsRequest = 65891, + GroupAccountDetailsReply = 65892, + GroupAccountTransactionsRequest = 65893, + GroupAccountTransactionsReply = 65894, + GroupActiveProposalsRequest = 65895, + GroupActiveProposalItemReply = 65896, + GroupVoteHistoryRequest = 65897, + GroupVoteHistoryItemReply = 65898, + StartGroupProposal = 65899, + GroupProposalBallot = 65900, + GroupMembersRequest = 65902, + GroupMembersReply = 65903, + ActivateGroup = 65904, + SetGroupContribution = 65905, + SetGroupAcceptNotices = 65906, + GroupRoleDataRequest = 65907, + GroupRoleDataReply = 65908, + GroupRoleMembersRequest = 65909, + GroupRoleMembersReply = 65910, + GroupTitlesRequest = 65911, + GroupTitlesReply = 65912, + GroupTitleUpdate = 65913, + GroupRoleUpdate = 65914, + LiveHelpGroupRequest = 65915, + LiveHelpGroupReply = 65916, + AgentWearablesRequest = 65917, + AgentWearablesUpdate = 65918, + AgentIsNowWearing = 65919, + AgentCachedTexture = 65920, + AgentCachedTextureResponse = 65921, + AgentDataUpdateRequest = 65922, + AgentDataUpdate = 65923, + GroupDataUpdate = 65924, + AgentGroupDataUpdate = 65925, + AgentDropGroup = 65926, + RezSingleAttachmentFromInv = 65931, + RezMultipleAttachmentsFromInv = 65932, + DetachAttachmentIntoInv = 65933, + CreateNewOutfitAttachments = 65934, + UserInfoRequest = 65935, + UserInfoReply = 65936, + UpdateUserInfo = 65937, + InitiateDownload = 65939, + MapLayerRequest = 65941, + MapLayerReply = 65942, + MapBlockRequest = 65943, + MapNameRequest = 65944, + MapBlockReply = 65945, + MapItemRequest = 65946, + MapItemReply = 65947, + SendPostcard = 65948, + ParcelMediaCommandMessage = 65955, + ParcelMediaUpdate = 65956, + LandStatRequest = 65957, + LandStatReply = 65958, + Error = 65959, + ObjectIncludeInSearch = 65960, + RezRestoreToWorld = 65961, + LinkInventoryItem = 65962, + PacketAck = 131067, + OpenCircuit = 131068, + CloseCircuit = 131069, + ObjectAdd = 131073, + MultipleObjectUpdate = 131074, + RequestMultipleObjects = 131075, + ObjectPosition = 131076, + RequestObjectPropertiesFamily = 131077, + CoarseLocationUpdate = 131078, + CrossedRegion = 131079, + ConfirmEnableSimulator = 131080, + ObjectProperties = 131081, + ObjectPropertiesFamily = 131082, + ParcelPropertiesRequest = 131083, + AttachedSound = 131085, + AttachedSoundGainChange = 131086, + PreloadSound = 131087, + ViewerEffect = 131089, + StartPingCheck = 196609, + CompletePingCheck = 196610, + AgentUpdate = 196612, + AgentAnimation = 196613, + AgentRequestSit = 196614, + AgentSit = 196615, + RequestImage = 196616, + ImageData = 196617, + ImagePacket = 196618, + LayerData = 196619, + ObjectUpdate = 196620, + ObjectUpdateCompressed = 196621, + ObjectUpdateCached = 196622, + ImprovedTerseObjectUpdate = 196623, + KillObject = 196624, + TransferPacket = 196625, + SendXferPacket = 196626, + ConfirmXferPacket = 196627, + AvatarAnimation = 196628, + AvatarSitResponse = 196629, + CameraConstraint = 196630, + ParcelProperties = 196631, + ChildAgentUpdate = 196633, + ChildAgentAlive = 196634, + ChildAgentPositionUpdate = 196635, + SoundTrigger = 196637, + } + + public abstract partial class Packet + { + public const int MTU = 1200; + + public Header Header; + public bool HasVariableBlocks; + public PacketType Type; + public abstract int Length { get; } + public abstract void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer); + public abstract void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd); + public abstract byte[] ToBytes(); + public abstract byte[][] ToBytesMultiple(); + + public static PacketType GetType(ushort id, PacketFrequency frequency) + { + switch (frequency) + { + case PacketFrequency.Low: + switch (id) + { + case 1: return PacketType.TestMessage; + case 3: return PacketType.UseCircuitCode; + case 10: return PacketType.TelehubInfo; + case 24: return PacketType.EconomyDataRequest; + case 25: return PacketType.EconomyData; + case 26: return PacketType.AvatarPickerRequest; + case 28: return PacketType.AvatarPickerReply; + case 29: return PacketType.PlacesQuery; + case 30: return PacketType.PlacesReply; + case 31: return PacketType.DirFindQuery; + case 33: return PacketType.DirPlacesQuery; + case 35: return PacketType.DirPlacesReply; + case 36: return PacketType.DirPeopleReply; + case 37: return PacketType.DirEventsReply; + case 38: return PacketType.DirGroupsReply; + case 39: return PacketType.DirClassifiedQuery; + case 41: return PacketType.DirClassifiedReply; + case 42: return PacketType.AvatarClassifiedReply; + case 43: return PacketType.ClassifiedInfoRequest; + case 44: return PacketType.ClassifiedInfoReply; + case 45: return PacketType.ClassifiedInfoUpdate; + case 46: return PacketType.ClassifiedDelete; + case 47: return PacketType.ClassifiedGodDelete; + case 48: return PacketType.DirLandQuery; + case 50: return PacketType.DirLandReply; + case 51: return PacketType.DirPopularQuery; + case 53: return PacketType.DirPopularReply; + case 54: return PacketType.ParcelInfoRequest; + case 55: return PacketType.ParcelInfoReply; + case 56: return PacketType.ParcelObjectOwnersRequest; + case 57: return PacketType.ParcelObjectOwnersReply; + case 58: return PacketType.GroupNoticesListRequest; + case 59: return PacketType.GroupNoticesListReply; + case 60: return PacketType.GroupNoticeRequest; + case 62: return PacketType.TeleportRequest; + case 63: return PacketType.TeleportLocationRequest; + case 64: return PacketType.TeleportLocal; + case 65: return PacketType.TeleportLandmarkRequest; + case 66: return PacketType.TeleportProgress; + case 69: return PacketType.TeleportFinish; + case 70: return PacketType.StartLure; + case 71: return PacketType.TeleportLureRequest; + case 72: return PacketType.TeleportCancel; + case 73: return PacketType.TeleportStart; + case 74: return PacketType.TeleportFailed; + case 75: return PacketType.Undo; + case 76: return PacketType.Redo; + case 77: return PacketType.UndoLand; + case 78: return PacketType.AgentPause; + case 79: return PacketType.AgentResume; + case 80: return PacketType.ChatFromViewer; + case 81: return PacketType.AgentThrottle; + case 82: return PacketType.AgentFOV; + case 83: return PacketType.AgentHeightWidth; + case 84: return PacketType.AgentSetAppearance; + case 85: return PacketType.AgentQuitCopy; + case 86: return PacketType.ImageNotInDatabase; + case 87: return PacketType.RebakeAvatarTextures; + case 88: return PacketType.SetAlwaysRun; + case 89: return PacketType.ObjectDelete; + case 90: return PacketType.ObjectDuplicate; + case 91: return PacketType.ObjectDuplicateOnRay; + case 92: return PacketType.ObjectScale; + case 93: return PacketType.ObjectRotation; + case 94: return PacketType.ObjectFlagUpdate; + case 95: return PacketType.ObjectClickAction; + case 96: return PacketType.ObjectImage; + case 97: return PacketType.ObjectMaterial; + case 98: return PacketType.ObjectShape; + case 99: return PacketType.ObjectExtraParams; + case 100: return PacketType.ObjectOwner; + case 101: return PacketType.ObjectGroup; + case 102: return PacketType.ObjectBuy; + case 103: return PacketType.BuyObjectInventory; + case 104: return PacketType.DerezContainer; + case 105: return PacketType.ObjectPermissions; + case 106: return PacketType.ObjectSaleInfo; + case 107: return PacketType.ObjectName; + case 108: return PacketType.ObjectDescription; + case 109: return PacketType.ObjectCategory; + case 110: return PacketType.ObjectSelect; + case 111: return PacketType.ObjectDeselect; + case 112: return PacketType.ObjectAttach; + case 113: return PacketType.ObjectDetach; + case 114: return PacketType.ObjectDrop; + case 115: return PacketType.ObjectLink; + case 116: return PacketType.ObjectDelink; + case 117: return PacketType.ObjectGrab; + case 118: return PacketType.ObjectGrabUpdate; + case 119: return PacketType.ObjectDeGrab; + case 120: return PacketType.ObjectSpinStart; + case 121: return PacketType.ObjectSpinUpdate; + case 122: return PacketType.ObjectSpinStop; + case 123: return PacketType.ObjectExportSelected; + case 124: return PacketType.ModifyLand; + case 125: return PacketType.VelocityInterpolateOn; + case 126: return PacketType.VelocityInterpolateOff; + case 127: return PacketType.StateSave; + case 128: return PacketType.ReportAutosaveCrash; + case 129: return PacketType.SimWideDeletes; + case 130: return PacketType.TrackAgent; + case 131: return PacketType.ViewerStats; + case 132: return PacketType.ScriptAnswerYes; + case 133: return PacketType.UserReport; + case 134: return PacketType.AlertMessage; + case 135: return PacketType.AgentAlertMessage; + case 136: return PacketType.MeanCollisionAlert; + case 137: return PacketType.ViewerFrozenMessage; + case 138: return PacketType.HealthMessage; + case 139: return PacketType.ChatFromSimulator; + case 140: return PacketType.SimStats; + case 141: return PacketType.RequestRegionInfo; + case 142: return PacketType.RegionInfo; + case 143: return PacketType.GodUpdateRegionInfo; + case 148: return PacketType.RegionHandshake; + case 149: return PacketType.RegionHandshakeReply; + case 150: return PacketType.SimulatorViewerTimeMessage; + case 151: return PacketType.EnableSimulator; + case 152: return PacketType.DisableSimulator; + case 153: return PacketType.TransferRequest; + case 154: return PacketType.TransferInfo; + case 155: return PacketType.TransferAbort; + case 156: return PacketType.RequestXfer; + case 157: return PacketType.AbortXfer; + case 158: return PacketType.AvatarAppearance; + case 159: return PacketType.SetFollowCamProperties; + case 160: return PacketType.ClearFollowCamProperties; + case 161: return PacketType.RequestPayPrice; + case 162: return PacketType.PayPriceReply; + case 163: return PacketType.KickUser; + case 165: return PacketType.GodKickUser; + case 167: return PacketType.EjectUser; + case 168: return PacketType.FreezeUser; + case 169: return PacketType.AvatarPropertiesRequest; + case 171: return PacketType.AvatarPropertiesReply; + case 172: return PacketType.AvatarInterestsReply; + case 173: return PacketType.AvatarGroupsReply; + case 174: return PacketType.AvatarPropertiesUpdate; + case 175: return PacketType.AvatarInterestsUpdate; + case 176: return PacketType.AvatarNotesReply; + case 177: return PacketType.AvatarNotesUpdate; + case 178: return PacketType.AvatarPicksReply; + case 179: return PacketType.EventInfoRequest; + case 180: return PacketType.EventInfoReply; + case 181: return PacketType.EventNotificationAddRequest; + case 182: return PacketType.EventNotificationRemoveRequest; + case 183: return PacketType.EventGodDelete; + case 184: return PacketType.PickInfoReply; + case 185: return PacketType.PickInfoUpdate; + case 186: return PacketType.PickDelete; + case 187: return PacketType.PickGodDelete; + case 188: return PacketType.ScriptQuestion; + case 189: return PacketType.ScriptControlChange; + case 190: return PacketType.ScriptDialog; + case 191: return PacketType.ScriptDialogReply; + case 192: return PacketType.ForceScriptControlRelease; + case 193: return PacketType.RevokePermissions; + case 194: return PacketType.LoadURL; + case 195: return PacketType.ScriptTeleportRequest; + case 196: return PacketType.ParcelOverlay; + case 197: return PacketType.ParcelPropertiesRequestByID; + case 198: return PacketType.ParcelPropertiesUpdate; + case 199: return PacketType.ParcelReturnObjects; + case 200: return PacketType.ParcelSetOtherCleanTime; + case 201: return PacketType.ParcelDisableObjects; + case 202: return PacketType.ParcelSelectObjects; + case 203: return PacketType.EstateCovenantRequest; + case 204: return PacketType.EstateCovenantReply; + case 205: return PacketType.ForceObjectSelect; + case 206: return PacketType.ParcelBuyPass; + case 207: return PacketType.ParcelDeedToGroup; + case 208: return PacketType.ParcelReclaim; + case 209: return PacketType.ParcelClaim; + case 210: return PacketType.ParcelJoin; + case 211: return PacketType.ParcelDivide; + case 212: return PacketType.ParcelRelease; + case 213: return PacketType.ParcelBuy; + case 214: return PacketType.ParcelGodForceOwner; + case 215: return PacketType.ParcelAccessListRequest; + case 216: return PacketType.ParcelAccessListReply; + case 217: return PacketType.ParcelAccessListUpdate; + case 218: return PacketType.ParcelDwellRequest; + case 219: return PacketType.ParcelDwellReply; + case 227: return PacketType.ParcelGodMarkAsContent; + case 228: return PacketType.ViewerStartAuction; + case 235: return PacketType.UUIDNameRequest; + case 236: return PacketType.UUIDNameReply; + case 237: return PacketType.UUIDGroupNameRequest; + case 238: return PacketType.UUIDGroupNameReply; + case 240: return PacketType.ChildAgentDying; + case 241: return PacketType.ChildAgentUnknown; + case 243: return PacketType.GetScriptRunning; + case 244: return PacketType.ScriptRunningReply; + case 245: return PacketType.SetScriptRunning; + case 246: return PacketType.ScriptReset; + case 247: return PacketType.ScriptSensorRequest; + case 248: return PacketType.ScriptSensorReply; + case 249: return PacketType.CompleteAgentMovement; + case 250: return PacketType.AgentMovementComplete; + case 252: return PacketType.LogoutRequest; + case 253: return PacketType.LogoutReply; + case 254: return PacketType.ImprovedInstantMessage; + case 255: return PacketType.RetrieveInstantMessages; + case 256: return PacketType.FindAgent; + case 257: return PacketType.RequestGodlikePowers; + case 258: return PacketType.GrantGodlikePowers; + case 259: return PacketType.GodlikeMessage; + case 260: return PacketType.EstateOwnerMessage; + case 261: return PacketType.GenericMessage; + case 262: return PacketType.MuteListRequest; + case 263: return PacketType.UpdateMuteListEntry; + case 264: return PacketType.RemoveMuteListEntry; + case 265: return PacketType.CopyInventoryFromNotecard; + case 266: return PacketType.UpdateInventoryItem; + case 267: return PacketType.UpdateCreateInventoryItem; + case 268: return PacketType.MoveInventoryItem; + case 269: return PacketType.CopyInventoryItem; + case 270: return PacketType.RemoveInventoryItem; + case 271: return PacketType.ChangeInventoryItemFlags; + case 272: return PacketType.SaveAssetIntoInventory; + case 273: return PacketType.CreateInventoryFolder; + case 274: return PacketType.UpdateInventoryFolder; + case 275: return PacketType.MoveInventoryFolder; + case 276: return PacketType.RemoveInventoryFolder; + case 277: return PacketType.FetchInventoryDescendents; + case 278: return PacketType.InventoryDescendents; + case 279: return PacketType.FetchInventory; + case 280: return PacketType.FetchInventoryReply; + case 281: return PacketType.BulkUpdateInventory; + case 284: return PacketType.RemoveInventoryObjects; + case 285: return PacketType.PurgeInventoryDescendents; + case 286: return PacketType.UpdateTaskInventory; + case 287: return PacketType.RemoveTaskInventory; + case 288: return PacketType.MoveTaskInventory; + case 289: return PacketType.RequestTaskInventory; + case 290: return PacketType.ReplyTaskInventory; + case 291: return PacketType.DeRezObject; + case 292: return PacketType.DeRezAck; + case 293: return PacketType.RezObject; + case 294: return PacketType.RezObjectFromNotecard; + case 297: return PacketType.AcceptFriendship; + case 298: return PacketType.DeclineFriendship; + case 300: return PacketType.TerminateFriendship; + case 301: return PacketType.OfferCallingCard; + case 302: return PacketType.AcceptCallingCard; + case 303: return PacketType.DeclineCallingCard; + case 304: return PacketType.RezScript; + case 305: return PacketType.CreateInventoryItem; + case 306: return PacketType.CreateLandmarkForEvent; + case 309: return PacketType.RegionHandleRequest; + case 310: return PacketType.RegionIDAndHandleReply; + case 311: return PacketType.MoneyTransferRequest; + case 313: return PacketType.MoneyBalanceRequest; + case 314: return PacketType.MoneyBalanceReply; + case 315: return PacketType.RoutedMoneyBalanceReply; + case 316: return PacketType.ActivateGestures; + case 317: return PacketType.DeactivateGestures; + case 318: return PacketType.MuteListUpdate; + case 319: return PacketType.UseCachedMuteList; + case 320: return PacketType.GrantUserRights; + case 321: return PacketType.ChangeUserRights; + case 322: return PacketType.OnlineNotification; + case 323: return PacketType.OfflineNotification; + case 324: return PacketType.SetStartLocationRequest; + case 333: return PacketType.AssetUploadRequest; + case 334: return PacketType.AssetUploadComplete; + case 339: return PacketType.CreateGroupRequest; + case 340: return PacketType.CreateGroupReply; + case 341: return PacketType.UpdateGroupInfo; + case 342: return PacketType.GroupRoleChanges; + case 343: return PacketType.JoinGroupRequest; + case 344: return PacketType.JoinGroupReply; + case 345: return PacketType.EjectGroupMemberRequest; + case 346: return PacketType.EjectGroupMemberReply; + case 347: return PacketType.LeaveGroupRequest; + case 348: return PacketType.LeaveGroupReply; + case 349: return PacketType.InviteGroupRequest; + case 351: return PacketType.GroupProfileRequest; + case 352: return PacketType.GroupProfileReply; + case 353: return PacketType.GroupAccountSummaryRequest; + case 354: return PacketType.GroupAccountSummaryReply; + case 355: return PacketType.GroupAccountDetailsRequest; + case 356: return PacketType.GroupAccountDetailsReply; + case 357: return PacketType.GroupAccountTransactionsRequest; + case 358: return PacketType.GroupAccountTransactionsReply; + case 359: return PacketType.GroupActiveProposalsRequest; + case 360: return PacketType.GroupActiveProposalItemReply; + case 361: return PacketType.GroupVoteHistoryRequest; + case 362: return PacketType.GroupVoteHistoryItemReply; + case 363: return PacketType.StartGroupProposal; + case 364: return PacketType.GroupProposalBallot; + case 366: return PacketType.GroupMembersRequest; + case 367: return PacketType.GroupMembersReply; + case 368: return PacketType.ActivateGroup; + case 369: return PacketType.SetGroupContribution; + case 370: return PacketType.SetGroupAcceptNotices; + case 371: return PacketType.GroupRoleDataRequest; + case 372: return PacketType.GroupRoleDataReply; + case 373: return PacketType.GroupRoleMembersRequest; + case 374: return PacketType.GroupRoleMembersReply; + case 375: return PacketType.GroupTitlesRequest; + case 376: return PacketType.GroupTitlesReply; + case 377: return PacketType.GroupTitleUpdate; + case 378: return PacketType.GroupRoleUpdate; + case 379: return PacketType.LiveHelpGroupRequest; + case 380: return PacketType.LiveHelpGroupReply; + case 381: return PacketType.AgentWearablesRequest; + case 382: return PacketType.AgentWearablesUpdate; + case 383: return PacketType.AgentIsNowWearing; + case 384: return PacketType.AgentCachedTexture; + case 385: return PacketType.AgentCachedTextureResponse; + case 386: return PacketType.AgentDataUpdateRequest; + case 387: return PacketType.AgentDataUpdate; + case 388: return PacketType.GroupDataUpdate; + case 389: return PacketType.AgentGroupDataUpdate; + case 390: return PacketType.AgentDropGroup; + case 395: return PacketType.RezSingleAttachmentFromInv; + case 396: return PacketType.RezMultipleAttachmentsFromInv; + case 397: return PacketType.DetachAttachmentIntoInv; + case 398: return PacketType.CreateNewOutfitAttachments; + case 399: return PacketType.UserInfoRequest; + case 400: return PacketType.UserInfoReply; + case 401: return PacketType.UpdateUserInfo; + case 403: return PacketType.InitiateDownload; + case 405: return PacketType.MapLayerRequest; + case 406: return PacketType.MapLayerReply; + case 407: return PacketType.MapBlockRequest; + case 408: return PacketType.MapNameRequest; + case 409: return PacketType.MapBlockReply; + case 410: return PacketType.MapItemRequest; + case 411: return PacketType.MapItemReply; + case 412: return PacketType.SendPostcard; + case 419: return PacketType.ParcelMediaCommandMessage; + case 420: return PacketType.ParcelMediaUpdate; + case 421: return PacketType.LandStatRequest; + case 422: return PacketType.LandStatReply; + case 423: return PacketType.Error; + case 424: return PacketType.ObjectIncludeInSearch; + case 425: return PacketType.RezRestoreToWorld; + case 426: return PacketType.LinkInventoryItem; + case 65531: return PacketType.PacketAck; + case 65532: return PacketType.OpenCircuit; + case 65533: return PacketType.CloseCircuit; + } + break; + case PacketFrequency.Medium: + switch (id) + { + case 1: return PacketType.ObjectAdd; + case 2: return PacketType.MultipleObjectUpdate; + case 3: return PacketType.RequestMultipleObjects; + case 4: return PacketType.ObjectPosition; + case 5: return PacketType.RequestObjectPropertiesFamily; + case 6: return PacketType.CoarseLocationUpdate; + case 7: return PacketType.CrossedRegion; + case 8: return PacketType.ConfirmEnableSimulator; + case 9: return PacketType.ObjectProperties; + case 10: return PacketType.ObjectPropertiesFamily; + case 11: return PacketType.ParcelPropertiesRequest; + case 13: return PacketType.AttachedSound; + case 14: return PacketType.AttachedSoundGainChange; + case 15: return PacketType.PreloadSound; + case 17: return PacketType.ViewerEffect; + } + break; + case PacketFrequency.High: + switch (id) + { + case 1: return PacketType.StartPingCheck; + case 2: return PacketType.CompletePingCheck; + case 4: return PacketType.AgentUpdate; + case 5: return PacketType.AgentAnimation; + case 6: return PacketType.AgentRequestSit; + case 7: return PacketType.AgentSit; + case 8: return PacketType.RequestImage; + case 9: return PacketType.ImageData; + case 10: return PacketType.ImagePacket; + case 11: return PacketType.LayerData; + case 12: return PacketType.ObjectUpdate; + case 13: return PacketType.ObjectUpdateCompressed; + case 14: return PacketType.ObjectUpdateCached; + case 15: return PacketType.ImprovedTerseObjectUpdate; + case 16: return PacketType.KillObject; + case 17: return PacketType.TransferPacket; + case 18: return PacketType.SendXferPacket; + case 19: return PacketType.ConfirmXferPacket; + case 20: return PacketType.AvatarAnimation; + case 21: return PacketType.AvatarSitResponse; + case 22: return PacketType.CameraConstraint; + case 23: return PacketType.ParcelProperties; + case 25: return PacketType.ChildAgentUpdate; + case 26: return PacketType.ChildAgentAlive; + case 27: return PacketType.ChildAgentPositionUpdate; + case 29: return PacketType.SoundTrigger; + } + break; + } + + return PacketType.Default; + } + + public static Packet BuildPacket(PacketType type) + { + if(type == PacketType.StartPingCheck) return new StartPingCheckPacket(); + if(type == PacketType.CompletePingCheck) return new CompletePingCheckPacket(); + if(type == PacketType.AgentUpdate) return new AgentUpdatePacket(); + if(type == PacketType.AgentAnimation) return new AgentAnimationPacket(); + if(type == PacketType.AgentRequestSit) return new AgentRequestSitPacket(); + if(type == PacketType.AgentSit) return new AgentSitPacket(); + if(type == PacketType.RequestImage) return new RequestImagePacket(); + if(type == PacketType.ImageData) return new ImageDataPacket(); + if(type == PacketType.ImagePacket) return new ImagePacketPacket(); + if(type == PacketType.LayerData) return new LayerDataPacket(); + if(type == PacketType.ObjectUpdate) return new ObjectUpdatePacket(); + if(type == PacketType.ObjectUpdateCompressed) return new ObjectUpdateCompressedPacket(); + if(type == PacketType.ObjectUpdateCached) return new ObjectUpdateCachedPacket(); + if(type == PacketType.ImprovedTerseObjectUpdate) return new ImprovedTerseObjectUpdatePacket(); + if(type == PacketType.KillObject) return new KillObjectPacket(); + if(type == PacketType.TransferPacket) return new TransferPacketPacket(); + if(type == PacketType.SendXferPacket) return new SendXferPacketPacket(); + if(type == PacketType.ConfirmXferPacket) return new ConfirmXferPacketPacket(); + if(type == PacketType.AvatarAnimation) return new AvatarAnimationPacket(); + if(type == PacketType.AvatarSitResponse) return new AvatarSitResponsePacket(); + if(type == PacketType.CameraConstraint) return new CameraConstraintPacket(); + if(type == PacketType.ParcelProperties) return new ParcelPropertiesPacket(); + if(type == PacketType.ChildAgentUpdate) return new ChildAgentUpdatePacket(); + if(type == PacketType.ChildAgentAlive) return new ChildAgentAlivePacket(); + if(type == PacketType.ChildAgentPositionUpdate) return new ChildAgentPositionUpdatePacket(); + if(type == PacketType.SoundTrigger) return new SoundTriggerPacket(); + if(type == PacketType.ObjectAdd) return new ObjectAddPacket(); + if(type == PacketType.MultipleObjectUpdate) return new MultipleObjectUpdatePacket(); + if(type == PacketType.RequestMultipleObjects) return new RequestMultipleObjectsPacket(); + if(type == PacketType.ObjectPosition) return new ObjectPositionPacket(); + if(type == PacketType.RequestObjectPropertiesFamily) return new RequestObjectPropertiesFamilyPacket(); + if(type == PacketType.CoarseLocationUpdate) return new CoarseLocationUpdatePacket(); + if(type == PacketType.CrossedRegion) return new CrossedRegionPacket(); + if(type == PacketType.ConfirmEnableSimulator) return new ConfirmEnableSimulatorPacket(); + if(type == PacketType.ObjectProperties) return new ObjectPropertiesPacket(); + if(type == PacketType.ObjectPropertiesFamily) return new ObjectPropertiesFamilyPacket(); + if(type == PacketType.ParcelPropertiesRequest) return new ParcelPropertiesRequestPacket(); + if(type == PacketType.AttachedSound) return new AttachedSoundPacket(); + if(type == PacketType.AttachedSoundGainChange) return new AttachedSoundGainChangePacket(); + if(type == PacketType.PreloadSound) return new PreloadSoundPacket(); + if(type == PacketType.ViewerEffect) return new ViewerEffectPacket(); + if(type == PacketType.TestMessage) return new TestMessagePacket(); + if(type == PacketType.UseCircuitCode) return new UseCircuitCodePacket(); + if(type == PacketType.TelehubInfo) return new TelehubInfoPacket(); + if(type == PacketType.EconomyDataRequest) return new EconomyDataRequestPacket(); + if(type == PacketType.EconomyData) return new EconomyDataPacket(); + if(type == PacketType.AvatarPickerRequest) return new AvatarPickerRequestPacket(); + if(type == PacketType.AvatarPickerReply) return new AvatarPickerReplyPacket(); + if(type == PacketType.PlacesQuery) return new PlacesQueryPacket(); + if(type == PacketType.PlacesReply) return new PlacesReplyPacket(); + if(type == PacketType.DirFindQuery) return new DirFindQueryPacket(); + if(type == PacketType.DirPlacesQuery) return new DirPlacesQueryPacket(); + if(type == PacketType.DirPlacesReply) return new DirPlacesReplyPacket(); + if(type == PacketType.DirPeopleReply) return new DirPeopleReplyPacket(); + if(type == PacketType.DirEventsReply) return new DirEventsReplyPacket(); + if(type == PacketType.DirGroupsReply) return new DirGroupsReplyPacket(); + if(type == PacketType.DirClassifiedQuery) return new DirClassifiedQueryPacket(); + if(type == PacketType.DirClassifiedReply) return new DirClassifiedReplyPacket(); + if(type == PacketType.AvatarClassifiedReply) return new AvatarClassifiedReplyPacket(); + if(type == PacketType.ClassifiedInfoRequest) return new ClassifiedInfoRequestPacket(); + if(type == PacketType.ClassifiedInfoReply) return new ClassifiedInfoReplyPacket(); + if(type == PacketType.ClassifiedInfoUpdate) return new ClassifiedInfoUpdatePacket(); + if(type == PacketType.ClassifiedDelete) return new ClassifiedDeletePacket(); + if(type == PacketType.ClassifiedGodDelete) return new ClassifiedGodDeletePacket(); + if(type == PacketType.DirLandQuery) return new DirLandQueryPacket(); + if(type == PacketType.DirLandReply) return new DirLandReplyPacket(); + if(type == PacketType.DirPopularQuery) return new DirPopularQueryPacket(); + if(type == PacketType.DirPopularReply) return new DirPopularReplyPacket(); + if(type == PacketType.ParcelInfoRequest) return new ParcelInfoRequestPacket(); + if(type == PacketType.ParcelInfoReply) return new ParcelInfoReplyPacket(); + if(type == PacketType.ParcelObjectOwnersRequest) return new ParcelObjectOwnersRequestPacket(); + if(type == PacketType.ParcelObjectOwnersReply) return new ParcelObjectOwnersReplyPacket(); + if(type == PacketType.GroupNoticesListRequest) return new GroupNoticesListRequestPacket(); + if(type == PacketType.GroupNoticesListReply) return new GroupNoticesListReplyPacket(); + if(type == PacketType.GroupNoticeRequest) return new GroupNoticeRequestPacket(); + if(type == PacketType.TeleportRequest) return new TeleportRequestPacket(); + if(type == PacketType.TeleportLocationRequest) return new TeleportLocationRequestPacket(); + if(type == PacketType.TeleportLocal) return new TeleportLocalPacket(); + if(type == PacketType.TeleportLandmarkRequest) return new TeleportLandmarkRequestPacket(); + if(type == PacketType.TeleportProgress) return new TeleportProgressPacket(); + if(type == PacketType.TeleportFinish) return new TeleportFinishPacket(); + if(type == PacketType.StartLure) return new StartLurePacket(); + if(type == PacketType.TeleportLureRequest) return new TeleportLureRequestPacket(); + if(type == PacketType.TeleportCancel) return new TeleportCancelPacket(); + if(type == PacketType.TeleportStart) return new TeleportStartPacket(); + if(type == PacketType.TeleportFailed) return new TeleportFailedPacket(); + if(type == PacketType.Undo) return new UndoPacket(); + if(type == PacketType.Redo) return new RedoPacket(); + if(type == PacketType.UndoLand) return new UndoLandPacket(); + if(type == PacketType.AgentPause) return new AgentPausePacket(); + if(type == PacketType.AgentResume) return new AgentResumePacket(); + if(type == PacketType.ChatFromViewer) return new ChatFromViewerPacket(); + if(type == PacketType.AgentThrottle) return new AgentThrottlePacket(); + if(type == PacketType.AgentFOV) return new AgentFOVPacket(); + if(type == PacketType.AgentHeightWidth) return new AgentHeightWidthPacket(); + if(type == PacketType.AgentSetAppearance) return new AgentSetAppearancePacket(); + if(type == PacketType.AgentQuitCopy) return new AgentQuitCopyPacket(); + if(type == PacketType.ImageNotInDatabase) return new ImageNotInDatabasePacket(); + if(type == PacketType.RebakeAvatarTextures) return new RebakeAvatarTexturesPacket(); + if(type == PacketType.SetAlwaysRun) return new SetAlwaysRunPacket(); + if(type == PacketType.ObjectDelete) return new ObjectDeletePacket(); + if(type == PacketType.ObjectDuplicate) return new ObjectDuplicatePacket(); + if(type == PacketType.ObjectDuplicateOnRay) return new ObjectDuplicateOnRayPacket(); + if(type == PacketType.ObjectScale) return new ObjectScalePacket(); + if(type == PacketType.ObjectRotation) return new ObjectRotationPacket(); + if(type == PacketType.ObjectFlagUpdate) return new ObjectFlagUpdatePacket(); + if(type == PacketType.ObjectClickAction) return new ObjectClickActionPacket(); + if(type == PacketType.ObjectImage) return new ObjectImagePacket(); + if(type == PacketType.ObjectMaterial) return new ObjectMaterialPacket(); + if(type == PacketType.ObjectShape) return new ObjectShapePacket(); + if(type == PacketType.ObjectExtraParams) return new ObjectExtraParamsPacket(); + if(type == PacketType.ObjectOwner) return new ObjectOwnerPacket(); + if(type == PacketType.ObjectGroup) return new ObjectGroupPacket(); + if(type == PacketType.ObjectBuy) return new ObjectBuyPacket(); + if(type == PacketType.BuyObjectInventory) return new BuyObjectInventoryPacket(); + if(type == PacketType.DerezContainer) return new DerezContainerPacket(); + if(type == PacketType.ObjectPermissions) return new ObjectPermissionsPacket(); + if(type == PacketType.ObjectSaleInfo) return new ObjectSaleInfoPacket(); + if(type == PacketType.ObjectName) return new ObjectNamePacket(); + if(type == PacketType.ObjectDescription) return new ObjectDescriptionPacket(); + if(type == PacketType.ObjectCategory) return new ObjectCategoryPacket(); + if(type == PacketType.ObjectSelect) return new ObjectSelectPacket(); + if(type == PacketType.ObjectDeselect) return new ObjectDeselectPacket(); + if(type == PacketType.ObjectAttach) return new ObjectAttachPacket(); + if(type == PacketType.ObjectDetach) return new ObjectDetachPacket(); + if(type == PacketType.ObjectDrop) return new ObjectDropPacket(); + if(type == PacketType.ObjectLink) return new ObjectLinkPacket(); + if(type == PacketType.ObjectDelink) return new ObjectDelinkPacket(); + if(type == PacketType.ObjectGrab) return new ObjectGrabPacket(); + if(type == PacketType.ObjectGrabUpdate) return new ObjectGrabUpdatePacket(); + if(type == PacketType.ObjectDeGrab) return new ObjectDeGrabPacket(); + if(type == PacketType.ObjectSpinStart) return new ObjectSpinStartPacket(); + if(type == PacketType.ObjectSpinUpdate) return new ObjectSpinUpdatePacket(); + if(type == PacketType.ObjectSpinStop) return new ObjectSpinStopPacket(); + if(type == PacketType.ObjectExportSelected) return new ObjectExportSelectedPacket(); + if(type == PacketType.ModifyLand) return new ModifyLandPacket(); + if(type == PacketType.VelocityInterpolateOn) return new VelocityInterpolateOnPacket(); + if(type == PacketType.VelocityInterpolateOff) return new VelocityInterpolateOffPacket(); + if(type == PacketType.StateSave) return new StateSavePacket(); + if(type == PacketType.ReportAutosaveCrash) return new ReportAutosaveCrashPacket(); + if(type == PacketType.SimWideDeletes) return new SimWideDeletesPacket(); + if(type == PacketType.TrackAgent) return new TrackAgentPacket(); + if(type == PacketType.ViewerStats) return new ViewerStatsPacket(); + if(type == PacketType.ScriptAnswerYes) return new ScriptAnswerYesPacket(); + if(type == PacketType.UserReport) return new UserReportPacket(); + if(type == PacketType.AlertMessage) return new AlertMessagePacket(); + if(type == PacketType.AgentAlertMessage) return new AgentAlertMessagePacket(); + if(type == PacketType.MeanCollisionAlert) return new MeanCollisionAlertPacket(); + if(type == PacketType.ViewerFrozenMessage) return new ViewerFrozenMessagePacket(); + if(type == PacketType.HealthMessage) return new HealthMessagePacket(); + if(type == PacketType.ChatFromSimulator) return new ChatFromSimulatorPacket(); + if(type == PacketType.SimStats) return new SimStatsPacket(); + if(type == PacketType.RequestRegionInfo) return new RequestRegionInfoPacket(); + if(type == PacketType.RegionInfo) return new RegionInfoPacket(); + if(type == PacketType.GodUpdateRegionInfo) return new GodUpdateRegionInfoPacket(); + if(type == PacketType.RegionHandshake) return new RegionHandshakePacket(); + if(type == PacketType.RegionHandshakeReply) return new RegionHandshakeReplyPacket(); + if(type == PacketType.SimulatorViewerTimeMessage) return new SimulatorViewerTimeMessagePacket(); + if(type == PacketType.EnableSimulator) return new EnableSimulatorPacket(); + if(type == PacketType.DisableSimulator) return new DisableSimulatorPacket(); + if(type == PacketType.TransferRequest) return new TransferRequestPacket(); + if(type == PacketType.TransferInfo) return new TransferInfoPacket(); + if(type == PacketType.TransferAbort) return new TransferAbortPacket(); + if(type == PacketType.RequestXfer) return new RequestXferPacket(); + if(type == PacketType.AbortXfer) return new AbortXferPacket(); + if(type == PacketType.AvatarAppearance) return new AvatarAppearancePacket(); + if(type == PacketType.SetFollowCamProperties) return new SetFollowCamPropertiesPacket(); + if(type == PacketType.ClearFollowCamProperties) return new ClearFollowCamPropertiesPacket(); + if(type == PacketType.RequestPayPrice) return new RequestPayPricePacket(); + if(type == PacketType.PayPriceReply) return new PayPriceReplyPacket(); + if(type == PacketType.KickUser) return new KickUserPacket(); + if(type == PacketType.GodKickUser) return new GodKickUserPacket(); + if(type == PacketType.EjectUser) return new EjectUserPacket(); + if(type == PacketType.FreezeUser) return new FreezeUserPacket(); + if(type == PacketType.AvatarPropertiesRequest) return new AvatarPropertiesRequestPacket(); + if(type == PacketType.AvatarPropertiesReply) return new AvatarPropertiesReplyPacket(); + if(type == PacketType.AvatarInterestsReply) return new AvatarInterestsReplyPacket(); + if(type == PacketType.AvatarGroupsReply) return new AvatarGroupsReplyPacket(); + if(type == PacketType.AvatarPropertiesUpdate) return new AvatarPropertiesUpdatePacket(); + if(type == PacketType.AvatarInterestsUpdate) return new AvatarInterestsUpdatePacket(); + if(type == PacketType.AvatarNotesReply) return new AvatarNotesReplyPacket(); + if(type == PacketType.AvatarNotesUpdate) return new AvatarNotesUpdatePacket(); + if(type == PacketType.AvatarPicksReply) return new AvatarPicksReplyPacket(); + if(type == PacketType.EventInfoRequest) return new EventInfoRequestPacket(); + if(type == PacketType.EventInfoReply) return new EventInfoReplyPacket(); + if(type == PacketType.EventNotificationAddRequest) return new EventNotificationAddRequestPacket(); + if(type == PacketType.EventNotificationRemoveRequest) return new EventNotificationRemoveRequestPacket(); + if(type == PacketType.EventGodDelete) return new EventGodDeletePacket(); + if(type == PacketType.PickInfoReply) return new PickInfoReplyPacket(); + if(type == PacketType.PickInfoUpdate) return new PickInfoUpdatePacket(); + if(type == PacketType.PickDelete) return new PickDeletePacket(); + if(type == PacketType.PickGodDelete) return new PickGodDeletePacket(); + if(type == PacketType.ScriptQuestion) return new ScriptQuestionPacket(); + if(type == PacketType.ScriptControlChange) return new ScriptControlChangePacket(); + if(type == PacketType.ScriptDialog) return new ScriptDialogPacket(); + if(type == PacketType.ScriptDialogReply) return new ScriptDialogReplyPacket(); + if(type == PacketType.ForceScriptControlRelease) return new ForceScriptControlReleasePacket(); + if(type == PacketType.RevokePermissions) return new RevokePermissionsPacket(); + if(type == PacketType.LoadURL) return new LoadURLPacket(); + if(type == PacketType.ScriptTeleportRequest) return new ScriptTeleportRequestPacket(); + if(type == PacketType.ParcelOverlay) return new ParcelOverlayPacket(); + if(type == PacketType.ParcelPropertiesRequestByID) return new ParcelPropertiesRequestByIDPacket(); + if(type == PacketType.ParcelPropertiesUpdate) return new ParcelPropertiesUpdatePacket(); + if(type == PacketType.ParcelReturnObjects) return new ParcelReturnObjectsPacket(); + if(type == PacketType.ParcelSetOtherCleanTime) return new ParcelSetOtherCleanTimePacket(); + if(type == PacketType.ParcelDisableObjects) return new ParcelDisableObjectsPacket(); + if(type == PacketType.ParcelSelectObjects) return new ParcelSelectObjectsPacket(); + if(type == PacketType.EstateCovenantRequest) return new EstateCovenantRequestPacket(); + if(type == PacketType.EstateCovenantReply) return new EstateCovenantReplyPacket(); + if(type == PacketType.ForceObjectSelect) return new ForceObjectSelectPacket(); + if(type == PacketType.ParcelBuyPass) return new ParcelBuyPassPacket(); + if(type == PacketType.ParcelDeedToGroup) return new ParcelDeedToGroupPacket(); + if(type == PacketType.ParcelReclaim) return new ParcelReclaimPacket(); + if(type == PacketType.ParcelClaim) return new ParcelClaimPacket(); + if(type == PacketType.ParcelJoin) return new ParcelJoinPacket(); + if(type == PacketType.ParcelDivide) return new ParcelDividePacket(); + if(type == PacketType.ParcelRelease) return new ParcelReleasePacket(); + if(type == PacketType.ParcelBuy) return new ParcelBuyPacket(); + if(type == PacketType.ParcelGodForceOwner) return new ParcelGodForceOwnerPacket(); + if(type == PacketType.ParcelAccessListRequest) return new ParcelAccessListRequestPacket(); + if(type == PacketType.ParcelAccessListReply) return new ParcelAccessListReplyPacket(); + if(type == PacketType.ParcelAccessListUpdate) return new ParcelAccessListUpdatePacket(); + if(type == PacketType.ParcelDwellRequest) return new ParcelDwellRequestPacket(); + if(type == PacketType.ParcelDwellReply) return new ParcelDwellReplyPacket(); + if(type == PacketType.ParcelGodMarkAsContent) return new ParcelGodMarkAsContentPacket(); + if(type == PacketType.ViewerStartAuction) return new ViewerStartAuctionPacket(); + if(type == PacketType.UUIDNameRequest) return new UUIDNameRequestPacket(); + if(type == PacketType.UUIDNameReply) return new UUIDNameReplyPacket(); + if(type == PacketType.UUIDGroupNameRequest) return new UUIDGroupNameRequestPacket(); + if(type == PacketType.UUIDGroupNameReply) return new UUIDGroupNameReplyPacket(); + if(type == PacketType.ChildAgentDying) return new ChildAgentDyingPacket(); + if(type == PacketType.ChildAgentUnknown) return new ChildAgentUnknownPacket(); + if(type == PacketType.GetScriptRunning) return new GetScriptRunningPacket(); + if(type == PacketType.ScriptRunningReply) return new ScriptRunningReplyPacket(); + if(type == PacketType.SetScriptRunning) return new SetScriptRunningPacket(); + if(type == PacketType.ScriptReset) return new ScriptResetPacket(); + if(type == PacketType.ScriptSensorRequest) return new ScriptSensorRequestPacket(); + if(type == PacketType.ScriptSensorReply) return new ScriptSensorReplyPacket(); + if(type == PacketType.CompleteAgentMovement) return new CompleteAgentMovementPacket(); + if(type == PacketType.AgentMovementComplete) return new AgentMovementCompletePacket(); + if(type == PacketType.LogoutRequest) return new LogoutRequestPacket(); + if(type == PacketType.LogoutReply) return new LogoutReplyPacket(); + if(type == PacketType.ImprovedInstantMessage) return new ImprovedInstantMessagePacket(); + if(type == PacketType.RetrieveInstantMessages) return new RetrieveInstantMessagesPacket(); + if(type == PacketType.FindAgent) return new FindAgentPacket(); + if(type == PacketType.RequestGodlikePowers) return new RequestGodlikePowersPacket(); + if(type == PacketType.GrantGodlikePowers) return new GrantGodlikePowersPacket(); + if(type == PacketType.GodlikeMessage) return new GodlikeMessagePacket(); + if(type == PacketType.EstateOwnerMessage) return new EstateOwnerMessagePacket(); + if(type == PacketType.GenericMessage) return new GenericMessagePacket(); + if(type == PacketType.MuteListRequest) return new MuteListRequestPacket(); + if(type == PacketType.UpdateMuteListEntry) return new UpdateMuteListEntryPacket(); + if(type == PacketType.RemoveMuteListEntry) return new RemoveMuteListEntryPacket(); + if(type == PacketType.CopyInventoryFromNotecard) return new CopyInventoryFromNotecardPacket(); + if(type == PacketType.UpdateInventoryItem) return new UpdateInventoryItemPacket(); + if(type == PacketType.UpdateCreateInventoryItem) return new UpdateCreateInventoryItemPacket(); + if(type == PacketType.MoveInventoryItem) return new MoveInventoryItemPacket(); + if(type == PacketType.CopyInventoryItem) return new CopyInventoryItemPacket(); + if(type == PacketType.RemoveInventoryItem) return new RemoveInventoryItemPacket(); + if(type == PacketType.ChangeInventoryItemFlags) return new ChangeInventoryItemFlagsPacket(); + if(type == PacketType.SaveAssetIntoInventory) return new SaveAssetIntoInventoryPacket(); + if(type == PacketType.CreateInventoryFolder) return new CreateInventoryFolderPacket(); + if(type == PacketType.UpdateInventoryFolder) return new UpdateInventoryFolderPacket(); + if(type == PacketType.MoveInventoryFolder) return new MoveInventoryFolderPacket(); + if(type == PacketType.RemoveInventoryFolder) return new RemoveInventoryFolderPacket(); + if(type == PacketType.FetchInventoryDescendents) return new FetchInventoryDescendentsPacket(); + if(type == PacketType.InventoryDescendents) return new InventoryDescendentsPacket(); + if(type == PacketType.FetchInventory) return new FetchInventoryPacket(); + if(type == PacketType.FetchInventoryReply) return new FetchInventoryReplyPacket(); + if(type == PacketType.BulkUpdateInventory) return new BulkUpdateInventoryPacket(); + if(type == PacketType.RemoveInventoryObjects) return new RemoveInventoryObjectsPacket(); + if(type == PacketType.PurgeInventoryDescendents) return new PurgeInventoryDescendentsPacket(); + if(type == PacketType.UpdateTaskInventory) return new UpdateTaskInventoryPacket(); + if(type == PacketType.RemoveTaskInventory) return new RemoveTaskInventoryPacket(); + if(type == PacketType.MoveTaskInventory) return new MoveTaskInventoryPacket(); + if(type == PacketType.RequestTaskInventory) return new RequestTaskInventoryPacket(); + if(type == PacketType.ReplyTaskInventory) return new ReplyTaskInventoryPacket(); + if(type == PacketType.DeRezObject) return new DeRezObjectPacket(); + if(type == PacketType.DeRezAck) return new DeRezAckPacket(); + if(type == PacketType.RezObject) return new RezObjectPacket(); + if(type == PacketType.RezObjectFromNotecard) return new RezObjectFromNotecardPacket(); + if(type == PacketType.AcceptFriendship) return new AcceptFriendshipPacket(); + if(type == PacketType.DeclineFriendship) return new DeclineFriendshipPacket(); + if(type == PacketType.TerminateFriendship) return new TerminateFriendshipPacket(); + if(type == PacketType.OfferCallingCard) return new OfferCallingCardPacket(); + if(type == PacketType.AcceptCallingCard) return new AcceptCallingCardPacket(); + if(type == PacketType.DeclineCallingCard) return new DeclineCallingCardPacket(); + if(type == PacketType.RezScript) return new RezScriptPacket(); + if(type == PacketType.CreateInventoryItem) return new CreateInventoryItemPacket(); + if(type == PacketType.CreateLandmarkForEvent) return new CreateLandmarkForEventPacket(); + if(type == PacketType.RegionHandleRequest) return new RegionHandleRequestPacket(); + if(type == PacketType.RegionIDAndHandleReply) return new RegionIDAndHandleReplyPacket(); + if(type == PacketType.MoneyTransferRequest) return new MoneyTransferRequestPacket(); + if(type == PacketType.MoneyBalanceRequest) return new MoneyBalanceRequestPacket(); + if(type == PacketType.MoneyBalanceReply) return new MoneyBalanceReplyPacket(); + if(type == PacketType.RoutedMoneyBalanceReply) return new RoutedMoneyBalanceReplyPacket(); + if(type == PacketType.ActivateGestures) return new ActivateGesturesPacket(); + if(type == PacketType.DeactivateGestures) return new DeactivateGesturesPacket(); + if(type == PacketType.MuteListUpdate) return new MuteListUpdatePacket(); + if(type == PacketType.UseCachedMuteList) return new UseCachedMuteListPacket(); + if(type == PacketType.GrantUserRights) return new GrantUserRightsPacket(); + if(type == PacketType.ChangeUserRights) return new ChangeUserRightsPacket(); + if(type == PacketType.OnlineNotification) return new OnlineNotificationPacket(); + if(type == PacketType.OfflineNotification) return new OfflineNotificationPacket(); + if(type == PacketType.SetStartLocationRequest) return new SetStartLocationRequestPacket(); + if(type == PacketType.AssetUploadRequest) return new AssetUploadRequestPacket(); + if(type == PacketType.AssetUploadComplete) return new AssetUploadCompletePacket(); + if(type == PacketType.CreateGroupRequest) return new CreateGroupRequestPacket(); + if(type == PacketType.CreateGroupReply) return new CreateGroupReplyPacket(); + if(type == PacketType.UpdateGroupInfo) return new UpdateGroupInfoPacket(); + if(type == PacketType.GroupRoleChanges) return new GroupRoleChangesPacket(); + if(type == PacketType.JoinGroupRequest) return new JoinGroupRequestPacket(); + if(type == PacketType.JoinGroupReply) return new JoinGroupReplyPacket(); + if(type == PacketType.EjectGroupMemberRequest) return new EjectGroupMemberRequestPacket(); + if(type == PacketType.EjectGroupMemberReply) return new EjectGroupMemberReplyPacket(); + if(type == PacketType.LeaveGroupRequest) return new LeaveGroupRequestPacket(); + if(type == PacketType.LeaveGroupReply) return new LeaveGroupReplyPacket(); + if(type == PacketType.InviteGroupRequest) return new InviteGroupRequestPacket(); + if(type == PacketType.GroupProfileRequest) return new GroupProfileRequestPacket(); + if(type == PacketType.GroupProfileReply) return new GroupProfileReplyPacket(); + if(type == PacketType.GroupAccountSummaryRequest) return new GroupAccountSummaryRequestPacket(); + if(type == PacketType.GroupAccountSummaryReply) return new GroupAccountSummaryReplyPacket(); + if(type == PacketType.GroupAccountDetailsRequest) return new GroupAccountDetailsRequestPacket(); + if(type == PacketType.GroupAccountDetailsReply) return new GroupAccountDetailsReplyPacket(); + if(type == PacketType.GroupAccountTransactionsRequest) return new GroupAccountTransactionsRequestPacket(); + if(type == PacketType.GroupAccountTransactionsReply) return new GroupAccountTransactionsReplyPacket(); + if(type == PacketType.GroupActiveProposalsRequest) return new GroupActiveProposalsRequestPacket(); + if(type == PacketType.GroupActiveProposalItemReply) return new GroupActiveProposalItemReplyPacket(); + if(type == PacketType.GroupVoteHistoryRequest) return new GroupVoteHistoryRequestPacket(); + if(type == PacketType.GroupVoteHistoryItemReply) return new GroupVoteHistoryItemReplyPacket(); + if(type == PacketType.StartGroupProposal) return new StartGroupProposalPacket(); + if(type == PacketType.GroupProposalBallot) return new GroupProposalBallotPacket(); + if(type == PacketType.GroupMembersRequest) return new GroupMembersRequestPacket(); + if(type == PacketType.GroupMembersReply) return new GroupMembersReplyPacket(); + if(type == PacketType.ActivateGroup) return new ActivateGroupPacket(); + if(type == PacketType.SetGroupContribution) return new SetGroupContributionPacket(); + if(type == PacketType.SetGroupAcceptNotices) return new SetGroupAcceptNoticesPacket(); + if(type == PacketType.GroupRoleDataRequest) return new GroupRoleDataRequestPacket(); + if(type == PacketType.GroupRoleDataReply) return new GroupRoleDataReplyPacket(); + if(type == PacketType.GroupRoleMembersRequest) return new GroupRoleMembersRequestPacket(); + if(type == PacketType.GroupRoleMembersReply) return new GroupRoleMembersReplyPacket(); + if(type == PacketType.GroupTitlesRequest) return new GroupTitlesRequestPacket(); + if(type == PacketType.GroupTitlesReply) return new GroupTitlesReplyPacket(); + if(type == PacketType.GroupTitleUpdate) return new GroupTitleUpdatePacket(); + if(type == PacketType.GroupRoleUpdate) return new GroupRoleUpdatePacket(); + if(type == PacketType.LiveHelpGroupRequest) return new LiveHelpGroupRequestPacket(); + if(type == PacketType.LiveHelpGroupReply) return new LiveHelpGroupReplyPacket(); + if(type == PacketType.AgentWearablesRequest) return new AgentWearablesRequestPacket(); + if(type == PacketType.AgentWearablesUpdate) return new AgentWearablesUpdatePacket(); + if(type == PacketType.AgentIsNowWearing) return new AgentIsNowWearingPacket(); + if(type == PacketType.AgentCachedTexture) return new AgentCachedTexturePacket(); + if(type == PacketType.AgentCachedTextureResponse) return new AgentCachedTextureResponsePacket(); + if(type == PacketType.AgentDataUpdateRequest) return new AgentDataUpdateRequestPacket(); + if(type == PacketType.AgentDataUpdate) return new AgentDataUpdatePacket(); + if(type == PacketType.GroupDataUpdate) return new GroupDataUpdatePacket(); + if(type == PacketType.AgentGroupDataUpdate) return new AgentGroupDataUpdatePacket(); + if(type == PacketType.AgentDropGroup) return new AgentDropGroupPacket(); + if(type == PacketType.RezSingleAttachmentFromInv) return new RezSingleAttachmentFromInvPacket(); + if(type == PacketType.RezMultipleAttachmentsFromInv) return new RezMultipleAttachmentsFromInvPacket(); + if(type == PacketType.DetachAttachmentIntoInv) return new DetachAttachmentIntoInvPacket(); + if(type == PacketType.CreateNewOutfitAttachments) return new CreateNewOutfitAttachmentsPacket(); + if(type == PacketType.UserInfoRequest) return new UserInfoRequestPacket(); + if(type == PacketType.UserInfoReply) return new UserInfoReplyPacket(); + if(type == PacketType.UpdateUserInfo) return new UpdateUserInfoPacket(); + if(type == PacketType.InitiateDownload) return new InitiateDownloadPacket(); + if(type == PacketType.MapLayerRequest) return new MapLayerRequestPacket(); + if(type == PacketType.MapLayerReply) return new MapLayerReplyPacket(); + if(type == PacketType.MapBlockRequest) return new MapBlockRequestPacket(); + if(type == PacketType.MapNameRequest) return new MapNameRequestPacket(); + if(type == PacketType.MapBlockReply) return new MapBlockReplyPacket(); + if(type == PacketType.MapItemRequest) return new MapItemRequestPacket(); + if(type == PacketType.MapItemReply) return new MapItemReplyPacket(); + if(type == PacketType.SendPostcard) return new SendPostcardPacket(); + if(type == PacketType.ParcelMediaCommandMessage) return new ParcelMediaCommandMessagePacket(); + if(type == PacketType.ParcelMediaUpdate) return new ParcelMediaUpdatePacket(); + if(type == PacketType.LandStatRequest) return new LandStatRequestPacket(); + if(type == PacketType.LandStatReply) return new LandStatReplyPacket(); + if(type == PacketType.Error) return new ErrorPacket(); + if(type == PacketType.ObjectIncludeInSearch) return new ObjectIncludeInSearchPacket(); + if(type == PacketType.RezRestoreToWorld) return new RezRestoreToWorldPacket(); + if(type == PacketType.LinkInventoryItem) return new LinkInventoryItemPacket(); + if(type == PacketType.PacketAck) return new PacketAckPacket(); + if(type == PacketType.OpenCircuit) return new OpenCircuitPacket(); + if(type == PacketType.CloseCircuit) return new CloseCircuitPacket(); + return null; + + } + + public static Packet BuildPacket(byte[] packetBuffer, ref int packetEnd, byte[] zeroBuffer) + { + byte[] bytes; + int i = 0; + Header header = Header.BuildHeader(packetBuffer, ref i, ref packetEnd); + if (header.Zerocoded) + { + packetEnd = Helpers.ZeroDecode(packetBuffer, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + else + { + bytes = packetBuffer; + } + Array.Clear(bytes, packetEnd + 1, bytes.Length - packetEnd - 1); + + switch (header.Frequency) + { + case PacketFrequency.Low: + switch (header.ID) + { + case 1: return new TestMessagePacket(header, bytes, ref i); + case 3: return new UseCircuitCodePacket(header, bytes, ref i); + case 10: return new TelehubInfoPacket(header, bytes, ref i); + case 24: return new EconomyDataRequestPacket(header, bytes, ref i); + case 25: return new EconomyDataPacket(header, bytes, ref i); + case 26: return new AvatarPickerRequestPacket(header, bytes, ref i); + case 28: return new AvatarPickerReplyPacket(header, bytes, ref i); + case 29: return new PlacesQueryPacket(header, bytes, ref i); + case 30: return new PlacesReplyPacket(header, bytes, ref i); + case 31: return new DirFindQueryPacket(header, bytes, ref i); + case 33: return new DirPlacesQueryPacket(header, bytes, ref i); + case 35: return new DirPlacesReplyPacket(header, bytes, ref i); + case 36: return new DirPeopleReplyPacket(header, bytes, ref i); + case 37: return new DirEventsReplyPacket(header, bytes, ref i); + case 38: return new DirGroupsReplyPacket(header, bytes, ref i); + case 39: return new DirClassifiedQueryPacket(header, bytes, ref i); + case 41: return new DirClassifiedReplyPacket(header, bytes, ref i); + case 42: return new AvatarClassifiedReplyPacket(header, bytes, ref i); + case 43: return new ClassifiedInfoRequestPacket(header, bytes, ref i); + case 44: return new ClassifiedInfoReplyPacket(header, bytes, ref i); + case 45: return new ClassifiedInfoUpdatePacket(header, bytes, ref i); + case 46: return new ClassifiedDeletePacket(header, bytes, ref i); + case 47: return new ClassifiedGodDeletePacket(header, bytes, ref i); + case 48: return new DirLandQueryPacket(header, bytes, ref i); + case 50: return new DirLandReplyPacket(header, bytes, ref i); + case 51: return new DirPopularQueryPacket(header, bytes, ref i); + case 53: return new DirPopularReplyPacket(header, bytes, ref i); + case 54: return new ParcelInfoRequestPacket(header, bytes, ref i); + case 55: return new ParcelInfoReplyPacket(header, bytes, ref i); + case 56: return new ParcelObjectOwnersRequestPacket(header, bytes, ref i); + case 57: return new ParcelObjectOwnersReplyPacket(header, bytes, ref i); + case 58: return new GroupNoticesListRequestPacket(header, bytes, ref i); + case 59: return new GroupNoticesListReplyPacket(header, bytes, ref i); + case 60: return new GroupNoticeRequestPacket(header, bytes, ref i); + case 62: return new TeleportRequestPacket(header, bytes, ref i); + case 63: return new TeleportLocationRequestPacket(header, bytes, ref i); + case 64: return new TeleportLocalPacket(header, bytes, ref i); + case 65: return new TeleportLandmarkRequestPacket(header, bytes, ref i); + case 66: return new TeleportProgressPacket(header, bytes, ref i); + case 69: return new TeleportFinishPacket(header, bytes, ref i); + case 70: return new StartLurePacket(header, bytes, ref i); + case 71: return new TeleportLureRequestPacket(header, bytes, ref i); + case 72: return new TeleportCancelPacket(header, bytes, ref i); + case 73: return new TeleportStartPacket(header, bytes, ref i); + case 74: return new TeleportFailedPacket(header, bytes, ref i); + case 75: return new UndoPacket(header, bytes, ref i); + case 76: return new RedoPacket(header, bytes, ref i); + case 77: return new UndoLandPacket(header, bytes, ref i); + case 78: return new AgentPausePacket(header, bytes, ref i); + case 79: return new AgentResumePacket(header, bytes, ref i); + case 80: return new ChatFromViewerPacket(header, bytes, ref i); + case 81: return new AgentThrottlePacket(header, bytes, ref i); + case 82: return new AgentFOVPacket(header, bytes, ref i); + case 83: return new AgentHeightWidthPacket(header, bytes, ref i); + case 84: return new AgentSetAppearancePacket(header, bytes, ref i); + case 85: return new AgentQuitCopyPacket(header, bytes, ref i); + case 86: return new ImageNotInDatabasePacket(header, bytes, ref i); + case 87: return new RebakeAvatarTexturesPacket(header, bytes, ref i); + case 88: return new SetAlwaysRunPacket(header, bytes, ref i); + case 89: return new ObjectDeletePacket(header, bytes, ref i); + case 90: return new ObjectDuplicatePacket(header, bytes, ref i); + case 91: return new ObjectDuplicateOnRayPacket(header, bytes, ref i); + case 92: return new ObjectScalePacket(header, bytes, ref i); + case 93: return new ObjectRotationPacket(header, bytes, ref i); + case 94: return new ObjectFlagUpdatePacket(header, bytes, ref i); + case 95: return new ObjectClickActionPacket(header, bytes, ref i); + case 96: return new ObjectImagePacket(header, bytes, ref i); + case 97: return new ObjectMaterialPacket(header, bytes, ref i); + case 98: return new ObjectShapePacket(header, bytes, ref i); + case 99: return new ObjectExtraParamsPacket(header, bytes, ref i); + case 100: return new ObjectOwnerPacket(header, bytes, ref i); + case 101: return new ObjectGroupPacket(header, bytes, ref i); + case 102: return new ObjectBuyPacket(header, bytes, ref i); + case 103: return new BuyObjectInventoryPacket(header, bytes, ref i); + case 104: return new DerezContainerPacket(header, bytes, ref i); + case 105: return new ObjectPermissionsPacket(header, bytes, ref i); + case 106: return new ObjectSaleInfoPacket(header, bytes, ref i); + case 107: return new ObjectNamePacket(header, bytes, ref i); + case 108: return new ObjectDescriptionPacket(header, bytes, ref i); + case 109: return new ObjectCategoryPacket(header, bytes, ref i); + case 110: return new ObjectSelectPacket(header, bytes, ref i); + case 111: return new ObjectDeselectPacket(header, bytes, ref i); + case 112: return new ObjectAttachPacket(header, bytes, ref i); + case 113: return new ObjectDetachPacket(header, bytes, ref i); + case 114: return new ObjectDropPacket(header, bytes, ref i); + case 115: return new ObjectLinkPacket(header, bytes, ref i); + case 116: return new ObjectDelinkPacket(header, bytes, ref i); + case 117: return new ObjectGrabPacket(header, bytes, ref i); + case 118: return new ObjectGrabUpdatePacket(header, bytes, ref i); + case 119: return new ObjectDeGrabPacket(header, bytes, ref i); + case 120: return new ObjectSpinStartPacket(header, bytes, ref i); + case 121: return new ObjectSpinUpdatePacket(header, bytes, ref i); + case 122: return new ObjectSpinStopPacket(header, bytes, ref i); + case 123: return new ObjectExportSelectedPacket(header, bytes, ref i); + case 124: return new ModifyLandPacket(header, bytes, ref i); + case 125: return new VelocityInterpolateOnPacket(header, bytes, ref i); + case 126: return new VelocityInterpolateOffPacket(header, bytes, ref i); + case 127: return new StateSavePacket(header, bytes, ref i); + case 128: return new ReportAutosaveCrashPacket(header, bytes, ref i); + case 129: return new SimWideDeletesPacket(header, bytes, ref i); + case 130: return new TrackAgentPacket(header, bytes, ref i); + case 131: return new ViewerStatsPacket(header, bytes, ref i); + case 132: return new ScriptAnswerYesPacket(header, bytes, ref i); + case 133: return new UserReportPacket(header, bytes, ref i); + case 134: return new AlertMessagePacket(header, bytes, ref i); + case 135: return new AgentAlertMessagePacket(header, bytes, ref i); + case 136: return new MeanCollisionAlertPacket(header, bytes, ref i); + case 137: return new ViewerFrozenMessagePacket(header, bytes, ref i); + case 138: return new HealthMessagePacket(header, bytes, ref i); + case 139: return new ChatFromSimulatorPacket(header, bytes, ref i); + case 140: return new SimStatsPacket(header, bytes, ref i); + case 141: return new RequestRegionInfoPacket(header, bytes, ref i); + case 142: return new RegionInfoPacket(header, bytes, ref i); + case 143: return new GodUpdateRegionInfoPacket(header, bytes, ref i); + case 148: return new RegionHandshakePacket(header, bytes, ref i); + case 149: return new RegionHandshakeReplyPacket(header, bytes, ref i); + case 150: return new SimulatorViewerTimeMessagePacket(header, bytes, ref i); + case 151: return new EnableSimulatorPacket(header, bytes, ref i); + case 152: return new DisableSimulatorPacket(header, bytes, ref i); + case 153: return new TransferRequestPacket(header, bytes, ref i); + case 154: return new TransferInfoPacket(header, bytes, ref i); + case 155: return new TransferAbortPacket(header, bytes, ref i); + case 156: return new RequestXferPacket(header, bytes, ref i); + case 157: return new AbortXferPacket(header, bytes, ref i); + case 158: return new AvatarAppearancePacket(header, bytes, ref i); + case 159: return new SetFollowCamPropertiesPacket(header, bytes, ref i); + case 160: return new ClearFollowCamPropertiesPacket(header, bytes, ref i); + case 161: return new RequestPayPricePacket(header, bytes, ref i); + case 162: return new PayPriceReplyPacket(header, bytes, ref i); + case 163: return new KickUserPacket(header, bytes, ref i); + case 165: return new GodKickUserPacket(header, bytes, ref i); + case 167: return new EjectUserPacket(header, bytes, ref i); + case 168: return new FreezeUserPacket(header, bytes, ref i); + case 169: return new AvatarPropertiesRequestPacket(header, bytes, ref i); + case 171: return new AvatarPropertiesReplyPacket(header, bytes, ref i); + case 172: return new AvatarInterestsReplyPacket(header, bytes, ref i); + case 173: return new AvatarGroupsReplyPacket(header, bytes, ref i); + case 174: return new AvatarPropertiesUpdatePacket(header, bytes, ref i); + case 175: return new AvatarInterestsUpdatePacket(header, bytes, ref i); + case 176: return new AvatarNotesReplyPacket(header, bytes, ref i); + case 177: return new AvatarNotesUpdatePacket(header, bytes, ref i); + case 178: return new AvatarPicksReplyPacket(header, bytes, ref i); + case 179: return new EventInfoRequestPacket(header, bytes, ref i); + case 180: return new EventInfoReplyPacket(header, bytes, ref i); + case 181: return new EventNotificationAddRequestPacket(header, bytes, ref i); + case 182: return new EventNotificationRemoveRequestPacket(header, bytes, ref i); + case 183: return new EventGodDeletePacket(header, bytes, ref i); + case 184: return new PickInfoReplyPacket(header, bytes, ref i); + case 185: return new PickInfoUpdatePacket(header, bytes, ref i); + case 186: return new PickDeletePacket(header, bytes, ref i); + case 187: return new PickGodDeletePacket(header, bytes, ref i); + case 188: return new ScriptQuestionPacket(header, bytes, ref i); + case 189: return new ScriptControlChangePacket(header, bytes, ref i); + case 190: return new ScriptDialogPacket(header, bytes, ref i); + case 191: return new ScriptDialogReplyPacket(header, bytes, ref i); + case 192: return new ForceScriptControlReleasePacket(header, bytes, ref i); + case 193: return new RevokePermissionsPacket(header, bytes, ref i); + case 194: return new LoadURLPacket(header, bytes, ref i); + case 195: return new ScriptTeleportRequestPacket(header, bytes, ref i); + case 196: return new ParcelOverlayPacket(header, bytes, ref i); + case 197: return new ParcelPropertiesRequestByIDPacket(header, bytes, ref i); + case 198: return new ParcelPropertiesUpdatePacket(header, bytes, ref i); + case 199: return new ParcelReturnObjectsPacket(header, bytes, ref i); + case 200: return new ParcelSetOtherCleanTimePacket(header, bytes, ref i); + case 201: return new ParcelDisableObjectsPacket(header, bytes, ref i); + case 202: return new ParcelSelectObjectsPacket(header, bytes, ref i); + case 203: return new EstateCovenantRequestPacket(header, bytes, ref i); + case 204: return new EstateCovenantReplyPacket(header, bytes, ref i); + case 205: return new ForceObjectSelectPacket(header, bytes, ref i); + case 206: return new ParcelBuyPassPacket(header, bytes, ref i); + case 207: return new ParcelDeedToGroupPacket(header, bytes, ref i); + case 208: return new ParcelReclaimPacket(header, bytes, ref i); + case 209: return new ParcelClaimPacket(header, bytes, ref i); + case 210: return new ParcelJoinPacket(header, bytes, ref i); + case 211: return new ParcelDividePacket(header, bytes, ref i); + case 212: return new ParcelReleasePacket(header, bytes, ref i); + case 213: return new ParcelBuyPacket(header, bytes, ref i); + case 214: return new ParcelGodForceOwnerPacket(header, bytes, ref i); + case 215: return new ParcelAccessListRequestPacket(header, bytes, ref i); + case 216: return new ParcelAccessListReplyPacket(header, bytes, ref i); + case 217: return new ParcelAccessListUpdatePacket(header, bytes, ref i); + case 218: return new ParcelDwellRequestPacket(header, bytes, ref i); + case 219: return new ParcelDwellReplyPacket(header, bytes, ref i); + case 227: return new ParcelGodMarkAsContentPacket(header, bytes, ref i); + case 228: return new ViewerStartAuctionPacket(header, bytes, ref i); + case 235: return new UUIDNameRequestPacket(header, bytes, ref i); + case 236: return new UUIDNameReplyPacket(header, bytes, ref i); + case 237: return new UUIDGroupNameRequestPacket(header, bytes, ref i); + case 238: return new UUIDGroupNameReplyPacket(header, bytes, ref i); + case 240: return new ChildAgentDyingPacket(header, bytes, ref i); + case 241: return new ChildAgentUnknownPacket(header, bytes, ref i); + case 243: return new GetScriptRunningPacket(header, bytes, ref i); + case 244: return new ScriptRunningReplyPacket(header, bytes, ref i); + case 245: return new SetScriptRunningPacket(header, bytes, ref i); + case 246: return new ScriptResetPacket(header, bytes, ref i); + case 247: return new ScriptSensorRequestPacket(header, bytes, ref i); + case 248: return new ScriptSensorReplyPacket(header, bytes, ref i); + case 249: return new CompleteAgentMovementPacket(header, bytes, ref i); + case 250: return new AgentMovementCompletePacket(header, bytes, ref i); + case 252: return new LogoutRequestPacket(header, bytes, ref i); + case 253: return new LogoutReplyPacket(header, bytes, ref i); + case 254: return new ImprovedInstantMessagePacket(header, bytes, ref i); + case 255: return new RetrieveInstantMessagesPacket(header, bytes, ref i); + case 256: return new FindAgentPacket(header, bytes, ref i); + case 257: return new RequestGodlikePowersPacket(header, bytes, ref i); + case 258: return new GrantGodlikePowersPacket(header, bytes, ref i); + case 259: return new GodlikeMessagePacket(header, bytes, ref i); + case 260: return new EstateOwnerMessagePacket(header, bytes, ref i); + case 261: return new GenericMessagePacket(header, bytes, ref i); + case 262: return new MuteListRequestPacket(header, bytes, ref i); + case 263: return new UpdateMuteListEntryPacket(header, bytes, ref i); + case 264: return new RemoveMuteListEntryPacket(header, bytes, ref i); + case 265: return new CopyInventoryFromNotecardPacket(header, bytes, ref i); + case 266: return new UpdateInventoryItemPacket(header, bytes, ref i); + case 267: return new UpdateCreateInventoryItemPacket(header, bytes, ref i); + case 268: return new MoveInventoryItemPacket(header, bytes, ref i); + case 269: return new CopyInventoryItemPacket(header, bytes, ref i); + case 270: return new RemoveInventoryItemPacket(header, bytes, ref i); + case 271: return new ChangeInventoryItemFlagsPacket(header, bytes, ref i); + case 272: return new SaveAssetIntoInventoryPacket(header, bytes, ref i); + case 273: return new CreateInventoryFolderPacket(header, bytes, ref i); + case 274: return new UpdateInventoryFolderPacket(header, bytes, ref i); + case 275: return new MoveInventoryFolderPacket(header, bytes, ref i); + case 276: return new RemoveInventoryFolderPacket(header, bytes, ref i); + case 277: return new FetchInventoryDescendentsPacket(header, bytes, ref i); + case 278: return new InventoryDescendentsPacket(header, bytes, ref i); + case 279: return new FetchInventoryPacket(header, bytes, ref i); + case 280: return new FetchInventoryReplyPacket(header, bytes, ref i); + case 281: return new BulkUpdateInventoryPacket(header, bytes, ref i); + case 284: return new RemoveInventoryObjectsPacket(header, bytes, ref i); + case 285: return new PurgeInventoryDescendentsPacket(header, bytes, ref i); + case 286: return new UpdateTaskInventoryPacket(header, bytes, ref i); + case 287: return new RemoveTaskInventoryPacket(header, bytes, ref i); + case 288: return new MoveTaskInventoryPacket(header, bytes, ref i); + case 289: return new RequestTaskInventoryPacket(header, bytes, ref i); + case 290: return new ReplyTaskInventoryPacket(header, bytes, ref i); + case 291: return new DeRezObjectPacket(header, bytes, ref i); + case 292: return new DeRezAckPacket(header, bytes, ref i); + case 293: return new RezObjectPacket(header, bytes, ref i); + case 294: return new RezObjectFromNotecardPacket(header, bytes, ref i); + case 297: return new AcceptFriendshipPacket(header, bytes, ref i); + case 298: return new DeclineFriendshipPacket(header, bytes, ref i); + case 300: return new TerminateFriendshipPacket(header, bytes, ref i); + case 301: return new OfferCallingCardPacket(header, bytes, ref i); + case 302: return new AcceptCallingCardPacket(header, bytes, ref i); + case 303: return new DeclineCallingCardPacket(header, bytes, ref i); + case 304: return new RezScriptPacket(header, bytes, ref i); + case 305: return new CreateInventoryItemPacket(header, bytes, ref i); + case 306: return new CreateLandmarkForEventPacket(header, bytes, ref i); + case 309: return new RegionHandleRequestPacket(header, bytes, ref i); + case 310: return new RegionIDAndHandleReplyPacket(header, bytes, ref i); + case 311: return new MoneyTransferRequestPacket(header, bytes, ref i); + case 313: return new MoneyBalanceRequestPacket(header, bytes, ref i); + case 314: return new MoneyBalanceReplyPacket(header, bytes, ref i); + case 315: return new RoutedMoneyBalanceReplyPacket(header, bytes, ref i); + case 316: return new ActivateGesturesPacket(header, bytes, ref i); + case 317: return new DeactivateGesturesPacket(header, bytes, ref i); + case 318: return new MuteListUpdatePacket(header, bytes, ref i); + case 319: return new UseCachedMuteListPacket(header, bytes, ref i); + case 320: return new GrantUserRightsPacket(header, bytes, ref i); + case 321: return new ChangeUserRightsPacket(header, bytes, ref i); + case 322: return new OnlineNotificationPacket(header, bytes, ref i); + case 323: return new OfflineNotificationPacket(header, bytes, ref i); + case 324: return new SetStartLocationRequestPacket(header, bytes, ref i); + case 333: return new AssetUploadRequestPacket(header, bytes, ref i); + case 334: return new AssetUploadCompletePacket(header, bytes, ref i); + case 339: return new CreateGroupRequestPacket(header, bytes, ref i); + case 340: return new CreateGroupReplyPacket(header, bytes, ref i); + case 341: return new UpdateGroupInfoPacket(header, bytes, ref i); + case 342: return new GroupRoleChangesPacket(header, bytes, ref i); + case 343: return new JoinGroupRequestPacket(header, bytes, ref i); + case 344: return new JoinGroupReplyPacket(header, bytes, ref i); + case 345: return new EjectGroupMemberRequestPacket(header, bytes, ref i); + case 346: return new EjectGroupMemberReplyPacket(header, bytes, ref i); + case 347: return new LeaveGroupRequestPacket(header, bytes, ref i); + case 348: return new LeaveGroupReplyPacket(header, bytes, ref i); + case 349: return new InviteGroupRequestPacket(header, bytes, ref i); + case 351: return new GroupProfileRequestPacket(header, bytes, ref i); + case 352: return new GroupProfileReplyPacket(header, bytes, ref i); + case 353: return new GroupAccountSummaryRequestPacket(header, bytes, ref i); + case 354: return new GroupAccountSummaryReplyPacket(header, bytes, ref i); + case 355: return new GroupAccountDetailsRequestPacket(header, bytes, ref i); + case 356: return new GroupAccountDetailsReplyPacket(header, bytes, ref i); + case 357: return new GroupAccountTransactionsRequestPacket(header, bytes, ref i); + case 358: return new GroupAccountTransactionsReplyPacket(header, bytes, ref i); + case 359: return new GroupActiveProposalsRequestPacket(header, bytes, ref i); + case 360: return new GroupActiveProposalItemReplyPacket(header, bytes, ref i); + case 361: return new GroupVoteHistoryRequestPacket(header, bytes, ref i); + case 362: return new GroupVoteHistoryItemReplyPacket(header, bytes, ref i); + case 363: return new StartGroupProposalPacket(header, bytes, ref i); + case 364: return new GroupProposalBallotPacket(header, bytes, ref i); + case 366: return new GroupMembersRequestPacket(header, bytes, ref i); + case 367: return new GroupMembersReplyPacket(header, bytes, ref i); + case 368: return new ActivateGroupPacket(header, bytes, ref i); + case 369: return new SetGroupContributionPacket(header, bytes, ref i); + case 370: return new SetGroupAcceptNoticesPacket(header, bytes, ref i); + case 371: return new GroupRoleDataRequestPacket(header, bytes, ref i); + case 372: return new GroupRoleDataReplyPacket(header, bytes, ref i); + case 373: return new GroupRoleMembersRequestPacket(header, bytes, ref i); + case 374: return new GroupRoleMembersReplyPacket(header, bytes, ref i); + case 375: return new GroupTitlesRequestPacket(header, bytes, ref i); + case 376: return new GroupTitlesReplyPacket(header, bytes, ref i); + case 377: return new GroupTitleUpdatePacket(header, bytes, ref i); + case 378: return new GroupRoleUpdatePacket(header, bytes, ref i); + case 379: return new LiveHelpGroupRequestPacket(header, bytes, ref i); + case 380: return new LiveHelpGroupReplyPacket(header, bytes, ref i); + case 381: return new AgentWearablesRequestPacket(header, bytes, ref i); + case 382: return new AgentWearablesUpdatePacket(header, bytes, ref i); + case 383: return new AgentIsNowWearingPacket(header, bytes, ref i); + case 384: return new AgentCachedTexturePacket(header, bytes, ref i); + case 385: return new AgentCachedTextureResponsePacket(header, bytes, ref i); + case 386: return new AgentDataUpdateRequestPacket(header, bytes, ref i); + case 387: return new AgentDataUpdatePacket(header, bytes, ref i); + case 388: return new GroupDataUpdatePacket(header, bytes, ref i); + case 389: return new AgentGroupDataUpdatePacket(header, bytes, ref i); + case 390: return new AgentDropGroupPacket(header, bytes, ref i); + case 395: return new RezSingleAttachmentFromInvPacket(header, bytes, ref i); + case 396: return new RezMultipleAttachmentsFromInvPacket(header, bytes, ref i); + case 397: return new DetachAttachmentIntoInvPacket(header, bytes, ref i); + case 398: return new CreateNewOutfitAttachmentsPacket(header, bytes, ref i); + case 399: return new UserInfoRequestPacket(header, bytes, ref i); + case 400: return new UserInfoReplyPacket(header, bytes, ref i); + case 401: return new UpdateUserInfoPacket(header, bytes, ref i); + case 403: return new InitiateDownloadPacket(header, bytes, ref i); + case 405: return new MapLayerRequestPacket(header, bytes, ref i); + case 406: return new MapLayerReplyPacket(header, bytes, ref i); + case 407: return new MapBlockRequestPacket(header, bytes, ref i); + case 408: return new MapNameRequestPacket(header, bytes, ref i); + case 409: return new MapBlockReplyPacket(header, bytes, ref i); + case 410: return new MapItemRequestPacket(header, bytes, ref i); + case 411: return new MapItemReplyPacket(header, bytes, ref i); + case 412: return new SendPostcardPacket(header, bytes, ref i); + case 419: return new ParcelMediaCommandMessagePacket(header, bytes, ref i); + case 420: return new ParcelMediaUpdatePacket(header, bytes, ref i); + case 421: return new LandStatRequestPacket(header, bytes, ref i); + case 422: return new LandStatReplyPacket(header, bytes, ref i); + case 423: return new ErrorPacket(header, bytes, ref i); + case 424: return new ObjectIncludeInSearchPacket(header, bytes, ref i); + case 425: return new RezRestoreToWorldPacket(header, bytes, ref i); + case 426: return new LinkInventoryItemPacket(header, bytes, ref i); + case 65531: return new PacketAckPacket(header, bytes, ref i); + case 65532: return new OpenCircuitPacket(header, bytes, ref i); + case 65533: return new CloseCircuitPacket(header, bytes, ref i); + + } + break; + case PacketFrequency.Medium: + switch (header.ID) + { + case 1: return new ObjectAddPacket(header, bytes, ref i); + case 2: return new MultipleObjectUpdatePacket(header, bytes, ref i); + case 3: return new RequestMultipleObjectsPacket(header, bytes, ref i); + case 4: return new ObjectPositionPacket(header, bytes, ref i); + case 5: return new RequestObjectPropertiesFamilyPacket(header, bytes, ref i); + case 6: return new CoarseLocationUpdatePacket(header, bytes, ref i); + case 7: return new CrossedRegionPacket(header, bytes, ref i); + case 8: return new ConfirmEnableSimulatorPacket(header, bytes, ref i); + case 9: return new ObjectPropertiesPacket(header, bytes, ref i); + case 10: return new ObjectPropertiesFamilyPacket(header, bytes, ref i); + case 11: return new ParcelPropertiesRequestPacket(header, bytes, ref i); + case 13: return new AttachedSoundPacket(header, bytes, ref i); + case 14: return new AttachedSoundGainChangePacket(header, bytes, ref i); + case 15: return new PreloadSoundPacket(header, bytes, ref i); + case 17: return new ViewerEffectPacket(header, bytes, ref i); + + } + break; + case PacketFrequency.High: + switch (header.ID) + { + case 1: return new StartPingCheckPacket(header, bytes, ref i); + case 2: return new CompletePingCheckPacket(header, bytes, ref i); + case 4: return new AgentUpdatePacket(header, bytes, ref i); + case 5: return new AgentAnimationPacket(header, bytes, ref i); + case 6: return new AgentRequestSitPacket(header, bytes, ref i); + case 7: return new AgentSitPacket(header, bytes, ref i); + case 8: return new RequestImagePacket(header, bytes, ref i); + case 9: return new ImageDataPacket(header, bytes, ref i); + case 10: return new ImagePacketPacket(header, bytes, ref i); + case 11: return new LayerDataPacket(header, bytes, ref i); + case 12: return new ObjectUpdatePacket(header, bytes, ref i); + case 13: return new ObjectUpdateCompressedPacket(header, bytes, ref i); + case 14: return new ObjectUpdateCachedPacket(header, bytes, ref i); + case 15: return new ImprovedTerseObjectUpdatePacket(header, bytes, ref i); + case 16: return new KillObjectPacket(header, bytes, ref i); + case 17: return new TransferPacketPacket(header, bytes, ref i); + case 18: return new SendXferPacketPacket(header, bytes, ref i); + case 19: return new ConfirmXferPacketPacket(header, bytes, ref i); + case 20: return new AvatarAnimationPacket(header, bytes, ref i); + case 21: return new AvatarSitResponsePacket(header, bytes, ref i); + case 22: return new CameraConstraintPacket(header, bytes, ref i); + case 23: return new ParcelPropertiesPacket(header, bytes, ref i); + case 25: return new ChildAgentUpdatePacket(header, bytes, ref i); + case 26: return new ChildAgentAlivePacket(header, bytes, ref i); + case 27: return new ChildAgentPositionUpdatePacket(header, bytes, ref i); + case 29: return new SoundTriggerPacket(header, bytes, ref i); + + } + break; + } + + throw new MalformedDataException("Unknown packet ID " + header.Frequency + " " + header.ID); + } + } + /// + public sealed class TestMessagePacket : Packet + { + /// + public sealed class TestBlock1Block : PacketBlock + { + public uint Test1; + + public override int Length + { + get + { + return 4; + } + } + + public TestBlock1Block() { } + public TestBlock1Block(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Test1 = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Test1, bytes, i); i += 4; + } + + } + + /// + public sealed class NeighborBlockBlock : PacketBlock + { + public uint Test0; + public uint Test1; + public uint Test2; + + public override int Length + { + get + { + return 12; + } + } + + public NeighborBlockBlock() { } + public NeighborBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Test0 = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Test1 = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Test2 = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Test0, bytes, i); i += 4; + Utils.UIntToBytes(Test1, bytes, i); i += 4; + Utils.UIntToBytes(Test2, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TestBlock1.Length; + for (int j = 0; j < 4; j++) + length += NeighborBlock[j].Length; + return length; + } + } + public TestBlock1Block TestBlock1; + public NeighborBlockBlock[] NeighborBlock; + + public TestMessagePacket() + { + HasVariableBlocks = false; + Type = PacketType.TestMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 1; + Header.Reliable = true; + Header.Zerocoded = true; + TestBlock1 = new TestBlock1Block(); + NeighborBlock = new NeighborBlockBlock[4]; + } + + public TestMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TestBlock1.FromBytes(bytes, ref i); + if(NeighborBlock == null || NeighborBlock.Length != 4) { + NeighborBlock = new NeighborBlockBlock[4]; + for(int j = 0; j < 4; j++) + { NeighborBlock[j] = new NeighborBlockBlock(); } + } + for (int j = 0; j < 4; j++) + { NeighborBlock[j].FromBytes(bytes, ref i); } + } + + public TestMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TestBlock1.FromBytes(bytes, ref i); + if(NeighborBlock == null || NeighborBlock.Length != 4) { + NeighborBlock = new NeighborBlockBlock[4]; + for(int j = 0; j < 4; j++) + { NeighborBlock[j] = new NeighborBlockBlock(); } + } + for (int j = 0; j < 4; j++) + { NeighborBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += TestBlock1.Length; + for (int j = 0; j < 4; j++) { length += NeighborBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TestBlock1.ToBytes(bytes, ref i); + for (int j = 0; j < 4; j++) { NeighborBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UseCircuitCodePacket : Packet + { + /// + public sealed class CircuitCodeBlock : PacketBlock + { + public uint Code; + public UUID SessionID; + public UUID ID; + + public override int Length + { + get + { + return 36; + } + } + + public CircuitCodeBlock() { } + public CircuitCodeBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Code = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SessionID.FromBytes(bytes, i); i += 16; + ID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Code, bytes, i); i += 4; + SessionID.ToBytes(bytes, i); i += 16; + ID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += CircuitCode.Length; + return length; + } + } + public CircuitCodeBlock CircuitCode; + + public UseCircuitCodePacket() + { + HasVariableBlocks = false; + Type = PacketType.UseCircuitCode; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 3; + Header.Reliable = true; + CircuitCode = new CircuitCodeBlock(); + } + + public UseCircuitCodePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + CircuitCode.FromBytes(bytes, ref i); + } + + public UseCircuitCodePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + CircuitCode.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += CircuitCode.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + CircuitCode.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TelehubInfoPacket : Packet + { + /// + public sealed class TelehubBlockBlock : PacketBlock + { + public UUID ObjectID; + public byte[] ObjectName; + public Vector3 TelehubPos; + public Quaternion TelehubRot; + + public override int Length + { + get + { + int length = 41; + if (ObjectName != null) { length += ObjectName.Length; } + return length; + } + } + + public TelehubBlockBlock() { } + public TelehubBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + ObjectName = new byte[length]; + Buffer.BlockCopy(bytes, i, ObjectName, 0, length); i += length; + TelehubPos.FromBytes(bytes, i); i += 12; + TelehubRot.FromBytes(bytes, i, true); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)ObjectName.Length; + Buffer.BlockCopy(ObjectName, 0, bytes, i, ObjectName.Length); i += ObjectName.Length; + TelehubPos.ToBytes(bytes, i); i += 12; + TelehubRot.ToBytes(bytes, i); i += 12; + } + + } + + /// + public sealed class SpawnPointBlockBlock : PacketBlock + { + public Vector3 SpawnPointPos; + + public override int Length + { + get + { + return 12; + } + } + + public SpawnPointBlockBlock() { } + public SpawnPointBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SpawnPointPos.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + SpawnPointPos.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 11; + length += TelehubBlock.Length; + for (int j = 0; j < SpawnPointBlock.Length; j++) + length += SpawnPointBlock[j].Length; + return length; + } + } + public TelehubBlockBlock TelehubBlock; + public SpawnPointBlockBlock[] SpawnPointBlock; + + public TelehubInfoPacket() + { + HasVariableBlocks = true; + Type = PacketType.TelehubInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 10; + Header.Reliable = true; + TelehubBlock = new TelehubBlockBlock(); + SpawnPointBlock = null; + } + + public TelehubInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TelehubBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SpawnPointBlock == null || SpawnPointBlock.Length != -1) { + SpawnPointBlock = new SpawnPointBlockBlock[count]; + for(int j = 0; j < count; j++) + { SpawnPointBlock[j] = new SpawnPointBlockBlock(); } + } + for (int j = 0; j < count; j++) + { SpawnPointBlock[j].FromBytes(bytes, ref i); } + } + + public TelehubInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TelehubBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SpawnPointBlock == null || SpawnPointBlock.Length != count) { + SpawnPointBlock = new SpawnPointBlockBlock[count]; + for(int j = 0; j < count; j++) + { SpawnPointBlock[j] = new SpawnPointBlockBlock(); } + } + for (int j = 0; j < count; j++) + { SpawnPointBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += TelehubBlock.Length; + length++; + for (int j = 0; j < SpawnPointBlock.Length; j++) { length += SpawnPointBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TelehubBlock.ToBytes(bytes, ref i); + bytes[i++] = (byte)SpawnPointBlock.Length; + for (int j = 0; j < SpawnPointBlock.Length; j++) { SpawnPointBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += TelehubBlock.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + TelehubBlock.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int SpawnPointBlockStart = 0; + do + { + int variableLength = 0; + int SpawnPointBlockCount = 0; + + i = SpawnPointBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < SpawnPointBlock.Length) { + int blockLength = SpawnPointBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++SpawnPointBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)SpawnPointBlockCount; + for (i = SpawnPointBlockStart; i < SpawnPointBlockStart + SpawnPointBlockCount; i++) { SpawnPointBlock[i].ToBytes(packet, ref length); } + SpawnPointBlockStart += SpawnPointBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + SpawnPointBlockStart < SpawnPointBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class EconomyDataRequestPacket : Packet + { + public override int Length + { + get + { + int length = 10; + return length; + } + } + + public EconomyDataRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.EconomyDataRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 24; + Header.Reliable = true; + } + + public EconomyDataRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + } + + public EconomyDataRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + } + + public override byte[] ToBytes() + { + int length = 10; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EconomyDataPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public int ObjectCapacity; + public int ObjectCount; + public int PriceEnergyUnit; + public int PriceObjectClaim; + public int PricePublicObjectDecay; + public int PricePublicObjectDelete; + public int PriceParcelClaim; + public float PriceParcelClaimFactor; + public int PriceUpload; + public int PriceRentLight; + public int TeleportMinPrice; + public float TeleportPriceExponent; + public float EnergyEfficiency; + public float PriceObjectRent; + public float PriceObjectScaleFactor; + public int PriceParcelRent; + public int PriceGroupCreate; + + public override int Length + { + get + { + return 68; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectCapacity = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ObjectCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PriceEnergyUnit = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PriceObjectClaim = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PricePublicObjectDecay = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PricePublicObjectDelete = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PriceParcelClaim = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PriceParcelClaimFactor = Utils.BytesToFloat(bytes, i); i += 4; + PriceUpload = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PriceRentLight = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TeleportMinPrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TeleportPriceExponent = Utils.BytesToFloat(bytes, i); i += 4; + EnergyEfficiency = Utils.BytesToFloat(bytes, i); i += 4; + PriceObjectRent = Utils.BytesToFloat(bytes, i); i += 4; + PriceObjectScaleFactor = Utils.BytesToFloat(bytes, i); i += 4; + PriceParcelRent = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PriceGroupCreate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(ObjectCapacity, bytes, i); i += 4; + Utils.IntToBytes(ObjectCount, bytes, i); i += 4; + Utils.IntToBytes(PriceEnergyUnit, bytes, i); i += 4; + Utils.IntToBytes(PriceObjectClaim, bytes, i); i += 4; + Utils.IntToBytes(PricePublicObjectDecay, bytes, i); i += 4; + Utils.IntToBytes(PricePublicObjectDelete, bytes, i); i += 4; + Utils.IntToBytes(PriceParcelClaim, bytes, i); i += 4; + Utils.FloatToBytes(PriceParcelClaimFactor, bytes, i); i += 4; + Utils.IntToBytes(PriceUpload, bytes, i); i += 4; + Utils.IntToBytes(PriceRentLight, bytes, i); i += 4; + Utils.IntToBytes(TeleportMinPrice, bytes, i); i += 4; + Utils.FloatToBytes(TeleportPriceExponent, bytes, i); i += 4; + Utils.FloatToBytes(EnergyEfficiency, bytes, i); i += 4; + Utils.FloatToBytes(PriceObjectRent, bytes, i); i += 4; + Utils.FloatToBytes(PriceObjectScaleFactor, bytes, i); i += 4; + Utils.IntToBytes(PriceParcelRent, bytes, i); i += 4; + Utils.IntToBytes(PriceGroupCreate, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Info.Length; + return length; + } + } + public InfoBlock Info; + + public EconomyDataPacket() + { + HasVariableBlocks = false; + Type = PacketType.EconomyData; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 25; + Header.Reliable = true; + Header.Zerocoded = true; + Info = new InfoBlock(); + } + + public EconomyDataPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + } + + public EconomyDataPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarPickerRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID QueryID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public byte[] Name; + + public override int Length + { + get + { + int length = 1; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public AvatarPickerRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarPickerRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 26; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public AvatarPickerRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public AvatarPickerRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarPickerReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID QueryID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID AvatarID; + public byte[] FirstName; + public byte[] LastName; + + public override int Length + { + get + { + int length = 18; + if (FirstName != null) { length += FirstName.Length; } + if (LastName != null) { length += LastName.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AvatarID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + FirstName = new byte[length]; + Buffer.BlockCopy(bytes, i, FirstName, 0, length); i += length; + length = bytes[i++]; + LastName = new byte[length]; + Buffer.BlockCopy(bytes, i, LastName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AvatarID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)FirstName.Length; + Buffer.BlockCopy(FirstName, 0, bytes, i, FirstName.Length); i += FirstName.Length; + bytes[i++] = (byte)LastName.Length; + Buffer.BlockCopy(LastName, 0, bytes, i, LastName.Length); i += LastName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock[] Data; + + public AvatarPickerReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.AvatarPickerReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 28; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = null; + } + + public AvatarPickerReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public AvatarPickerReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class PlacesQueryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID QueryID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionDataBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionDataBlock() { } + public TransactionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public byte[] QueryText; + public uint QueryFlags; + public sbyte Category; + public byte[] SimName; + + public override int Length + { + get + { + int length = 7; + if (QueryText != null) { length += QueryText.Length; } + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + QueryText = new byte[length]; + Buffer.BlockCopy(bytes, i, QueryText, 0, length); i += length; + QueryFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Category = (sbyte)bytes[i++]; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)QueryText.Length; + Buffer.BlockCopy(QueryText, 0, bytes, i, QueryText.Length); i += QueryText.Length; + Utils.UIntToBytes(QueryFlags, bytes, i); i += 4; + bytes[i++] = (byte)Category; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += TransactionData.Length; + length += QueryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionDataBlock TransactionData; + public QueryDataBlock QueryData; + + public PlacesQueryPacket() + { + HasVariableBlocks = false; + Type = PacketType.PlacesQuery; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 29; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + TransactionData = new TransactionDataBlock(); + QueryData = new QueryDataBlock(); + } + + public PlacesQueryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public PlacesQueryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionData.Length; + length += QueryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PlacesReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID QueryID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionDataBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionDataBlock() { } + public TransactionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID OwnerID; + public byte[] Name; + public byte[] Desc; + public int ActualArea; + public int BillableArea; + public byte Flags; + public float GlobalX; + public float GlobalY; + public float GlobalZ; + public byte[] SimName; + public UUID SnapshotID; + public float Dwell; + public int Price; + + public override int Length + { + get + { + int length = 64; + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + OwnerID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + ActualArea = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + BillableArea = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (byte)bytes[i++]; + GlobalX = Utils.BytesToFloat(bytes, i); i += 4; + GlobalY = Utils.BytesToFloat(bytes, i); i += 4; + GlobalZ = Utils.BytesToFloat(bytes, i); i += 4; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + SnapshotID.FromBytes(bytes, i); i += 16; + Dwell = Utils.BytesToFloat(bytes, i); i += 4; + Price = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Desc.Length; + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + Utils.IntToBytes(ActualArea, bytes, i); i += 4; + Utils.IntToBytes(BillableArea, bytes, i); i += 4; + bytes[i++] = Flags; + Utils.FloatToBytes(GlobalX, bytes, i); i += 4; + Utils.FloatToBytes(GlobalY, bytes, i); i += 4; + Utils.FloatToBytes(GlobalZ, bytes, i); i += 4; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + SnapshotID.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(Dwell, bytes, i); i += 4; + Utils.IntToBytes(Price, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += TransactionData.Length; + for (int j = 0; j < QueryData.Length; j++) + length += QueryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionDataBlock TransactionData; + public QueryDataBlock[] QueryData; + + public PlacesReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.PlacesReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 30; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + TransactionData = new TransactionDataBlock(); + QueryData = null; + } + + public PlacesReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryData == null || QueryData.Length != -1) { + QueryData = new QueryDataBlock[count]; + for(int j = 0; j < count; j++) + { QueryData[j] = new QueryDataBlock(); } + } + for (int j = 0; j < count; j++) + { QueryData[j].FromBytes(bytes, ref i); } + } + + public PlacesReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryData == null || QueryData.Length != count) { + QueryData = new QueryDataBlock[count]; + for(int j = 0; j < count; j++) + { QueryData[j] = new QueryDataBlock(); } + } + for (int j = 0; j < count; j++) + { QueryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionData.Length; + length++; + for (int j = 0; j < QueryData.Length; j++) { length += QueryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryData.Length; + for (int j = 0; j < QueryData.Length; j++) { QueryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += TransactionData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + TransactionData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int QueryDataStart = 0; + do + { + int variableLength = 0; + int QueryDataCount = 0; + + i = QueryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryData.Length) { + int blockLength = QueryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryDataCount; + for (i = QueryDataStart; i < QueryDataStart + QueryDataCount; i++) { QueryData[i].ToBytes(packet, ref length); } + QueryDataStart += QueryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryDataStart < QueryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DirFindQueryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + public byte[] QueryText; + public uint QueryFlags; + public int QueryStart; + + public override int Length + { + get + { + int length = 25; + if (QueryText != null) { length += QueryText.Length; } + return length; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + QueryID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + QueryText = new byte[length]; + Buffer.BlockCopy(bytes, i, QueryText, 0, length); i += length; + QueryFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + QueryStart = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)QueryText.Length; + Buffer.BlockCopy(QueryText, 0, bytes, i, QueryText.Length); i += QueryText.Length; + Utils.UIntToBytes(QueryFlags, bytes, i); i += 4; + Utils.IntToBytes(QueryStart, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + + public DirFindQueryPacket() + { + HasVariableBlocks = false; + Type = PacketType.DirFindQuery; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 31; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + } + + public DirFindQueryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public DirFindQueryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DirPlacesQueryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + public byte[] QueryText; + public uint QueryFlags; + public sbyte Category; + public byte[] SimName; + public int QueryStart; + + public override int Length + { + get + { + int length = 27; + if (QueryText != null) { length += QueryText.Length; } + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + QueryID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + QueryText = new byte[length]; + Buffer.BlockCopy(bytes, i, QueryText, 0, length); i += length; + QueryFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Category = (sbyte)bytes[i++]; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + QueryStart = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)QueryText.Length; + Buffer.BlockCopy(QueryText, 0, bytes, i, QueryText.Length); i += QueryText.Length; + Utils.UIntToBytes(QueryFlags, bytes, i); i += 4; + bytes[i++] = (byte)Category; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + Utils.IntToBytes(QueryStart, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + + public DirPlacesQueryPacket() + { + HasVariableBlocks = false; + Type = PacketType.DirPlacesQuery; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 33; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + } + + public DirPlacesQueryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public DirPlacesQueryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DirPlacesReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + + public override int Length + { + get + { + return 16; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryRepliesBlock : PacketBlock + { + public UUID ParcelID; + public byte[] Name; + public bool ForSale; + public bool Auction; + public float Dwell; + + public override int Length + { + get + { + int length = 23; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public QueryRepliesBlock() { } + public QueryRepliesBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ParcelID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + ForSale = (bytes[i++] != 0) ? (bool)true : (bool)false; + Auction = (bytes[i++] != 0) ? (bool)true : (bool)false; + Dwell = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ParcelID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)((ForSale) ? 1 : 0); + bytes[i++] = (byte)((Auction) ? 1 : 0); + Utils.FloatToBytes(Dwell, bytes, i); i += 4; + } + + } + + /// + public sealed class StatusDataBlock : PacketBlock + { + public uint Status; + + public override int Length + { + get + { + return 4; + } + } + + public StatusDataBlock() { } + public StatusDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Status = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Status, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 13; + length += AgentData.Length; + for (int j = 0; j < QueryData.Length; j++) + length += QueryData[j].Length; + for (int j = 0; j < QueryReplies.Length; j++) + length += QueryReplies[j].Length; + for (int j = 0; j < StatusData.Length; j++) + length += StatusData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock[] QueryData; + public QueryRepliesBlock[] QueryReplies; + public StatusDataBlock[] StatusData; + + public DirPlacesReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.DirPlacesReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 35; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = null; + QueryReplies = null; + StatusData = null; + } + + public DirPlacesReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryData == null || QueryData.Length != -1) { + QueryData = new QueryDataBlock[count]; + for(int j = 0; j < count; j++) + { QueryData[j] = new QueryDataBlock(); } + } + for (int j = 0; j < count; j++) + { QueryData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != -1) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(StatusData == null || StatusData.Length != -1) { + StatusData = new StatusDataBlock[count]; + for(int j = 0; j < count; j++) + { StatusData[j] = new StatusDataBlock(); } + } + for (int j = 0; j < count; j++) + { StatusData[j].FromBytes(bytes, ref i); } + } + + public DirPlacesReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryData == null || QueryData.Length != count) { + QueryData = new QueryDataBlock[count]; + for(int j = 0; j < count; j++) + { QueryData[j] = new QueryDataBlock(); } + } + for (int j = 0; j < count; j++) + { QueryData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != count) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(StatusData == null || StatusData.Length != count) { + StatusData = new StatusDataBlock[count]; + for(int j = 0; j < count; j++) + { StatusData[j] = new StatusDataBlock(); } + } + for (int j = 0; j < count; j++) + { StatusData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < QueryData.Length; j++) { length += QueryData[j].Length; } + length++; + for (int j = 0; j < QueryReplies.Length; j++) { length += QueryReplies[j].Length; } + length++; + for (int j = 0; j < StatusData.Length; j++) { length += StatusData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryData.Length; + for (int j = 0; j < QueryData.Length; j++) { QueryData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)QueryReplies.Length; + for (int j = 0; j < QueryReplies.Length; j++) { QueryReplies[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)StatusData.Length; + for (int j = 0; j < StatusData.Length; j++) { StatusData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 3; + + int QueryDataStart = 0; + int QueryRepliesStart = 0; + int StatusDataStart = 0; + do + { + int variableLength = 0; + int QueryDataCount = 0; + int QueryRepliesCount = 0; + int StatusDataCount = 0; + + i = QueryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryData.Length) { + int blockLength = QueryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryDataCount; + } + else { break; } + ++i; + } + + i = QueryRepliesStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryReplies.Length) { + int blockLength = QueryReplies[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryRepliesCount; + } + else { break; } + ++i; + } + + i = StatusDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < StatusData.Length) { + int blockLength = StatusData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++StatusDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryDataCount; + for (i = QueryDataStart; i < QueryDataStart + QueryDataCount; i++) { QueryData[i].ToBytes(packet, ref length); } + QueryDataStart += QueryDataCount; + + packet[length++] = (byte)QueryRepliesCount; + for (i = QueryRepliesStart; i < QueryRepliesStart + QueryRepliesCount; i++) { QueryReplies[i].ToBytes(packet, ref length); } + QueryRepliesStart += QueryRepliesCount; + + packet[length++] = (byte)StatusDataCount; + for (i = StatusDataStart; i < StatusDataStart + StatusDataCount; i++) { StatusData[i].ToBytes(packet, ref length); } + StatusDataStart += StatusDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryDataStart < QueryData.Length || + QueryRepliesStart < QueryReplies.Length || + StatusDataStart < StatusData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DirPeopleReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + + public override int Length + { + get + { + return 16; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryRepliesBlock : PacketBlock + { + public UUID AgentID; + public byte[] FirstName; + public byte[] LastName; + public byte[] Group; + public bool Online; + public int Reputation; + + public override int Length + { + get + { + int length = 24; + if (FirstName != null) { length += FirstName.Length; } + if (LastName != null) { length += LastName.Length; } + if (Group != null) { length += Group.Length; } + return length; + } + } + + public QueryRepliesBlock() { } + public QueryRepliesBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + FirstName = new byte[length]; + Buffer.BlockCopy(bytes, i, FirstName, 0, length); i += length; + length = bytes[i++]; + LastName = new byte[length]; + Buffer.BlockCopy(bytes, i, LastName, 0, length); i += length; + length = bytes[i++]; + Group = new byte[length]; + Buffer.BlockCopy(bytes, i, Group, 0, length); i += length; + Online = (bytes[i++] != 0) ? (bool)true : (bool)false; + Reputation = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)FirstName.Length; + Buffer.BlockCopy(FirstName, 0, bytes, i, FirstName.Length); i += FirstName.Length; + bytes[i++] = (byte)LastName.Length; + Buffer.BlockCopy(LastName, 0, bytes, i, LastName.Length); i += LastName.Length; + bytes[i++] = (byte)Group.Length; + Buffer.BlockCopy(Group, 0, bytes, i, Group.Length); i += Group.Length; + bytes[i++] = (byte)((Online) ? 1 : 0); + Utils.IntToBytes(Reputation, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += QueryData.Length; + for (int j = 0; j < QueryReplies.Length; j++) + length += QueryReplies[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + public QueryRepliesBlock[] QueryReplies; + + public DirPeopleReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.DirPeopleReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 36; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + QueryReplies = null; + } + + public DirPeopleReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != -1) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public DirPeopleReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != count) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + length++; + for (int j = 0; j < QueryReplies.Length; j++) { length += QueryReplies[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryReplies.Length; + for (int j = 0; j < QueryReplies.Length; j++) { QueryReplies[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += QueryData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + QueryData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int QueryRepliesStart = 0; + do + { + int variableLength = 0; + int QueryRepliesCount = 0; + + i = QueryRepliesStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryReplies.Length) { + int blockLength = QueryReplies[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryRepliesCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryRepliesCount; + for (i = QueryRepliesStart; i < QueryRepliesStart + QueryRepliesCount; i++) { QueryReplies[i].ToBytes(packet, ref length); } + QueryRepliesStart += QueryRepliesCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryRepliesStart < QueryReplies.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DirEventsReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + + public override int Length + { + get + { + return 16; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryRepliesBlock : PacketBlock + { + public UUID OwnerID; + public byte[] Name; + public uint EventID; + public byte[] Date; + public uint UnixTime; + public uint EventFlags; + + public override int Length + { + get + { + int length = 30; + if (Name != null) { length += Name.Length; } + if (Date != null) { length += Date.Length; } + return length; + } + } + + public QueryRepliesBlock() { } + public QueryRepliesBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + OwnerID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + EventID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Date = new byte[length]; + Buffer.BlockCopy(bytes, i, Date, 0, length); i += length; + UnixTime = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EventFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + Utils.UIntToBytes(EventID, bytes, i); i += 4; + bytes[i++] = (byte)Date.Length; + Buffer.BlockCopy(Date, 0, bytes, i, Date.Length); i += Date.Length; + Utils.UIntToBytes(UnixTime, bytes, i); i += 4; + Utils.UIntToBytes(EventFlags, bytes, i); i += 4; + } + + } + + /// + public sealed class StatusDataBlock : PacketBlock + { + public uint Status; + + public override int Length + { + get + { + return 4; + } + } + + public StatusDataBlock() { } + public StatusDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Status = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Status, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + length += QueryData.Length; + for (int j = 0; j < QueryReplies.Length; j++) + length += QueryReplies[j].Length; + for (int j = 0; j < StatusData.Length; j++) + length += StatusData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + public QueryRepliesBlock[] QueryReplies; + public StatusDataBlock[] StatusData; + + public DirEventsReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.DirEventsReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 37; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + QueryReplies = null; + StatusData = null; + } + + public DirEventsReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != -1) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(StatusData == null || StatusData.Length != -1) { + StatusData = new StatusDataBlock[count]; + for(int j = 0; j < count; j++) + { StatusData[j] = new StatusDataBlock(); } + } + for (int j = 0; j < count; j++) + { StatusData[j].FromBytes(bytes, ref i); } + } + + public DirEventsReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != count) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(StatusData == null || StatusData.Length != count) { + StatusData = new StatusDataBlock[count]; + for(int j = 0; j < count; j++) + { StatusData[j] = new StatusDataBlock(); } + } + for (int j = 0; j < count; j++) + { StatusData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + length++; + for (int j = 0; j < QueryReplies.Length; j++) { length += QueryReplies[j].Length; } + length++; + for (int j = 0; j < StatusData.Length; j++) { length += StatusData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryReplies.Length; + for (int j = 0; j < QueryReplies.Length; j++) { QueryReplies[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)StatusData.Length; + for (int j = 0; j < StatusData.Length; j++) { StatusData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += QueryData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + QueryData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int QueryRepliesStart = 0; + int StatusDataStart = 0; + do + { + int variableLength = 0; + int QueryRepliesCount = 0; + int StatusDataCount = 0; + + i = QueryRepliesStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryReplies.Length) { + int blockLength = QueryReplies[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryRepliesCount; + } + else { break; } + ++i; + } + + i = StatusDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < StatusData.Length) { + int blockLength = StatusData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++StatusDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryRepliesCount; + for (i = QueryRepliesStart; i < QueryRepliesStart + QueryRepliesCount; i++) { QueryReplies[i].ToBytes(packet, ref length); } + QueryRepliesStart += QueryRepliesCount; + + packet[length++] = (byte)StatusDataCount; + for (i = StatusDataStart; i < StatusDataStart + StatusDataCount; i++) { StatusData[i].ToBytes(packet, ref length); } + StatusDataStart += StatusDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryRepliesStart < QueryReplies.Length || + StatusDataStart < StatusData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DirGroupsReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + + public override int Length + { + get + { + return 16; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryRepliesBlock : PacketBlock + { + public UUID GroupID; + public byte[] GroupName; + public int Members; + public float SearchOrder; + + public override int Length + { + get + { + int length = 25; + if (GroupName != null) { length += GroupName.Length; } + return length; + } + } + + public QueryRepliesBlock() { } + public QueryRepliesBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GroupID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + GroupName = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupName, 0, length); i += length; + Members = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SearchOrder = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)GroupName.Length; + Buffer.BlockCopy(GroupName, 0, bytes, i, GroupName.Length); i += GroupName.Length; + Utils.IntToBytes(Members, bytes, i); i += 4; + Utils.FloatToBytes(SearchOrder, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += QueryData.Length; + for (int j = 0; j < QueryReplies.Length; j++) + length += QueryReplies[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + public QueryRepliesBlock[] QueryReplies; + + public DirGroupsReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.DirGroupsReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 38; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + QueryReplies = null; + } + + public DirGroupsReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != -1) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public DirGroupsReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != count) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + length++; + for (int j = 0; j < QueryReplies.Length; j++) { length += QueryReplies[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryReplies.Length; + for (int j = 0; j < QueryReplies.Length; j++) { QueryReplies[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += QueryData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + QueryData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int QueryRepliesStart = 0; + do + { + int variableLength = 0; + int QueryRepliesCount = 0; + + i = QueryRepliesStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryReplies.Length) { + int blockLength = QueryReplies[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryRepliesCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryRepliesCount; + for (i = QueryRepliesStart; i < QueryRepliesStart + QueryRepliesCount; i++) { QueryReplies[i].ToBytes(packet, ref length); } + QueryRepliesStart += QueryRepliesCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryRepliesStart < QueryReplies.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DirClassifiedQueryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + public byte[] QueryText; + public uint QueryFlags; + public uint Category; + public int QueryStart; + + public override int Length + { + get + { + int length = 29; + if (QueryText != null) { length += QueryText.Length; } + return length; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + QueryID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + QueryText = new byte[length]; + Buffer.BlockCopy(bytes, i, QueryText, 0, length); i += length; + QueryFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Category = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + QueryStart = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)QueryText.Length; + Buffer.BlockCopy(QueryText, 0, bytes, i, QueryText.Length); i += QueryText.Length; + Utils.UIntToBytes(QueryFlags, bytes, i); i += 4; + Utils.UIntToBytes(Category, bytes, i); i += 4; + Utils.IntToBytes(QueryStart, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + + public DirClassifiedQueryPacket() + { + HasVariableBlocks = false; + Type = PacketType.DirClassifiedQuery; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 39; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + } + + public DirClassifiedQueryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public DirClassifiedQueryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DirClassifiedReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + + public override int Length + { + get + { + return 16; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryRepliesBlock : PacketBlock + { + public UUID ClassifiedID; + public byte[] Name; + public byte ClassifiedFlags; + public uint CreationDate; + public uint ExpirationDate; + public int PriceForListing; + + public override int Length + { + get + { + int length = 30; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public QueryRepliesBlock() { } + public QueryRepliesBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ClassifiedID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + ClassifiedFlags = (byte)bytes[i++]; + CreationDate = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ExpirationDate = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PriceForListing = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ClassifiedID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = ClassifiedFlags; + Utils.UIntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(ExpirationDate, bytes, i); i += 4; + Utils.IntToBytes(PriceForListing, bytes, i); i += 4; + } + + } + + /// + public sealed class StatusDataBlock : PacketBlock + { + public uint Status; + + public override int Length + { + get + { + return 4; + } + } + + public StatusDataBlock() { } + public StatusDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Status = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Status, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + length += QueryData.Length; + for (int j = 0; j < QueryReplies.Length; j++) + length += QueryReplies[j].Length; + for (int j = 0; j < StatusData.Length; j++) + length += StatusData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + public QueryRepliesBlock[] QueryReplies; + public StatusDataBlock[] StatusData; + + public DirClassifiedReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.DirClassifiedReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 41; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + QueryReplies = null; + StatusData = null; + } + + public DirClassifiedReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != -1) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(StatusData == null || StatusData.Length != -1) { + StatusData = new StatusDataBlock[count]; + for(int j = 0; j < count; j++) + { StatusData[j] = new StatusDataBlock(); } + } + for (int j = 0; j < count; j++) + { StatusData[j].FromBytes(bytes, ref i); } + } + + public DirClassifiedReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != count) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(StatusData == null || StatusData.Length != count) { + StatusData = new StatusDataBlock[count]; + for(int j = 0; j < count; j++) + { StatusData[j] = new StatusDataBlock(); } + } + for (int j = 0; j < count; j++) + { StatusData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + length++; + for (int j = 0; j < QueryReplies.Length; j++) { length += QueryReplies[j].Length; } + length++; + for (int j = 0; j < StatusData.Length; j++) { length += StatusData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryReplies.Length; + for (int j = 0; j < QueryReplies.Length; j++) { QueryReplies[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)StatusData.Length; + for (int j = 0; j < StatusData.Length; j++) { StatusData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += QueryData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + QueryData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int QueryRepliesStart = 0; + int StatusDataStart = 0; + do + { + int variableLength = 0; + int QueryRepliesCount = 0; + int StatusDataCount = 0; + + i = QueryRepliesStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryReplies.Length) { + int blockLength = QueryReplies[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryRepliesCount; + } + else { break; } + ++i; + } + + i = StatusDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < StatusData.Length) { + int blockLength = StatusData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++StatusDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryRepliesCount; + for (i = QueryRepliesStart; i < QueryRepliesStart + QueryRepliesCount; i++) { QueryReplies[i].ToBytes(packet, ref length); } + QueryRepliesStart += QueryRepliesCount; + + packet[length++] = (byte)StatusDataCount; + for (i = StatusDataStart; i < StatusDataStart + StatusDataCount; i++) { StatusData[i].ToBytes(packet, ref length); } + StatusDataStart += StatusDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryRepliesStart < QueryReplies.Length || + StatusDataStart < StatusData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AvatarClassifiedReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID TargetID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + TargetID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + TargetID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ClassifiedID; + public byte[] Name; + + public override int Length + { + get + { + int length = 17; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ClassifiedID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ClassifiedID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock[] Data; + + public AvatarClassifiedReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.AvatarClassifiedReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 42; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = null; + } + + public AvatarClassifiedReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public AvatarClassifiedReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ClassifiedInfoRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ClassifiedID; + + public override int Length + { + get + { + return 16; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ClassifiedID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ClassifiedID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ClassifiedInfoRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ClassifiedInfoRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 43; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ClassifiedInfoRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ClassifiedInfoRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ClassifiedInfoReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ClassifiedID; + public UUID CreatorID; + public uint CreationDate; + public uint ExpirationDate; + public uint Category; + public byte[] Name; + public byte[] Desc; + public UUID ParcelID; + public uint ParentEstate; + public UUID SnapshotID; + public byte[] SimName; + public Vector3d PosGlobal; + public byte[] ParcelName; + public byte ClassifiedFlags; + public int PriceForListing; + + public override int Length + { + get + { + int length = 114; + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + if (SimName != null) { length += SimName.Length; } + if (ParcelName != null) { length += ParcelName.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ClassifiedID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + CreationDate = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ExpirationDate = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Category = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + ParcelID.FromBytes(bytes, i); i += 16; + ParentEstate = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SnapshotID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + PosGlobal.FromBytes(bytes, i); i += 24; + length = bytes[i++]; + ParcelName = new byte[length]; + Buffer.BlockCopy(bytes, i, ParcelName, 0, length); i += length; + ClassifiedFlags = (byte)bytes[i++]; + PriceForListing = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ClassifiedID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(ExpirationDate, bytes, i); i += 4; + Utils.UIntToBytes(Category, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)(Desc.Length % 256); + bytes[i++] = (byte)((Desc.Length >> 8) % 256); + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + ParcelID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(ParentEstate, bytes, i); i += 4; + SnapshotID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + PosGlobal.ToBytes(bytes, i); i += 24; + bytes[i++] = (byte)ParcelName.Length; + Buffer.BlockCopy(ParcelName, 0, bytes, i, ParcelName.Length); i += ParcelName.Length; + bytes[i++] = ClassifiedFlags; + Utils.IntToBytes(PriceForListing, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ClassifiedInfoReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.ClassifiedInfoReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 44; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ClassifiedInfoReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ClassifiedInfoReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ClassifiedInfoUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ClassifiedID; + public uint Category; + public byte[] Name; + public byte[] Desc; + public UUID ParcelID; + public uint ParentEstate; + public UUID SnapshotID; + public Vector3d PosGlobal; + public byte ClassifiedFlags; + public int PriceForListing; + + public override int Length + { + get + { + int length = 88; + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ClassifiedID.FromBytes(bytes, i); i += 16; + Category = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + ParcelID.FromBytes(bytes, i); i += 16; + ParentEstate = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SnapshotID.FromBytes(bytes, i); i += 16; + PosGlobal.FromBytes(bytes, i); i += 24; + ClassifiedFlags = (byte)bytes[i++]; + PriceForListing = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ClassifiedID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Category, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)(Desc.Length % 256); + bytes[i++] = (byte)((Desc.Length >> 8) % 256); + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + ParcelID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(ParentEstate, bytes, i); i += 4; + SnapshotID.ToBytes(bytes, i); i += 16; + PosGlobal.ToBytes(bytes, i); i += 24; + bytes[i++] = ClassifiedFlags; + Utils.IntToBytes(PriceForListing, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ClassifiedInfoUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.ClassifiedInfoUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 45; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ClassifiedInfoUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ClassifiedInfoUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ClassifiedDeletePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ClassifiedID; + + public override int Length + { + get + { + return 16; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ClassifiedID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ClassifiedID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ClassifiedDeletePacket() + { + HasVariableBlocks = false; + Type = PacketType.ClassifiedDelete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 46; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ClassifiedDeletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ClassifiedDeletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ClassifiedGodDeletePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ClassifiedID; + public UUID QueryID; + + public override int Length + { + get + { + return 32; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ClassifiedID.FromBytes(bytes, i); i += 16; + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ClassifiedID.ToBytes(bytes, i); i += 16; + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ClassifiedGodDeletePacket() + { + HasVariableBlocks = false; + Type = PacketType.ClassifiedGodDelete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 47; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ClassifiedGodDeletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ClassifiedGodDeletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DirLandQueryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + public uint QueryFlags; + public uint SearchType; + public int Price; + public int Area; + public int QueryStart; + + public override int Length + { + get + { + return 36; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + QueryFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SearchType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Price = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Area = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + QueryStart = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(QueryFlags, bytes, i); i += 4; + Utils.UIntToBytes(SearchType, bytes, i); i += 4; + Utils.IntToBytes(Price, bytes, i); i += 4; + Utils.IntToBytes(Area, bytes, i); i += 4; + Utils.IntToBytes(QueryStart, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + + public DirLandQueryPacket() + { + HasVariableBlocks = false; + Type = PacketType.DirLandQuery; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 48; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + } + + public DirLandQueryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public DirLandQueryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DirLandReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + + public override int Length + { + get + { + return 16; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryRepliesBlock : PacketBlock + { + public UUID ParcelID; + public byte[] Name; + public bool Auction; + public bool ForSale; + public int SalePrice; + public int ActualArea; + + public override int Length + { + get + { + int length = 27; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public QueryRepliesBlock() { } + public QueryRepliesBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ParcelID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + Auction = (bytes[i++] != 0) ? (bool)true : (bool)false; + ForSale = (bytes[i++] != 0) ? (bool)true : (bool)false; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ActualArea = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ParcelID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)((Auction) ? 1 : 0); + bytes[i++] = (byte)((ForSale) ? 1 : 0); + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + Utils.IntToBytes(ActualArea, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += QueryData.Length; + for (int j = 0; j < QueryReplies.Length; j++) + length += QueryReplies[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + public QueryRepliesBlock[] QueryReplies; + + public DirLandReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.DirLandReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 50; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + QueryReplies = null; + } + + public DirLandReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != -1) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public DirLandReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != count) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + length++; + for (int j = 0; j < QueryReplies.Length; j++) { length += QueryReplies[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryReplies.Length; + for (int j = 0; j < QueryReplies.Length; j++) { QueryReplies[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += QueryData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + QueryData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int QueryRepliesStart = 0; + do + { + int variableLength = 0; + int QueryRepliesCount = 0; + + i = QueryRepliesStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryReplies.Length) { + int blockLength = QueryReplies[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryRepliesCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryRepliesCount; + for (i = QueryRepliesStart; i < QueryRepliesStart + QueryRepliesCount; i++) { QueryReplies[i].ToBytes(packet, ref length); } + QueryRepliesStart += QueryRepliesCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryRepliesStart < QueryReplies.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DirPopularQueryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + public uint QueryFlags; + + public override int Length + { + get + { + return 20; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + QueryFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(QueryFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + + public DirPopularQueryPacket() + { + HasVariableBlocks = false; + Type = PacketType.DirPopularQuery; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 51; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + } + + public DirPopularQueryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public DirPopularQueryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DirPopularReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + + public override int Length + { + get + { + return 16; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class QueryRepliesBlock : PacketBlock + { + public UUID ParcelID; + public byte[] Name; + public float Dwell; + + public override int Length + { + get + { + int length = 21; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public QueryRepliesBlock() { } + public QueryRepliesBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ParcelID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + Dwell = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ParcelID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + Utils.FloatToBytes(Dwell, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += QueryData.Length; + for (int j = 0; j < QueryReplies.Length; j++) + length += QueryReplies[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public QueryDataBlock QueryData; + public QueryRepliesBlock[] QueryReplies; + + public DirPopularReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.DirPopularReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 53; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + QueryData = new QueryDataBlock(); + QueryReplies = null; + } + + public DirPopularReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != -1) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public DirPopularReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(QueryReplies == null || QueryReplies.Length != count) { + QueryReplies = new QueryRepliesBlock[count]; + for(int j = 0; j < count; j++) + { QueryReplies[j] = new QueryRepliesBlock(); } + } + for (int j = 0; j < count; j++) + { QueryReplies[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += QueryData.Length; + length++; + for (int j = 0; j < QueryReplies.Length; j++) { length += QueryReplies[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + bytes[i++] = (byte)QueryReplies.Length; + for (int j = 0; j < QueryReplies.Length; j++) { QueryReplies[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += QueryData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + QueryData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int QueryRepliesStart = 0; + do + { + int variableLength = 0; + int QueryRepliesCount = 0; + + i = QueryRepliesStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < QueryReplies.Length) { + int blockLength = QueryReplies[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++QueryRepliesCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)QueryRepliesCount; + for (i = QueryRepliesStart; i < QueryRepliesStart + QueryRepliesCount; i++) { QueryReplies[i].ToBytes(packet, ref length); } + QueryRepliesStart += QueryRepliesCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + QueryRepliesStart < QueryReplies.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ParcelInfoRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ParcelID; + + public override int Length + { + get + { + return 16; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ParcelID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ParcelID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelInfoRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelInfoRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 54; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelInfoRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelInfoRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelInfoReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ParcelID; + public UUID OwnerID; + public byte[] Name; + public byte[] Desc; + public int ActualArea; + public int BillableArea; + public byte Flags; + public float GlobalX; + public float GlobalY; + public float GlobalZ; + public byte[] SimName; + public UUID SnapshotID; + public float Dwell; + public int SalePrice; + public int AuctionID; + + public override int Length + { + get + { + int length = 84; + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ParcelID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + ActualArea = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + BillableArea = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (byte)bytes[i++]; + GlobalX = Utils.BytesToFloat(bytes, i); i += 4; + GlobalY = Utils.BytesToFloat(bytes, i); i += 4; + GlobalZ = Utils.BytesToFloat(bytes, i); i += 4; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + SnapshotID.FromBytes(bytes, i); i += 16; + Dwell = Utils.BytesToFloat(bytes, i); i += 4; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AuctionID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ParcelID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Desc.Length; + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + Utils.IntToBytes(ActualArea, bytes, i); i += 4; + Utils.IntToBytes(BillableArea, bytes, i); i += 4; + bytes[i++] = Flags; + Utils.FloatToBytes(GlobalX, bytes, i); i += 4; + Utils.FloatToBytes(GlobalY, bytes, i); i += 4; + Utils.FloatToBytes(GlobalZ, bytes, i); i += 4; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + SnapshotID.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(Dwell, bytes, i); i += 4; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + Utils.IntToBytes(AuctionID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelInfoReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelInfoReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 55; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelInfoReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelInfoReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelObjectOwnersRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelObjectOwnersRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelObjectOwnersRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 56; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelObjectOwnersRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelObjectOwnersRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelObjectOwnersReplyPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public UUID OwnerID; + public bool IsGroupOwned; + public int Count; + public bool OnlineStatus; + + public override int Length + { + get + { + return 22; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OwnerID.FromBytes(bytes, i); i += 16; + IsGroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + Count = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OnlineStatus = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsGroupOwned) ? 1 : 0); + Utils.IntToBytes(Count, bytes, i); i += 4; + bytes[i++] = (byte)((OnlineStatus) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public DataBlock[] Data; + + public ParcelObjectOwnersReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.ParcelObjectOwnersReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 57; + Header.Reliable = true; + Header.Zerocoded = true; + Data = null; + } + + public ParcelObjectOwnersReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public ParcelObjectOwnersReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupNoticesListRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public GroupNoticesListRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupNoticesListRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 58; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public GroupNoticesListRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public GroupNoticesListRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupNoticesListReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID NoticeID; + public uint Timestamp; + public byte[] FromName; + public byte[] Subject; + public bool HasAttachment; + public byte AssetType; + + public override int Length + { + get + { + int length = 26; + if (FromName != null) { length += FromName.Length; } + if (Subject != null) { length += Subject.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + NoticeID.FromBytes(bytes, i); i += 16; + Timestamp = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = (bytes[i++] + (bytes[i++] << 8)); + FromName = new byte[length]; + Buffer.BlockCopy(bytes, i, FromName, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Subject = new byte[length]; + Buffer.BlockCopy(bytes, i, Subject, 0, length); i += length; + HasAttachment = (bytes[i++] != 0) ? (bool)true : (bool)false; + AssetType = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + NoticeID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Timestamp, bytes, i); i += 4; + bytes[i++] = (byte)(FromName.Length % 256); + bytes[i++] = (byte)((FromName.Length >> 8) % 256); + Buffer.BlockCopy(FromName, 0, bytes, i, FromName.Length); i += FromName.Length; + bytes[i++] = (byte)(Subject.Length % 256); + bytes[i++] = (byte)((Subject.Length >> 8) % 256); + Buffer.BlockCopy(Subject, 0, bytes, i, Subject.Length); i += Subject.Length; + bytes[i++] = (byte)((HasAttachment) ? 1 : 0); + bytes[i++] = AssetType; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock[] Data; + + public GroupNoticesListReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupNoticesListReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 59; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = null; + } + + public GroupNoticesListReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public GroupNoticesListReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupNoticeRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID GroupNoticeID; + + public override int Length + { + get + { + return 16; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupNoticeID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupNoticeID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public GroupNoticeRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupNoticeRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 60; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public GroupNoticeRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public GroupNoticeRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InfoBlock : PacketBlock + { + public UUID RegionID; + public Vector3 Position; + public Vector3 LookAt; + + public override int Length + { + get + { + return 40; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionID.FromBytes(bytes, i); i += 16; + Position.FromBytes(bytes, i); i += 12; + LookAt.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RegionID.ToBytes(bytes, i); i += 16; + Position.ToBytes(bytes, i); i += 12; + LookAt.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Info.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InfoBlock Info; + + public TeleportRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 62; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Info = new InfoBlock(); + } + + public TeleportRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public TeleportRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportLocationRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InfoBlock : PacketBlock + { + public ulong RegionHandle; + public Vector3 Position; + public Vector3 LookAt; + + public override int Length + { + get + { + return 32; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + Position.FromBytes(bytes, i); i += 12; + LookAt.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + Position.ToBytes(bytes, i); i += 12; + LookAt.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Info.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InfoBlock Info; + + public TeleportLocationRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportLocationRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 63; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Info = new InfoBlock(); + } + + public TeleportLocationRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public TeleportLocationRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportLocalPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public UUID AgentID; + public uint LocationID; + public Vector3 Position; + public Vector3 LookAt; + public uint TeleportFlags; + + public override int Length + { + get + { + return 48; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + LocationID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Position.FromBytes(bytes, i); i += 12; + LookAt.FromBytes(bytes, i); i += 12; + TeleportFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(LocationID, bytes, i); i += 4; + Position.ToBytes(bytes, i); i += 12; + LookAt.ToBytes(bytes, i); i += 12; + Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Info.Length; + return length; + } + } + public InfoBlock Info; + + public TeleportLocalPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportLocal; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 64; + Header.Reliable = true; + Info = new InfoBlock(); + } + + public TeleportLocalPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + } + + public TeleportLocalPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportLandmarkRequestPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID LandmarkID; + + public override int Length + { + get + { + return 48; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + LandmarkID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + LandmarkID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Info.Length; + return length; + } + } + public InfoBlock Info; + + public TeleportLandmarkRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportLandmarkRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 65; + Header.Reliable = true; + Header.Zerocoded = true; + Info = new InfoBlock(); + } + + public TeleportLandmarkRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + } + + public TeleportLandmarkRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportProgressPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InfoBlock : PacketBlock + { + public uint TeleportFlags; + public byte[] Message; + + public override int Length + { + get + { + int length = 5; + if (Message != null) { length += Message.Length; } + return length; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TeleportFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4; + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Info.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InfoBlock Info; + + public TeleportProgressPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportProgress; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 66; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Info = new InfoBlock(); + } + + public TeleportProgressPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public TeleportProgressPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportFinishPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public UUID AgentID; + public uint LocationID; + public uint SimIP; + public ushort SimPort; + public ulong RegionHandle; + public byte[] SeedCapability; + public byte SimAccess; + public uint TeleportFlags; + + public override int Length + { + get + { + int length = 41; + if (SeedCapability != null) { length += SeedCapability.Length; } + return length; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + LocationID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SimIP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SimPort = (ushort)((bytes[i++] << 8) + bytes[i++]); + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + length = (bytes[i++] + (bytes[i++] << 8)); + SeedCapability = new byte[length]; + Buffer.BlockCopy(bytes, i, SeedCapability, 0, length); i += length; + SimAccess = (byte)bytes[i++]; + TeleportFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(LocationID, bytes, i); i += 4; + Utils.UIntToBytes(SimIP, bytes, i); i += 4; + bytes[i++] = (byte)((SimPort >> 8) % 256); + bytes[i++] = (byte)(SimPort % 256); + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + bytes[i++] = (byte)(SeedCapability.Length % 256); + bytes[i++] = (byte)((SeedCapability.Length >> 8) % 256); + Buffer.BlockCopy(SeedCapability, 0, bytes, i, SeedCapability.Length); i += SeedCapability.Length; + bytes[i++] = SimAccess; + Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Info.Length; + return length; + } + } + public InfoBlock Info; + + public TeleportFinishPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportFinish; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 69; + Header.Reliable = true; + Info = new InfoBlock(); + } + + public TeleportFinishPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + } + + public TeleportFinishPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class StartLurePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InfoBlock : PacketBlock + { + public byte LureType; + public byte[] Message; + + public override int Length + { + get + { + int length = 2; + if (Message != null) { length += Message.Length; } + return length; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + LureType = (byte)bytes[i++]; + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = LureType; + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + } + + } + + /// + public sealed class TargetDataBlock : PacketBlock + { + public UUID TargetID; + + public override int Length + { + get + { + return 16; + } + } + + public TargetDataBlock() { } + public TargetDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TargetID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TargetID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += Info.Length; + for (int j = 0; j < TargetData.Length; j++) + length += TargetData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InfoBlock Info; + public TargetDataBlock[] TargetData; + + public StartLurePacket() + { + HasVariableBlocks = true; + Type = PacketType.StartLure; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 70; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Info = new InfoBlock(); + TargetData = null; + } + + public StartLurePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(TargetData == null || TargetData.Length != -1) { + TargetData = new TargetDataBlock[count]; + for(int j = 0; j < count; j++) + { TargetData[j] = new TargetDataBlock(); } + } + for (int j = 0; j < count; j++) + { TargetData[j].FromBytes(bytes, ref i); } + } + + public StartLurePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(TargetData == null || TargetData.Length != count) { + TargetData = new TargetDataBlock[count]; + for(int j = 0; j < count; j++) + { TargetData[j] = new TargetDataBlock(); } + } + for (int j = 0; j < count; j++) + { TargetData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Info.Length; + length++; + for (int j = 0; j < TargetData.Length; j++) { length += TargetData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + bytes[i++] = (byte)TargetData.Length; + for (int j = 0; j < TargetData.Length; j++) { TargetData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += Info.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + Info.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int TargetDataStart = 0; + do + { + int variableLength = 0; + int TargetDataCount = 0; + + i = TargetDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < TargetData.Length) { + int blockLength = TargetData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++TargetDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)TargetDataCount; + for (i = TargetDataStart; i < TargetDataStart + TargetDataCount; i++) { TargetData[i].ToBytes(packet, ref length); } + TargetDataStart += TargetDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + TargetDataStart < TargetData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class TeleportLureRequestPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID LureID; + public uint TeleportFlags; + + public override int Length + { + get + { + return 52; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + LureID.FromBytes(bytes, i); i += 16; + TeleportFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + LureID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Info.Length; + return length; + } + } + public InfoBlock Info; + + public TeleportLureRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportLureRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 71; + Header.Reliable = true; + Info = new InfoBlock(); + } + + public TeleportLureRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + } + + public TeleportLureRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportCancelPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Info.Length; + return length; + } + } + public InfoBlock Info; + + public TeleportCancelPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportCancel; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 72; + Header.Reliable = true; + Info = new InfoBlock(); + } + + public TeleportCancelPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + } + + public TeleportCancelPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportStartPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public uint TeleportFlags; + + public override int Length + { + get + { + return 4; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TeleportFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Info.Length; + return length; + } + } + public InfoBlock Info; + + public TeleportStartPacket() + { + HasVariableBlocks = false; + Type = PacketType.TeleportStart; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 73; + Header.Reliable = true; + Info = new InfoBlock(); + } + + public TeleportStartPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + } + + public TeleportStartPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TeleportFailedPacket : Packet + { + /// + public sealed class InfoBlock : PacketBlock + { + public UUID AgentID; + public byte[] Reason; + + public override int Length + { + get + { + int length = 17; + if (Reason != null) { length += Reason.Length; } + return length; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Reason = new byte[length]; + Buffer.BlockCopy(bytes, i, Reason, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Reason.Length; + Buffer.BlockCopy(Reason, 0, bytes, i, Reason.Length); i += Reason.Length; + } + + } + + /// + public sealed class AlertInfoBlock : PacketBlock + { + public byte[] Message; + public byte[] ExtraParams; + + public override int Length + { + get + { + int length = 2; + if (Message != null) { length += Message.Length; } + if (ExtraParams != null) { length += ExtraParams.Length; } + return length; + } + } + + public AlertInfoBlock() { } + public AlertInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + length = bytes[i++]; + ExtraParams = new byte[length]; + Buffer.BlockCopy(bytes, i, ExtraParams, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + bytes[i++] = (byte)ExtraParams.Length; + Buffer.BlockCopy(ExtraParams, 0, bytes, i, ExtraParams.Length); i += ExtraParams.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += Info.Length; + for (int j = 0; j < AlertInfo.Length; j++) + length += AlertInfo[j].Length; + return length; + } + } + public InfoBlock Info; + public AlertInfoBlock[] AlertInfo; + + public TeleportFailedPacket() + { + HasVariableBlocks = true; + Type = PacketType.TeleportFailed; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 74; + Header.Reliable = true; + Info = new InfoBlock(); + AlertInfo = null; + } + + public TeleportFailedPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Info.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AlertInfo == null || AlertInfo.Length != -1) { + AlertInfo = new AlertInfoBlock[count]; + for(int j = 0; j < count; j++) + { AlertInfo[j] = new AlertInfoBlock(); } + } + for (int j = 0; j < count; j++) + { AlertInfo[j].FromBytes(bytes, ref i); } + } + + public TeleportFailedPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Info.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AlertInfo == null || AlertInfo.Length != count) { + AlertInfo = new AlertInfoBlock[count]; + for(int j = 0; j < count; j++) + { AlertInfo[j] = new AlertInfoBlock(); } + } + for (int j = 0; j < count; j++) + { AlertInfo[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += Info.Length; + length++; + for (int j = 0; j < AlertInfo.Length; j++) { length += AlertInfo[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + bytes[i++] = (byte)AlertInfo.Length; + for (int j = 0; j < AlertInfo.Length; j++) { AlertInfo[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += Info.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + Info.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int AlertInfoStart = 0; + do + { + int variableLength = 0; + int AlertInfoCount = 0; + + i = AlertInfoStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AlertInfo.Length) { + int blockLength = AlertInfo[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AlertInfoCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)AlertInfoCount; + for (i = AlertInfoStart; i < AlertInfoStart + AlertInfoCount; i++) { AlertInfo[i].ToBytes(packet, ref length); } + AlertInfoStart += AlertInfoCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + AlertInfoStart < AlertInfo.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UndoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public UndoPacket() + { + HasVariableBlocks = true; + Type = PacketType.Undo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 75; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public UndoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public UndoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RedoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public RedoPacket() + { + HasVariableBlocks = true; + Type = PacketType.Redo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 76; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public RedoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public RedoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UndoLandPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public UndoLandPacket() + { + HasVariableBlocks = false; + Type = PacketType.UndoLand; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 77; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public UndoLandPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public UndoLandPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentPausePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint SerialNum; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + SerialNum = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(SerialNum, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentPausePacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentPause; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 78; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public AgentPausePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentPausePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentResumePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint SerialNum; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + SerialNum = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(SerialNum, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentResumePacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentResume; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 79; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public AgentResumePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentResumePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ChatFromViewerPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ChatDataBlock : PacketBlock + { + public byte[] Message; + public byte Type; + public int Channel; + + public override int Length + { + get + { + int length = 7; + if (Message != null) { length += Message.Length; } + return length; + } + } + + public ChatDataBlock() { } + public ChatDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + Type = (byte)bytes[i++]; + Channel = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(Message.Length % 256); + bytes[i++] = (byte)((Message.Length >> 8) % 256); + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + bytes[i++] = Type; + Utils.IntToBytes(Channel, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ChatData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ChatDataBlock ChatData; + + public ChatFromViewerPacket() + { + HasVariableBlocks = false; + Type = PacketType.ChatFromViewer; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 80; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ChatData = new ChatDataBlock(); + } + + public ChatFromViewerPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ChatData.FromBytes(bytes, ref i); + } + + public ChatFromViewerPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ChatData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ChatData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ChatData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentThrottlePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint CircuitCode; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + CircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CircuitCode, bytes, i); i += 4; + } + + } + + /// + public sealed class ThrottleBlock : PacketBlock + { + public uint GenCounter; + public byte[] Throttles; + + public override int Length + { + get + { + int length = 5; + if (Throttles != null) { length += Throttles.Length; } + return length; + } + } + + public ThrottleBlock() { } + public ThrottleBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GenCounter = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Throttles = new byte[length]; + Buffer.BlockCopy(bytes, i, Throttles, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(GenCounter, bytes, i); i += 4; + bytes[i++] = (byte)Throttles.Length; + Buffer.BlockCopy(Throttles, 0, bytes, i, Throttles.Length); i += Throttles.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Throttle.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ThrottleBlock Throttle; + + public AgentThrottlePacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentThrottle; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 81; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Throttle = new ThrottleBlock(); + } + + public AgentThrottlePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Throttle.FromBytes(bytes, ref i); + } + + public AgentThrottlePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Throttle.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Throttle.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Throttle.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentFOVPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint CircuitCode; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + CircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CircuitCode, bytes, i); i += 4; + } + + } + + /// + public sealed class FOVBlockBlock : PacketBlock + { + public uint GenCounter; + public float VerticalAngle; + + public override int Length + { + get + { + return 8; + } + } + + public FOVBlockBlock() { } + public FOVBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GenCounter = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + VerticalAngle = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(GenCounter, bytes, i); i += 4; + Utils.FloatToBytes(VerticalAngle, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += FOVBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public FOVBlockBlock FOVBlock; + + public AgentFOVPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentFOV; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 82; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + FOVBlock = new FOVBlockBlock(); + } + + public AgentFOVPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + FOVBlock.FromBytes(bytes, ref i); + } + + public AgentFOVPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + FOVBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += FOVBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + FOVBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentHeightWidthPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint CircuitCode; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + CircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CircuitCode, bytes, i); i += 4; + } + + } + + /// + public sealed class HeightWidthBlockBlock : PacketBlock + { + public uint GenCounter; + public ushort Height; + public ushort Width; + + public override int Length + { + get + { + return 8; + } + } + + public HeightWidthBlockBlock() { } + public HeightWidthBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GenCounter = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Height = (ushort)(bytes[i++] + (bytes[i++] << 8)); + Width = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(GenCounter, bytes, i); i += 4; + bytes[i++] = (byte)(Height % 256); + bytes[i++] = (byte)((Height >> 8) % 256); + bytes[i++] = (byte)(Width % 256); + bytes[i++] = (byte)((Width >> 8) % 256); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += HeightWidthBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public HeightWidthBlockBlock HeightWidthBlock; + + public AgentHeightWidthPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentHeightWidth; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 83; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + HeightWidthBlock = new HeightWidthBlockBlock(); + } + + public AgentHeightWidthPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + HeightWidthBlock.FromBytes(bytes, ref i); + } + + public AgentHeightWidthPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + HeightWidthBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += HeightWidthBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + HeightWidthBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentSetAppearancePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint SerialNum; + public Vector3 Size; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + SerialNum = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Size.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(SerialNum, bytes, i); i += 4; + Size.ToBytes(bytes, i); i += 12; + } + + } + + /// + public sealed class WearableDataBlock : PacketBlock + { + public UUID CacheID; + public byte TextureIndex; + + public override int Length + { + get + { + return 17; + } + } + + public WearableDataBlock() { } + public WearableDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + CacheID.FromBytes(bytes, i); i += 16; + TextureIndex = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + CacheID.ToBytes(bytes, i); i += 16; + bytes[i++] = TextureIndex; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public byte[] TextureEntry; + + public override int Length + { + get + { + int length = 2; + if (TextureEntry != null) { length += TextureEntry.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + TextureEntry = new byte[length]; + Buffer.BlockCopy(bytes, i, TextureEntry, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(TextureEntry.Length % 256); + bytes[i++] = (byte)((TextureEntry.Length >> 8) % 256); + Buffer.BlockCopy(TextureEntry, 0, bytes, i, TextureEntry.Length); i += TextureEntry.Length; + } + + } + + /// + public sealed class VisualParamBlock : PacketBlock + { + public byte ParamValue; + + public override int Length + { + get + { + return 1; + } + } + + public VisualParamBlock() { } + public VisualParamBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ParamValue = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = ParamValue; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + for (int j = 0; j < WearableData.Length; j++) + length += WearableData[j].Length; + length += ObjectData.Length; + for (int j = 0; j < VisualParam.Length; j++) + length += VisualParam[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public WearableDataBlock[] WearableData; + public ObjectDataBlock ObjectData; + public VisualParamBlock[] VisualParam; + + public AgentSetAppearancePacket() + { + HasVariableBlocks = true; + Type = PacketType.AgentSetAppearance; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 84; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + WearableData = null; + ObjectData = new ObjectDataBlock(); + VisualParam = null; + } + + public AgentSetAppearancePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != -1) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + ObjectData.FromBytes(bytes, ref i); + count = (int)bytes[i++]; + if(VisualParam == null || VisualParam.Length != -1) { + VisualParam = new VisualParamBlock[count]; + for(int j = 0; j < count; j++) + { VisualParam[j] = new VisualParamBlock(); } + } + for (int j = 0; j < count; j++) + { VisualParam[j].FromBytes(bytes, ref i); } + } + + public AgentSetAppearancePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != count) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + ObjectData.FromBytes(bytes, ref i); + count = (int)bytes[i++]; + if(VisualParam == null || VisualParam.Length != count) { + VisualParam = new VisualParamBlock[count]; + for(int j = 0; j < count; j++) + { VisualParam[j] = new VisualParamBlock(); } + } + for (int j = 0; j < count; j++) + { VisualParam[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + length++; + for (int j = 0; j < WearableData.Length; j++) { length += WearableData[j].Length; } + length++; + for (int j = 0; j < VisualParam.Length; j++) { length += VisualParam[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)WearableData.Length; + for (int j = 0; j < WearableData.Length; j++) { WearableData[j].ToBytes(bytes, ref i); } + ObjectData.ToBytes(bytes, ref i); + bytes[i++] = (byte)VisualParam.Length; + for (int j = 0; j < VisualParam.Length; j++) { VisualParam[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentQuitCopyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FuseBlockBlock : PacketBlock + { + public uint ViewerCircuitCode; + + public override int Length + { + get + { + return 4; + } + } + + public FuseBlockBlock() { } + public FuseBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ViewerCircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ViewerCircuitCode, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += FuseBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public FuseBlockBlock FuseBlock; + + public AgentQuitCopyPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentQuitCopy; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 85; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + FuseBlock = new FuseBlockBlock(); + } + + public AgentQuitCopyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + FuseBlock.FromBytes(bytes, ref i); + } + + public AgentQuitCopyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + FuseBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += FuseBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + FuseBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ImageNotInDatabasePacket : Packet + { + /// + public sealed class ImageIDBlock : PacketBlock + { + public UUID ID; + + public override int Length + { + get + { + return 16; + } + } + + public ImageIDBlock() { } + public ImageIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ImageID.Length; + return length; + } + } + public ImageIDBlock ImageID; + + public ImageNotInDatabasePacket() + { + HasVariableBlocks = false; + Type = PacketType.ImageNotInDatabase; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 86; + Header.Reliable = true; + ImageID = new ImageIDBlock(); + } + + public ImageNotInDatabasePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ImageID.FromBytes(bytes, ref i); + } + + public ImageNotInDatabasePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ImageID.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ImageID.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ImageID.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RebakeAvatarTexturesPacket : Packet + { + /// + public sealed class TextureDataBlock : PacketBlock + { + public UUID TextureID; + + public override int Length + { + get + { + return 16; + } + } + + public TextureDataBlock() { } + public TextureDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TextureID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TextureID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TextureData.Length; + return length; + } + } + public TextureDataBlock TextureData; + + public RebakeAvatarTexturesPacket() + { + HasVariableBlocks = false; + Type = PacketType.RebakeAvatarTextures; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 87; + Header.Reliable = true; + TextureData = new TextureDataBlock(); + } + + public RebakeAvatarTexturesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TextureData.FromBytes(bytes, ref i); + } + + public RebakeAvatarTexturesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TextureData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TextureData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TextureData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SetAlwaysRunPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public bool AlwaysRun; + + public override int Length + { + get + { + return 33; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + AlwaysRun = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((AlwaysRun) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public SetAlwaysRunPacket() + { + HasVariableBlocks = false; + Type = PacketType.SetAlwaysRun; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 88; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public SetAlwaysRunPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public SetAlwaysRunPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectDeletePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public bool Force; + + public override int Length + { + get + { + return 33; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Force = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Force) ? 1 : 0); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectDeletePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDelete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 89; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectDeletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDeletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDuplicatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class SharedDataBlock : PacketBlock + { + public Vector3 Offset; + public uint DuplicateFlags; + + public override int Length + { + get + { + return 16; + } + } + + public SharedDataBlock() { } + public SharedDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Offset.FromBytes(bytes, i); i += 12; + DuplicateFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Offset.ToBytes(bytes, i); i += 12; + Utils.UIntToBytes(DuplicateFlags, bytes, i); i += 4; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += SharedData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public SharedDataBlock SharedData; + public ObjectDataBlock[] ObjectData; + + public ObjectDuplicatePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDuplicate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 90; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + SharedData = new SharedDataBlock(); + ObjectData = null; + } + + public ObjectDuplicatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + SharedData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDuplicatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + SharedData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += SharedData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + SharedData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += SharedData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + SharedData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDuplicateOnRayPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + public Vector3 RayStart; + public Vector3 RayEnd; + public bool BypassRaycast; + public bool RayEndIsIntersection; + public bool CopyCenters; + public bool CopyRotates; + public UUID RayTargetID; + public uint DuplicateFlags; + + public override int Length + { + get + { + return 96; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + RayStart.FromBytes(bytes, i); i += 12; + RayEnd.FromBytes(bytes, i); i += 12; + BypassRaycast = (bytes[i++] != 0) ? (bool)true : (bool)false; + RayEndIsIntersection = (bytes[i++] != 0) ? (bool)true : (bool)false; + CopyCenters = (bytes[i++] != 0) ? (bool)true : (bool)false; + CopyRotates = (bytes[i++] != 0) ? (bool)true : (bool)false; + RayTargetID.FromBytes(bytes, i); i += 16; + DuplicateFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + RayStart.ToBytes(bytes, i); i += 12; + RayEnd.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)((BypassRaycast) ? 1 : 0); + bytes[i++] = (byte)((RayEndIsIntersection) ? 1 : 0); + bytes[i++] = (byte)((CopyCenters) ? 1 : 0); + bytes[i++] = (byte)((CopyRotates) ? 1 : 0); + RayTargetID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(DuplicateFlags, bytes, i); i += 4; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectDuplicateOnRayPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDuplicateOnRay; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 91; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectDuplicateOnRayPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDuplicateOnRayPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectScalePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public Vector3 Scale; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Scale.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + Scale.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectScalePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectScale; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 92; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectScalePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectScalePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectRotationPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public Quaternion Rotation; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Rotation.FromBytes(bytes, i, true); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + Rotation.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectRotationPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectRotation; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 93; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectRotationPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectRotationPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectFlagUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint ObjectLocalID; + public bool UsePhysics; + public bool IsTemporary; + public bool IsPhantom; + public bool CastsShadows; + + public override int Length + { + get + { + return 40; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + UsePhysics = (bytes[i++] != 0) ? (bool)true : (bool)false; + IsTemporary = (bytes[i++] != 0) ? (bool)true : (bool)false; + IsPhantom = (bytes[i++] != 0) ? (bool)true : (bool)false; + CastsShadows = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = (byte)((UsePhysics) ? 1 : 0); + bytes[i++] = (byte)((IsTemporary) ? 1 : 0); + bytes[i++] = (byte)((IsPhantom) ? 1 : 0); + bytes[i++] = (byte)((CastsShadows) ? 1 : 0); + } + + } + + /// + public sealed class ExtraPhysicsBlock : PacketBlock + { + public byte PhysicsShapeType; + public float Density; + public float Friction; + public float Restitution; + public float GravityMultiplier; + + public override int Length + { + get + { + return 17; + } + } + + public ExtraPhysicsBlock() { } + public ExtraPhysicsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PhysicsShapeType = (byte)bytes[i++]; + Density = Utils.BytesToFloat(bytes, i); i += 4; + Friction = Utils.BytesToFloat(bytes, i); i += 4; + Restitution = Utils.BytesToFloat(bytes, i); i += 4; + GravityMultiplier = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = PhysicsShapeType; + Utils.FloatToBytes(Density, bytes, i); i += 4; + Utils.FloatToBytes(Friction, bytes, i); i += 4; + Utils.FloatToBytes(Restitution, bytes, i); i += 4; + Utils.FloatToBytes(GravityMultiplier, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ExtraPhysics.Length; j++) + length += ExtraPhysics[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ExtraPhysicsBlock[] ExtraPhysics; + + public ObjectFlagUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectFlagUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 94; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ExtraPhysics = null; + } + + public ObjectFlagUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ExtraPhysics == null || ExtraPhysics.Length != -1) { + ExtraPhysics = new ExtraPhysicsBlock[count]; + for(int j = 0; j < count; j++) + { ExtraPhysics[j] = new ExtraPhysicsBlock(); } + } + for (int j = 0; j < count; j++) + { ExtraPhysics[j].FromBytes(bytes, ref i); } + } + + public ObjectFlagUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ExtraPhysics == null || ExtraPhysics.Length != count) { + ExtraPhysics = new ExtraPhysicsBlock[count]; + for(int j = 0; j < count; j++) + { ExtraPhysics[j] = new ExtraPhysicsBlock(); } + } + for (int j = 0; j < count; j++) + { ExtraPhysics[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ExtraPhysics.Length; j++) { length += ExtraPhysics[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ExtraPhysics.Length; + for (int j = 0; j < ExtraPhysics.Length; j++) { ExtraPhysics[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ExtraPhysicsStart = 0; + do + { + int variableLength = 0; + int ExtraPhysicsCount = 0; + + i = ExtraPhysicsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ExtraPhysics.Length) { + int blockLength = ExtraPhysics[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ExtraPhysicsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ExtraPhysicsCount; + for (i = ExtraPhysicsStart; i < ExtraPhysicsStart + ExtraPhysicsCount; i++) { ExtraPhysics[i].ToBytes(packet, ref length); } + ExtraPhysicsStart += ExtraPhysicsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ExtraPhysicsStart < ExtraPhysics.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectClickActionPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public byte ClickAction; + + public override int Length + { + get + { + return 5; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ClickAction = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = ClickAction; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectClickActionPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectClickAction; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 95; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectClickActionPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectClickActionPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectImagePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public byte[] MediaURL; + public byte[] TextureEntry; + + public override int Length + { + get + { + int length = 7; + if (MediaURL != null) { length += MediaURL.Length; } + if (TextureEntry != null) { length += TextureEntry.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + MediaURL = new byte[length]; + Buffer.BlockCopy(bytes, i, MediaURL, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + TextureEntry = new byte[length]; + Buffer.BlockCopy(bytes, i, TextureEntry, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = (byte)MediaURL.Length; + Buffer.BlockCopy(MediaURL, 0, bytes, i, MediaURL.Length); i += MediaURL.Length; + bytes[i++] = (byte)(TextureEntry.Length % 256); + bytes[i++] = (byte)((TextureEntry.Length >> 8) % 256); + Buffer.BlockCopy(TextureEntry, 0, bytes, i, TextureEntry.Length); i += TextureEntry.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectImagePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectImage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 96; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectImagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectImagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectMaterialPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public byte Material; + + public override int Length + { + get + { + return 5; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Material = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = Material; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectMaterialPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectMaterial; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 97; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectMaterialPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectMaterialPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectShapePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public byte PathCurve; + public byte ProfileCurve; + public ushort PathBegin; + public ushort PathEnd; + public byte PathScaleX; + public byte PathScaleY; + public byte PathShearX; + public byte PathShearY; + public sbyte PathTwist; + public sbyte PathTwistBegin; + public sbyte PathRadiusOffset; + public sbyte PathTaperX; + public sbyte PathTaperY; + public byte PathRevolutions; + public sbyte PathSkew; + public ushort ProfileBegin; + public ushort ProfileEnd; + public ushort ProfileHollow; + + public override int Length + { + get + { + return 27; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PathCurve = (byte)bytes[i++]; + ProfileCurve = (byte)bytes[i++]; + PathBegin = (ushort)(bytes[i++] + (bytes[i++] << 8)); + PathEnd = (ushort)(bytes[i++] + (bytes[i++] << 8)); + PathScaleX = (byte)bytes[i++]; + PathScaleY = (byte)bytes[i++]; + PathShearX = (byte)bytes[i++]; + PathShearY = (byte)bytes[i++]; + PathTwist = (sbyte)bytes[i++]; + PathTwistBegin = (sbyte)bytes[i++]; + PathRadiusOffset = (sbyte)bytes[i++]; + PathTaperX = (sbyte)bytes[i++]; + PathTaperY = (sbyte)bytes[i++]; + PathRevolutions = (byte)bytes[i++]; + PathSkew = (sbyte)bytes[i++]; + ProfileBegin = (ushort)(bytes[i++] + (bytes[i++] << 8)); + ProfileEnd = (ushort)(bytes[i++] + (bytes[i++] << 8)); + ProfileHollow = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = PathCurve; + bytes[i++] = ProfileCurve; + bytes[i++] = (byte)(PathBegin % 256); + bytes[i++] = (byte)((PathBegin >> 8) % 256); + bytes[i++] = (byte)(PathEnd % 256); + bytes[i++] = (byte)((PathEnd >> 8) % 256); + bytes[i++] = PathScaleX; + bytes[i++] = PathScaleY; + bytes[i++] = PathShearX; + bytes[i++] = PathShearY; + bytes[i++] = (byte)PathTwist; + bytes[i++] = (byte)PathTwistBegin; + bytes[i++] = (byte)PathRadiusOffset; + bytes[i++] = (byte)PathTaperX; + bytes[i++] = (byte)PathTaperY; + bytes[i++] = PathRevolutions; + bytes[i++] = (byte)PathSkew; + bytes[i++] = (byte)(ProfileBegin % 256); + bytes[i++] = (byte)((ProfileBegin >> 8) % 256); + bytes[i++] = (byte)(ProfileEnd % 256); + bytes[i++] = (byte)((ProfileEnd >> 8) % 256); + bytes[i++] = (byte)(ProfileHollow % 256); + bytes[i++] = (byte)((ProfileHollow >> 8) % 256); + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectShapePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectShape; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 98; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectShapePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectShapePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectExtraParamsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public ushort ParamType; + public bool ParamInUse; + public uint ParamSize; + public byte[] ParamData; + + public override int Length + { + get + { + int length = 12; + if (ParamData != null) { length += ParamData.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParamType = (ushort)(bytes[i++] + (bytes[i++] << 8)); + ParamInUse = (bytes[i++] != 0) ? (bool)true : (bool)false; + ParamSize = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + ParamData = new byte[length]; + Buffer.BlockCopy(bytes, i, ParamData, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = (byte)(ParamType % 256); + bytes[i++] = (byte)((ParamType >> 8) % 256); + bytes[i++] = (byte)((ParamInUse) ? 1 : 0); + Utils.UIntToBytes(ParamSize, bytes, i); i += 4; + bytes[i++] = (byte)ParamData.Length; + Buffer.BlockCopy(ParamData, 0, bytes, i, ParamData.Length); i += ParamData.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectExtraParamsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectExtraParams; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 99; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectExtraParamsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectExtraParamsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectOwnerPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class HeaderDataBlock : PacketBlock + { + public bool Override; + public UUID OwnerID; + public UUID GroupID; + + public override int Length + { + get + { + return 33; + } + } + + public HeaderDataBlock() { } + public HeaderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Override = (bytes[i++] != 0) ? (bool)true : (bool)false; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((Override) ? 1 : 0); + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += HeaderData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public HeaderDataBlock HeaderData; + public ObjectDataBlock[] ObjectData; + + public ObjectOwnerPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectOwner; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 100; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + HeaderData = new HeaderDataBlock(); + ObjectData = null; + } + + public ObjectOwnerPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectOwnerPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += HeaderData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + HeaderData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += HeaderData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + HeaderData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectGroupPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectGroupPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectGroup; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 101; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectGroupPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectGroupPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectBuyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + public UUID CategoryID; + + public override int Length + { + get + { + return 64; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + CategoryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + CategoryID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public byte SaleType; + public int SalePrice; + + public override int Length + { + get + { + return 9; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectBuyPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectBuy; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 102; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectBuyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectBuyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class BuyObjectInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ObjectID; + public UUID ItemID; + public UUID FolderID; + + public override int Length + { + get + { + return 48; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public BuyObjectInventoryPacket() + { + HasVariableBlocks = false; + Type = PacketType.BuyObjectInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 103; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public BuyObjectInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public BuyObjectInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DerezContainerPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public UUID ObjectID; + public bool Delete; + + public override int Length + { + get + { + return 17; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + Delete = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Delete) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += Data.Length; + return length; + } + } + public DataBlock Data; + + public DerezContainerPacket() + { + HasVariableBlocks = false; + Type = PacketType.DerezContainer; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 104; + Header.Reliable = true; + Header.Zerocoded = true; + Data = new DataBlock(); + } + + public DerezContainerPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Data.FromBytes(bytes, ref i); + } + + public DerezContainerPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectPermissionsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class HeaderDataBlock : PacketBlock + { + public bool Override; + + public override int Length + { + get + { + return 1; + } + } + + public HeaderDataBlock() { } + public HeaderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Override = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((Override) ? 1 : 0); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public byte Field; + public byte Set; + public uint Mask; + + public override int Length + { + get + { + return 10; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Field = (byte)bytes[i++]; + Set = (byte)bytes[i++]; + Mask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = Field; + bytes[i++] = Set; + Utils.UIntToBytes(Mask, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += HeaderData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public HeaderDataBlock HeaderData; + public ObjectDataBlock[] ObjectData; + + public ObjectPermissionsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectPermissions; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 105; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + HeaderData = new HeaderDataBlock(); + ObjectData = null; + } + + public ObjectPermissionsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectPermissionsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += HeaderData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + HeaderData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += HeaderData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + HeaderData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectSaleInfoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint LocalID; + public byte SaleType; + public int SalePrice; + + public override int Length + { + get + { + return 9; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectSaleInfoPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectSaleInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 106; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectSaleInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectSaleInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectNamePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint LocalID; + public byte[] Name; + + public override int Length + { + get + { + int length = 5; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectNamePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectName; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 107; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectNamePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectNamePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDescriptionPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint LocalID; + public byte[] Description; + + public override int Length + { + get + { + int length = 5; + if (Description != null) { length += Description.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectDescriptionPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDescription; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 108; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectDescriptionPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDescriptionPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectCategoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint LocalID; + public uint Category; + + public override int Length + { + get + { + return 8; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Category = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + Utils.UIntToBytes(Category, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectCategoryPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectCategory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 109; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectCategoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectCategoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectSelectPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectSelectPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectSelect; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 110; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectSelectPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectSelectPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDeselectPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectDeselectPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDeselect; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 111; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectDeselectPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDeselectPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectAttachPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public byte AttachmentPoint; + + public override int Length + { + get + { + return 33; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + AttachmentPoint = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + bytes[i++] = AttachmentPoint; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public Quaternion Rotation; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Rotation.FromBytes(bytes, i, true); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + Rotation.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectAttachPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectAttach; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 112; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectAttachPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectAttachPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDetachPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectDetachPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDetach; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 113; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectDetachPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDetachPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDropPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectDropPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDrop; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 114; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectDropPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDropPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectLinkPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectLinkPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectLink; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 115; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectLinkPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectLinkPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDelinkPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectDelinkPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDelink; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 116; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectDelinkPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectDelinkPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectGrabPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint LocalID; + public Vector3 GrabOffset; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GrabOffset.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + GrabOffset.ToBytes(bytes, i); i += 12; + } + + } + + /// + public sealed class SurfaceInfoBlock : PacketBlock + { + public Vector3 UVCoord; + public Vector3 STCoord; + public int FaceIndex; + public Vector3 Position; + public Vector3 Normal; + public Vector3 Binormal; + + public override int Length + { + get + { + return 64; + } + } + + public SurfaceInfoBlock() { } + public SurfaceInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + UVCoord.FromBytes(bytes, i); i += 12; + STCoord.FromBytes(bytes, i); i += 12; + FaceIndex = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Position.FromBytes(bytes, i); i += 12; + Normal.FromBytes(bytes, i); i += 12; + Binormal.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + UVCoord.ToBytes(bytes, i); i += 12; + STCoord.ToBytes(bytes, i); i += 12; + Utils.IntToBytes(FaceIndex, bytes, i); i += 4; + Position.ToBytes(bytes, i); i += 12; + Normal.ToBytes(bytes, i); i += 12; + Binormal.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += ObjectData.Length; + for (int j = 0; j < SurfaceInfo.Length; j++) + length += SurfaceInfo[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + public SurfaceInfoBlock[] SurfaceInfo; + + public ObjectGrabPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectGrab; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 117; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + SurfaceInfo = null; + } + + public ObjectGrabPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SurfaceInfo == null || SurfaceInfo.Length != -1) { + SurfaceInfo = new SurfaceInfoBlock[count]; + for(int j = 0; j < count; j++) + { SurfaceInfo[j] = new SurfaceInfoBlock(); } + } + for (int j = 0; j < count; j++) + { SurfaceInfo[j].FromBytes(bytes, ref i); } + } + + public ObjectGrabPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SurfaceInfo == null || SurfaceInfo.Length != count) { + SurfaceInfo = new SurfaceInfoBlock[count]; + for(int j = 0; j < count; j++) + { SurfaceInfo[j] = new SurfaceInfoBlock(); } + } + for (int j = 0; j < count; j++) + { SurfaceInfo[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + length++; + for (int j = 0; j < SurfaceInfo.Length; j++) { length += SurfaceInfo[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + bytes[i++] = (byte)SurfaceInfo.Length; + for (int j = 0; j < SurfaceInfo.Length; j++) { SurfaceInfo[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += ObjectData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + ObjectData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int SurfaceInfoStart = 0; + do + { + int variableLength = 0; + int SurfaceInfoCount = 0; + + i = SurfaceInfoStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < SurfaceInfo.Length) { + int blockLength = SurfaceInfo[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++SurfaceInfoCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)SurfaceInfoCount; + for (i = SurfaceInfoStart; i < SurfaceInfoStart + SurfaceInfoCount; i++) { SurfaceInfo[i].ToBytes(packet, ref length); } + SurfaceInfoStart += SurfaceInfoCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + SurfaceInfoStart < SurfaceInfo.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectGrabUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + public Vector3 GrabOffsetInitial; + public Vector3 GrabPosition; + public uint TimeSinceLast; + + public override int Length + { + get + { + return 44; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + GrabOffsetInitial.FromBytes(bytes, i); i += 12; + GrabPosition.FromBytes(bytes, i); i += 12; + TimeSinceLast = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + GrabOffsetInitial.ToBytes(bytes, i); i += 12; + GrabPosition.ToBytes(bytes, i); i += 12; + Utils.UIntToBytes(TimeSinceLast, bytes, i); i += 4; + } + + } + + /// + public sealed class SurfaceInfoBlock : PacketBlock + { + public Vector3 UVCoord; + public Vector3 STCoord; + public int FaceIndex; + public Vector3 Position; + public Vector3 Normal; + public Vector3 Binormal; + + public override int Length + { + get + { + return 64; + } + } + + public SurfaceInfoBlock() { } + public SurfaceInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + UVCoord.FromBytes(bytes, i); i += 12; + STCoord.FromBytes(bytes, i); i += 12; + FaceIndex = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Position.FromBytes(bytes, i); i += 12; + Normal.FromBytes(bytes, i); i += 12; + Binormal.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + UVCoord.ToBytes(bytes, i); i += 12; + STCoord.ToBytes(bytes, i); i += 12; + Utils.IntToBytes(FaceIndex, bytes, i); i += 4; + Position.ToBytes(bytes, i); i += 12; + Normal.ToBytes(bytes, i); i += 12; + Binormal.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += ObjectData.Length; + for (int j = 0; j < SurfaceInfo.Length; j++) + length += SurfaceInfo[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + public SurfaceInfoBlock[] SurfaceInfo; + + public ObjectGrabUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectGrabUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 118; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + SurfaceInfo = null; + } + + public ObjectGrabUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SurfaceInfo == null || SurfaceInfo.Length != -1) { + SurfaceInfo = new SurfaceInfoBlock[count]; + for(int j = 0; j < count; j++) + { SurfaceInfo[j] = new SurfaceInfoBlock(); } + } + for (int j = 0; j < count; j++) + { SurfaceInfo[j].FromBytes(bytes, ref i); } + } + + public ObjectGrabUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SurfaceInfo == null || SurfaceInfo.Length != count) { + SurfaceInfo = new SurfaceInfoBlock[count]; + for(int j = 0; j < count; j++) + { SurfaceInfo[j] = new SurfaceInfoBlock(); } + } + for (int j = 0; j < count; j++) + { SurfaceInfo[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + length++; + for (int j = 0; j < SurfaceInfo.Length; j++) { length += SurfaceInfo[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + bytes[i++] = (byte)SurfaceInfo.Length; + for (int j = 0; j < SurfaceInfo.Length; j++) { SurfaceInfo[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += ObjectData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + ObjectData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int SurfaceInfoStart = 0; + do + { + int variableLength = 0; + int SurfaceInfoCount = 0; + + i = SurfaceInfoStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < SurfaceInfo.Length) { + int blockLength = SurfaceInfo[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++SurfaceInfoCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)SurfaceInfoCount; + for (i = SurfaceInfoStart; i < SurfaceInfoStart + SurfaceInfoCount; i++) { SurfaceInfo[i].ToBytes(packet, ref length); } + SurfaceInfoStart += SurfaceInfoCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + SurfaceInfoStart < SurfaceInfo.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectDeGrabPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + } + + } + + /// + public sealed class SurfaceInfoBlock : PacketBlock + { + public Vector3 UVCoord; + public Vector3 STCoord; + public int FaceIndex; + public Vector3 Position; + public Vector3 Normal; + public Vector3 Binormal; + + public override int Length + { + get + { + return 64; + } + } + + public SurfaceInfoBlock() { } + public SurfaceInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + UVCoord.FromBytes(bytes, i); i += 12; + STCoord.FromBytes(bytes, i); i += 12; + FaceIndex = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Position.FromBytes(bytes, i); i += 12; + Normal.FromBytes(bytes, i); i += 12; + Binormal.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + UVCoord.ToBytes(bytes, i); i += 12; + STCoord.ToBytes(bytes, i); i += 12; + Utils.IntToBytes(FaceIndex, bytes, i); i += 4; + Position.ToBytes(bytes, i); i += 12; + Normal.ToBytes(bytes, i); i += 12; + Binormal.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += ObjectData.Length; + for (int j = 0; j < SurfaceInfo.Length; j++) + length += SurfaceInfo[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + public SurfaceInfoBlock[] SurfaceInfo; + + public ObjectDeGrabPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectDeGrab; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 119; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + SurfaceInfo = null; + } + + public ObjectDeGrabPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SurfaceInfo == null || SurfaceInfo.Length != -1) { + SurfaceInfo = new SurfaceInfoBlock[count]; + for(int j = 0; j < count; j++) + { SurfaceInfo[j] = new SurfaceInfoBlock(); } + } + for (int j = 0; j < count; j++) + { SurfaceInfo[j].FromBytes(bytes, ref i); } + } + + public ObjectDeGrabPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SurfaceInfo == null || SurfaceInfo.Length != count) { + SurfaceInfo = new SurfaceInfoBlock[count]; + for(int j = 0; j < count; j++) + { SurfaceInfo[j] = new SurfaceInfoBlock(); } + } + for (int j = 0; j < count; j++) + { SurfaceInfo[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + length++; + for (int j = 0; j < SurfaceInfo.Length; j++) { length += SurfaceInfo[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + bytes[i++] = (byte)SurfaceInfo.Length; + for (int j = 0; j < SurfaceInfo.Length; j++) { SurfaceInfo[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += ObjectData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + ObjectData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int SurfaceInfoStart = 0; + do + { + int variableLength = 0; + int SurfaceInfoCount = 0; + + i = SurfaceInfoStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < SurfaceInfo.Length) { + int blockLength = SurfaceInfo[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++SurfaceInfoCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)SurfaceInfoCount; + for (i = SurfaceInfoStart; i < SurfaceInfoStart + SurfaceInfoCount; i++) { SurfaceInfo[i].ToBytes(packet, ref length); } + SurfaceInfoStart += SurfaceInfoCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + SurfaceInfoStart < SurfaceInfo.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectSpinStartPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + + public ObjectSpinStartPacket() + { + HasVariableBlocks = false; + Type = PacketType.ObjectSpinStart; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 120; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + } + + public ObjectSpinStartPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public ObjectSpinStartPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectSpinUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + public Quaternion Rotation; + + public override int Length + { + get + { + return 28; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + Rotation.FromBytes(bytes, i, true); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + Rotation.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + + public ObjectSpinUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.ObjectSpinUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 121; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + } + + public ObjectSpinUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public ObjectSpinUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectSpinStopPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + + public ObjectSpinStopPacket() + { + HasVariableBlocks = false; + Type = PacketType.ObjectSpinStop; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 122; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + } + + public ObjectSpinStopPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public ObjectSpinStopPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectExportSelectedPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID RequestID; + public short VolumeDetail; + + public override int Length + { + get + { + return 34; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + VolumeDetail = (short)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(VolumeDetail % 256); + bytes[i++] = (byte)((VolumeDetail >> 8) % 256); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectExportSelectedPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectExportSelected; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 123; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectExportSelectedPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectExportSelectedPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ModifyLandPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ModifyBlockBlock : PacketBlock + { + public byte Action; + public byte BrushSize; + public float Seconds; + public float Height; + + public override int Length + { + get + { + return 10; + } + } + + public ModifyBlockBlock() { } + public ModifyBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Action = (byte)bytes[i++]; + BrushSize = (byte)bytes[i++]; + Seconds = Utils.BytesToFloat(bytes, i); i += 4; + Height = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = Action; + bytes[i++] = BrushSize; + Utils.FloatToBytes(Seconds, bytes, i); i += 4; + Utils.FloatToBytes(Height, bytes, i); i += 4; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + public float West; + public float South; + public float East; + public float North; + + public override int Length + { + get + { + return 20; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + West = Utils.BytesToFloat(bytes, i); i += 4; + South = Utils.BytesToFloat(bytes, i); i += 4; + East = Utils.BytesToFloat(bytes, i); i += 4; + North = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + Utils.FloatToBytes(West, bytes, i); i += 4; + Utils.FloatToBytes(South, bytes, i); i += 4; + Utils.FloatToBytes(East, bytes, i); i += 4; + Utils.FloatToBytes(North, bytes, i); i += 4; + } + + } + + /// + public sealed class ModifyBlockExtendedBlock : PacketBlock + { + public float BrushSize; + + public override int Length + { + get + { + return 4; + } + } + + public ModifyBlockExtendedBlock() { } + public ModifyBlockExtendedBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + BrushSize = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.FloatToBytes(BrushSize, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + length += ModifyBlock.Length; + for (int j = 0; j < ParcelData.Length; j++) + length += ParcelData[j].Length; + for (int j = 0; j < ModifyBlockExtended.Length; j++) + length += ModifyBlockExtended[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ModifyBlockBlock ModifyBlock; + public ParcelDataBlock[] ParcelData; + public ModifyBlockExtendedBlock[] ModifyBlockExtended; + + public ModifyLandPacket() + { + HasVariableBlocks = true; + Type = PacketType.ModifyLand; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 124; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ModifyBlock = new ModifyBlockBlock(); + ParcelData = null; + ModifyBlockExtended = null; + } + + public ModifyLandPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ModifyBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParcelData == null || ParcelData.Length != -1) { + ParcelData = new ParcelDataBlock[count]; + for(int j = 0; j < count; j++) + { ParcelData[j] = new ParcelDataBlock(); } + } + for (int j = 0; j < count; j++) + { ParcelData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ModifyBlockExtended == null || ModifyBlockExtended.Length != -1) { + ModifyBlockExtended = new ModifyBlockExtendedBlock[count]; + for(int j = 0; j < count; j++) + { ModifyBlockExtended[j] = new ModifyBlockExtendedBlock(); } + } + for (int j = 0; j < count; j++) + { ModifyBlockExtended[j].FromBytes(bytes, ref i); } + } + + public ModifyLandPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ModifyBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParcelData == null || ParcelData.Length != count) { + ParcelData = new ParcelDataBlock[count]; + for(int j = 0; j < count; j++) + { ParcelData[j] = new ParcelDataBlock(); } + } + for (int j = 0; j < count; j++) + { ParcelData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ModifyBlockExtended == null || ModifyBlockExtended.Length != count) { + ModifyBlockExtended = new ModifyBlockExtendedBlock[count]; + for(int j = 0; j < count; j++) + { ModifyBlockExtended[j] = new ModifyBlockExtendedBlock(); } + } + for (int j = 0; j < count; j++) + { ModifyBlockExtended[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ModifyBlock.Length; + length++; + for (int j = 0; j < ParcelData.Length; j++) { length += ParcelData[j].Length; } + length++; + for (int j = 0; j < ModifyBlockExtended.Length; j++) { length += ModifyBlockExtended[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ModifyBlock.ToBytes(bytes, ref i); + bytes[i++] = (byte)ParcelData.Length; + for (int j = 0; j < ParcelData.Length; j++) { ParcelData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)ModifyBlockExtended.Length; + for (int j = 0; j < ModifyBlockExtended.Length; j++) { ModifyBlockExtended[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += ModifyBlock.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + ModifyBlock.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int ParcelDataStart = 0; + int ModifyBlockExtendedStart = 0; + do + { + int variableLength = 0; + int ParcelDataCount = 0; + int ModifyBlockExtendedCount = 0; + + i = ParcelDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ParcelData.Length) { + int blockLength = ParcelData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ParcelDataCount; + } + else { break; } + ++i; + } + + i = ModifyBlockExtendedStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ModifyBlockExtended.Length) { + int blockLength = ModifyBlockExtended[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ModifyBlockExtendedCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ParcelDataCount; + for (i = ParcelDataStart; i < ParcelDataStart + ParcelDataCount; i++) { ParcelData[i].ToBytes(packet, ref length); } + ParcelDataStart += ParcelDataCount; + + packet[length++] = (byte)ModifyBlockExtendedCount; + for (i = ModifyBlockExtendedStart; i < ModifyBlockExtendedStart + ModifyBlockExtendedCount; i++) { ModifyBlockExtended[i].ToBytes(packet, ref length); } + ModifyBlockExtendedStart += ModifyBlockExtendedCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ParcelDataStart < ParcelData.Length || + ModifyBlockExtendedStart < ModifyBlockExtended.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class VelocityInterpolateOnPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public VelocityInterpolateOnPacket() + { + HasVariableBlocks = false; + Type = PacketType.VelocityInterpolateOn; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 125; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public VelocityInterpolateOnPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public VelocityInterpolateOnPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class VelocityInterpolateOffPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public VelocityInterpolateOffPacket() + { + HasVariableBlocks = false; + Type = PacketType.VelocityInterpolateOff; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 126; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public VelocityInterpolateOffPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public VelocityInterpolateOffPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class StateSavePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlockBlock : PacketBlock + { + public byte[] Filename; + + public override int Length + { + get + { + int length = 1; + if (Filename != null) { length += Filename.Length; } + return length; + } + } + + public DataBlockBlock() { } + public DataBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Filename = new byte[length]; + Buffer.BlockCopy(bytes, i, Filename, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Filename.Length; + Buffer.BlockCopy(Filename, 0, bytes, i, Filename.Length); i += Filename.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += DataBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlockBlock DataBlock; + + public StateSavePacket() + { + HasVariableBlocks = false; + Type = PacketType.StateSave; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 127; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + DataBlock = new DataBlockBlock(); + } + + public StateSavePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + DataBlock.FromBytes(bytes, ref i); + } + + public StateSavePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + DataBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += DataBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + DataBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ReportAutosaveCrashPacket : Packet + { + /// + public sealed class AutosaveDataBlock : PacketBlock + { + public int PID; + public int Status; + + public override int Length + { + get + { + return 8; + } + } + + public AutosaveDataBlock() { } + public AutosaveDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Status = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(PID, bytes, i); i += 4; + Utils.IntToBytes(Status, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AutosaveData.Length; + return length; + } + } + public AutosaveDataBlock AutosaveData; + + public ReportAutosaveCrashPacket() + { + HasVariableBlocks = false; + Type = PacketType.ReportAutosaveCrash; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 128; + Header.Reliable = true; + AutosaveData = new AutosaveDataBlock(); + } + + public ReportAutosaveCrashPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AutosaveData.FromBytes(bytes, ref i); + } + + public ReportAutosaveCrashPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AutosaveData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AutosaveData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AutosaveData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SimWideDeletesPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlockBlock : PacketBlock + { + public UUID TargetID; + public uint Flags; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlockBlock() { } + public DataBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TargetID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TargetID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += DataBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlockBlock DataBlock; + + public SimWideDeletesPacket() + { + HasVariableBlocks = false; + Type = PacketType.SimWideDeletes; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 129; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + DataBlock = new DataBlockBlock(); + } + + public SimWideDeletesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + DataBlock.FromBytes(bytes, ref i); + } + + public SimWideDeletesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + DataBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += DataBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + DataBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TrackAgentPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TargetDataBlock : PacketBlock + { + public UUID PreyID; + + public override int Length + { + get + { + return 16; + } + } + + public TargetDataBlock() { } + public TargetDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PreyID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + PreyID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += TargetData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public TargetDataBlock TargetData; + + public TrackAgentPacket() + { + HasVariableBlocks = false; + Type = PacketType.TrackAgent; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 130; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + TargetData = new TargetDataBlock(); + } + + public TrackAgentPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TargetData.FromBytes(bytes, ref i); + } + + public TrackAgentPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TargetData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TargetData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TargetData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ViewerStatsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint IP; + public uint StartTime; + public float RunTime; + public float SimFPS; + public float FPS; + public byte AgentsInView; + public float Ping; + public double MetersTraveled; + public int RegionsVisited; + public uint SysRAM; + public byte[] SysOS; + public byte[] SysCPU; + public byte[] SysGPU; + + public override int Length + { + get + { + int length = 76; + if (SysOS != null) { length += SysOS.Length; } + if (SysCPU != null) { length += SysCPU.Length; } + if (SysGPU != null) { length += SysGPU.Length; } + return length; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + IP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + StartTime = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RunTime = Utils.BytesToFloat(bytes, i); i += 4; + SimFPS = Utils.BytesToFloat(bytes, i); i += 4; + FPS = Utils.BytesToFloat(bytes, i); i += 4; + AgentsInView = (byte)bytes[i++]; + Ping = Utils.BytesToFloat(bytes, i); i += 4; + MetersTraveled = Utils.BytesToDouble(bytes, i); i += 8; + RegionsVisited = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SysRAM = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + SysOS = new byte[length]; + Buffer.BlockCopy(bytes, i, SysOS, 0, length); i += length; + length = bytes[i++]; + SysCPU = new byte[length]; + Buffer.BlockCopy(bytes, i, SysCPU, 0, length); i += length; + length = bytes[i++]; + SysGPU = new byte[length]; + Buffer.BlockCopy(bytes, i, SysGPU, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(IP, bytes, i); i += 4; + Utils.UIntToBytes(StartTime, bytes, i); i += 4; + Utils.FloatToBytes(RunTime, bytes, i); i += 4; + Utils.FloatToBytes(SimFPS, bytes, i); i += 4; + Utils.FloatToBytes(FPS, bytes, i); i += 4; + bytes[i++] = AgentsInView; + Utils.FloatToBytes(Ping, bytes, i); i += 4; + Utils.DoubleToBytes(MetersTraveled, bytes, i); i += 8; + Utils.IntToBytes(RegionsVisited, bytes, i); i += 4; + Utils.UIntToBytes(SysRAM, bytes, i); i += 4; + bytes[i++] = (byte)SysOS.Length; + Buffer.BlockCopy(SysOS, 0, bytes, i, SysOS.Length); i += SysOS.Length; + bytes[i++] = (byte)SysCPU.Length; + Buffer.BlockCopy(SysCPU, 0, bytes, i, SysCPU.Length); i += SysCPU.Length; + bytes[i++] = (byte)SysGPU.Length; + Buffer.BlockCopy(SysGPU, 0, bytes, i, SysGPU.Length); i += SysGPU.Length; + } + + } + + /// + public sealed class DownloadTotalsBlock : PacketBlock + { + public uint World; + public uint Objects; + public uint Textures; + + public override int Length + { + get + { + return 12; + } + } + + public DownloadTotalsBlock() { } + public DownloadTotalsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + World = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Objects = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Textures = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(World, bytes, i); i += 4; + Utils.UIntToBytes(Objects, bytes, i); i += 4; + Utils.UIntToBytes(Textures, bytes, i); i += 4; + } + + } + + /// + public sealed class NetStatsBlock : PacketBlock + { + public uint Bytes; + public uint Packets; + public uint Compressed; + public uint Savings; + + public override int Length + { + get + { + return 16; + } + } + + public NetStatsBlock() { } + public NetStatsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Bytes = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Packets = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Compressed = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Savings = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Bytes, bytes, i); i += 4; + Utils.UIntToBytes(Packets, bytes, i); i += 4; + Utils.UIntToBytes(Compressed, bytes, i); i += 4; + Utils.UIntToBytes(Savings, bytes, i); i += 4; + } + + } + + /// + public sealed class FailStatsBlock : PacketBlock + { + public uint SendPacket; + public uint Dropped; + public uint Resent; + public uint FailedResends; + public uint OffCircuit; + public uint Invalid; + + public override int Length + { + get + { + return 24; + } + } + + public FailStatsBlock() { } + public FailStatsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SendPacket = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Dropped = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Resent = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + FailedResends = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OffCircuit = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Invalid = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(SendPacket, bytes, i); i += 4; + Utils.UIntToBytes(Dropped, bytes, i); i += 4; + Utils.UIntToBytes(Resent, bytes, i); i += 4; + Utils.UIntToBytes(FailedResends, bytes, i); i += 4; + Utils.UIntToBytes(OffCircuit, bytes, i); i += 4; + Utils.UIntToBytes(Invalid, bytes, i); i += 4; + } + + } + + /// + public sealed class MiscStatsBlock : PacketBlock + { + public uint Type; + public double Value; + + public override int Length + { + get + { + return 12; + } + } + + public MiscStatsBlock() { } + public MiscStatsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Type = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Value = Utils.BytesToDouble(bytes, i); i += 8; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Type, bytes, i); i += 4; + Utils.DoubleToBytes(Value, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += DownloadTotals.Length; + for (int j = 0; j < 2; j++) + length += NetStats[j].Length; + length += FailStats.Length; + for (int j = 0; j < MiscStats.Length; j++) + length += MiscStats[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DownloadTotalsBlock DownloadTotals; + public NetStatsBlock[] NetStats; + public FailStatsBlock FailStats; + public MiscStatsBlock[] MiscStats; + + public ViewerStatsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ViewerStats; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 131; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + DownloadTotals = new DownloadTotalsBlock(); + NetStats = new NetStatsBlock[2]; + FailStats = new FailStatsBlock(); + MiscStats = null; + } + + public ViewerStatsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + DownloadTotals.FromBytes(bytes, ref i); + if(NetStats == null || NetStats.Length != 2) { + NetStats = new NetStatsBlock[2]; + for(int j = 0; j < 2; j++) + { NetStats[j] = new NetStatsBlock(); } + } + for (int j = 0; j < 2; j++) + { NetStats[j].FromBytes(bytes, ref i); } + FailStats.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(MiscStats == null || MiscStats.Length != -1) { + MiscStats = new MiscStatsBlock[count]; + for(int j = 0; j < count; j++) + { MiscStats[j] = new MiscStatsBlock(); } + } + for (int j = 0; j < count; j++) + { MiscStats[j].FromBytes(bytes, ref i); } + } + + public ViewerStatsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + DownloadTotals.FromBytes(bytes, ref i); + if(NetStats == null || NetStats.Length != 2) { + NetStats = new NetStatsBlock[2]; + for(int j = 0; j < 2; j++) + { NetStats[j] = new NetStatsBlock(); } + } + for (int j = 0; j < 2; j++) + { NetStats[j].FromBytes(bytes, ref i); } + FailStats.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(MiscStats == null || MiscStats.Length != count) { + MiscStats = new MiscStatsBlock[count]; + for(int j = 0; j < count; j++) + { MiscStats[j] = new MiscStatsBlock(); } + } + for (int j = 0; j < count; j++) + { MiscStats[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += DownloadTotals.Length; + length += FailStats.Length; + for (int j = 0; j < 2; j++) { length += NetStats[j].Length; } + length++; + for (int j = 0; j < MiscStats.Length; j++) { length += MiscStats[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + DownloadTotals.ToBytes(bytes, ref i); + for (int j = 0; j < 2; j++) { NetStats[j].ToBytes(bytes, ref i); } + FailStats.ToBytes(bytes, ref i); + bytes[i++] = (byte)MiscStats.Length; + for (int j = 0; j < MiscStats.Length; j++) { MiscStats[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += DownloadTotals.Length; + for (int j = 0; j < 2; j++) { fixedLength += NetStats[j].Length; } + fixedLength += FailStats.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + DownloadTotals.ToBytes(fixedBytes, ref i); + for (int j = 0; j < 2; j++) { NetStats[j].ToBytes(fixedBytes, ref i); } + FailStats.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int MiscStatsStart = 0; + do + { + int variableLength = 0; + int MiscStatsCount = 0; + + i = MiscStatsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < MiscStats.Length) { + int blockLength = MiscStats[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++MiscStatsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)MiscStatsCount; + for (i = MiscStatsStart; i < MiscStatsStart + MiscStatsCount; i++) { MiscStats[i].ToBytes(packet, ref length); } + MiscStatsStart += MiscStatsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + MiscStatsStart < MiscStats.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ScriptAnswerYesPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID TaskID; + public UUID ItemID; + public int Questions; + + public override int Length + { + get + { + return 36; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TaskID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + Questions = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TaskID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Questions, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ScriptAnswerYesPacket() + { + HasVariableBlocks = false; + Type = PacketType.ScriptAnswerYes; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 132; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ScriptAnswerYesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ScriptAnswerYesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UserReportPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ReportDataBlock : PacketBlock + { + public byte ReportType; + public byte Category; + public Vector3 Position; + public byte CheckFlags; + public UUID ScreenshotID; + public UUID ObjectID; + public UUID AbuserID; + public byte[] AbuseRegionName; + public UUID AbuseRegionID; + public byte[] Summary; + public byte[] Details; + public byte[] VersionString; + + public override int Length + { + get + { + int length = 84; + if (AbuseRegionName != null) { length += AbuseRegionName.Length; } + if (Summary != null) { length += Summary.Length; } + if (Details != null) { length += Details.Length; } + if (VersionString != null) { length += VersionString.Length; } + return length; + } + } + + public ReportDataBlock() { } + public ReportDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ReportType = (byte)bytes[i++]; + Category = (byte)bytes[i++]; + Position.FromBytes(bytes, i); i += 12; + CheckFlags = (byte)bytes[i++]; + ScreenshotID.FromBytes(bytes, i); i += 16; + ObjectID.FromBytes(bytes, i); i += 16; + AbuserID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + AbuseRegionName = new byte[length]; + Buffer.BlockCopy(bytes, i, AbuseRegionName, 0, length); i += length; + AbuseRegionID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Summary = new byte[length]; + Buffer.BlockCopy(bytes, i, Summary, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Details = new byte[length]; + Buffer.BlockCopy(bytes, i, Details, 0, length); i += length; + length = bytes[i++]; + VersionString = new byte[length]; + Buffer.BlockCopy(bytes, i, VersionString, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = ReportType; + bytes[i++] = Category; + Position.ToBytes(bytes, i); i += 12; + bytes[i++] = CheckFlags; + ScreenshotID.ToBytes(bytes, i); i += 16; + ObjectID.ToBytes(bytes, i); i += 16; + AbuserID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)AbuseRegionName.Length; + Buffer.BlockCopy(AbuseRegionName, 0, bytes, i, AbuseRegionName.Length); i += AbuseRegionName.Length; + AbuseRegionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Summary.Length; + Buffer.BlockCopy(Summary, 0, bytes, i, Summary.Length); i += Summary.Length; + bytes[i++] = (byte)(Details.Length % 256); + bytes[i++] = (byte)((Details.Length >> 8) % 256); + Buffer.BlockCopy(Details, 0, bytes, i, Details.Length); i += Details.Length; + bytes[i++] = (byte)VersionString.Length; + Buffer.BlockCopy(VersionString, 0, bytes, i, VersionString.Length); i += VersionString.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ReportData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ReportDataBlock ReportData; + + public UserReportPacket() + { + HasVariableBlocks = false; + Type = PacketType.UserReport; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 133; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ReportData = new ReportDataBlock(); + } + + public UserReportPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ReportData.FromBytes(bytes, ref i); + } + + public UserReportPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ReportData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ReportData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ReportData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AlertMessagePacket : Packet + { + /// + public sealed class AlertDataBlock : PacketBlock + { + public byte[] Message; + + public override int Length + { + get + { + int length = 1; + if (Message != null) { length += Message.Length; } + return length; + } + } + + public AlertDataBlock() { } + public AlertDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + } + + } + + /// + public sealed class AlertInfoBlock : PacketBlock + { + public byte[] Message; + public byte[] ExtraParams; + + public override int Length + { + get + { + int length = 2; + if (Message != null) { length += Message.Length; } + if (ExtraParams != null) { length += ExtraParams.Length; } + return length; + } + } + + public AlertInfoBlock() { } + public AlertInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + length = bytes[i++]; + ExtraParams = new byte[length]; + Buffer.BlockCopy(bytes, i, ExtraParams, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + bytes[i++] = (byte)ExtraParams.Length; + Buffer.BlockCopy(ExtraParams, 0, bytes, i, ExtraParams.Length); i += ExtraParams.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AlertData.Length; + for (int j = 0; j < AlertInfo.Length; j++) + length += AlertInfo[j].Length; + return length; + } + } + public AlertDataBlock AlertData; + public AlertInfoBlock[] AlertInfo; + + public AlertMessagePacket() + { + HasVariableBlocks = true; + Type = PacketType.AlertMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 134; + Header.Reliable = true; + AlertData = new AlertDataBlock(); + AlertInfo = null; + } + + public AlertMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AlertData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AlertInfo == null || AlertInfo.Length != -1) { + AlertInfo = new AlertInfoBlock[count]; + for(int j = 0; j < count; j++) + { AlertInfo[j] = new AlertInfoBlock(); } + } + for (int j = 0; j < count; j++) + { AlertInfo[j].FromBytes(bytes, ref i); } + } + + public AlertMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AlertData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AlertInfo == null || AlertInfo.Length != count) { + AlertInfo = new AlertInfoBlock[count]; + for(int j = 0; j < count; j++) + { AlertInfo[j] = new AlertInfoBlock(); } + } + for (int j = 0; j < count; j++) + { AlertInfo[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AlertData.Length; + length++; + for (int j = 0; j < AlertInfo.Length; j++) { length += AlertInfo[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AlertData.ToBytes(bytes, ref i); + bytes[i++] = (byte)AlertInfo.Length; + for (int j = 0; j < AlertInfo.Length; j++) { AlertInfo[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AlertData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AlertData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int AlertInfoStart = 0; + do + { + int variableLength = 0; + int AlertInfoCount = 0; + + i = AlertInfoStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AlertInfo.Length) { + int blockLength = AlertInfo[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AlertInfoCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)AlertInfoCount; + for (i = AlertInfoStart; i < AlertInfoStart + AlertInfoCount; i++) { AlertInfo[i].ToBytes(packet, ref length); } + AlertInfoStart += AlertInfoCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + AlertInfoStart < AlertInfo.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentAlertMessagePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class AlertDataBlock : PacketBlock + { + public bool Modal; + public byte[] Message; + + public override int Length + { + get + { + int length = 2; + if (Message != null) { length += Message.Length; } + return length; + } + } + + public AlertDataBlock() { } + public AlertDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + Modal = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((Modal) ? 1 : 0); + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += AlertData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public AlertDataBlock AlertData; + + public AgentAlertMessagePacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentAlertMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 135; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + AlertData = new AlertDataBlock(); + } + + public AgentAlertMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + AlertData.FromBytes(bytes, ref i); + } + + public AgentAlertMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + AlertData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += AlertData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + AlertData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MeanCollisionAlertPacket : Packet + { + /// + public sealed class MeanCollisionBlock : PacketBlock + { + public UUID Victim; + public UUID Perp; + public uint Time; + public float Mag; + public byte Type; + + public override int Length + { + get + { + return 41; + } + } + + public MeanCollisionBlock() { } + public MeanCollisionBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Victim.FromBytes(bytes, i); i += 16; + Perp.FromBytes(bytes, i); i += 16; + Time = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Mag = Utils.BytesToFloat(bytes, i); i += 4; + Type = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Victim.ToBytes(bytes, i); i += 16; + Perp.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Time, bytes, i); i += 4; + Utils.FloatToBytes(Mag, bytes, i); i += 4; + bytes[i++] = Type; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < MeanCollision.Length; j++) + length += MeanCollision[j].Length; + return length; + } + } + public MeanCollisionBlock[] MeanCollision; + + public MeanCollisionAlertPacket() + { + HasVariableBlocks = true; + Type = PacketType.MeanCollisionAlert; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 136; + Header.Reliable = true; + Header.Zerocoded = true; + MeanCollision = null; + } + + public MeanCollisionAlertPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(MeanCollision == null || MeanCollision.Length != -1) { + MeanCollision = new MeanCollisionBlock[count]; + for(int j = 0; j < count; j++) + { MeanCollision[j] = new MeanCollisionBlock(); } + } + for (int j = 0; j < count; j++) + { MeanCollision[j].FromBytes(bytes, ref i); } + } + + public MeanCollisionAlertPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(MeanCollision == null || MeanCollision.Length != count) { + MeanCollision = new MeanCollisionBlock[count]; + for(int j = 0; j < count; j++) + { MeanCollision[j] = new MeanCollisionBlock(); } + } + for (int j = 0; j < count; j++) + { MeanCollision[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < MeanCollision.Length; j++) { length += MeanCollision[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)MeanCollision.Length; + for (int j = 0; j < MeanCollision.Length; j++) { MeanCollision[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int MeanCollisionStart = 0; + do + { + int variableLength = 0; + int MeanCollisionCount = 0; + + i = MeanCollisionStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < MeanCollision.Length) { + int blockLength = MeanCollision[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++MeanCollisionCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)MeanCollisionCount; + for (i = MeanCollisionStart; i < MeanCollisionStart + MeanCollisionCount; i++) { MeanCollision[i].ToBytes(packet, ref length); } + MeanCollisionStart += MeanCollisionCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + MeanCollisionStart < MeanCollision.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ViewerFrozenMessagePacket : Packet + { + /// + public sealed class FrozenDataBlock : PacketBlock + { + public bool Data; + + public override int Length + { + get + { + return 1; + } + } + + public FrozenDataBlock() { } + public FrozenDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Data = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((Data) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += FrozenData.Length; + return length; + } + } + public FrozenDataBlock FrozenData; + + public ViewerFrozenMessagePacket() + { + HasVariableBlocks = false; + Type = PacketType.ViewerFrozenMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 137; + Header.Reliable = true; + FrozenData = new FrozenDataBlock(); + } + + public ViewerFrozenMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + FrozenData.FromBytes(bytes, ref i); + } + + public ViewerFrozenMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + FrozenData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += FrozenData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + FrozenData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class HealthMessagePacket : Packet + { + /// + public sealed class HealthDataBlock : PacketBlock + { + public float Health; + + public override int Length + { + get + { + return 4; + } + } + + public HealthDataBlock() { } + public HealthDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Health = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.FloatToBytes(Health, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += HealthData.Length; + return length; + } + } + public HealthDataBlock HealthData; + + public HealthMessagePacket() + { + HasVariableBlocks = false; + Type = PacketType.HealthMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 138; + Header.Reliable = true; + Header.Zerocoded = true; + HealthData = new HealthDataBlock(); + } + + public HealthMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + HealthData.FromBytes(bytes, ref i); + } + + public HealthMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + HealthData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += HealthData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + HealthData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ChatFromSimulatorPacket : Packet + { + /// + public sealed class ChatDataBlock : PacketBlock + { + public byte[] FromName; + public UUID SourceID; + public UUID OwnerID; + public byte SourceType; + public byte ChatType; + public byte Audible; + public Vector3 Position; + public byte[] Message; + + public override int Length + { + get + { + int length = 50; + if (FromName != null) { length += FromName.Length; } + if (Message != null) { length += Message.Length; } + return length; + } + } + + public ChatDataBlock() { } + public ChatDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + FromName = new byte[length]; + Buffer.BlockCopy(bytes, i, FromName, 0, length); i += length; + SourceID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + SourceType = (byte)bytes[i++]; + ChatType = (byte)bytes[i++]; + Audible = (byte)bytes[i++]; + Position.FromBytes(bytes, i); i += 12; + length = (bytes[i++] + (bytes[i++] << 8)); + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)FromName.Length; + Buffer.BlockCopy(FromName, 0, bytes, i, FromName.Length); i += FromName.Length; + SourceID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = SourceType; + bytes[i++] = ChatType; + bytes[i++] = Audible; + Position.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)(Message.Length % 256); + bytes[i++] = (byte)((Message.Length >> 8) % 256); + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ChatData.Length; + return length; + } + } + public ChatDataBlock ChatData; + + public ChatFromSimulatorPacket() + { + HasVariableBlocks = false; + Type = PacketType.ChatFromSimulator; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 139; + Header.Reliable = true; + ChatData = new ChatDataBlock(); + } + + public ChatFromSimulatorPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ChatData.FromBytes(bytes, ref i); + } + + public ChatFromSimulatorPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ChatData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ChatData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ChatData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SimStatsPacket : Packet + { + /// + public sealed class RegionBlock : PacketBlock + { + public uint RegionX; + public uint RegionY; + public uint RegionFlags; + public uint ObjectCapacity; + + public override int Length + { + get + { + return 16; + } + } + + public RegionBlock() { } + public RegionBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionX = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RegionY = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RegionFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ObjectCapacity = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(RegionX, bytes, i); i += 4; + Utils.UIntToBytes(RegionY, bytes, i); i += 4; + Utils.UIntToBytes(RegionFlags, bytes, i); i += 4; + Utils.UIntToBytes(ObjectCapacity, bytes, i); i += 4; + } + + } + + /// + public sealed class StatBlock : PacketBlock + { + public uint StatID; + public float StatValue; + + public override int Length + { + get + { + return 8; + } + } + + public StatBlock() { } + public StatBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + StatID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + StatValue = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(StatID, bytes, i); i += 4; + Utils.FloatToBytes(StatValue, bytes, i); i += 4; + } + + } + + /// + public sealed class PidStatBlock : PacketBlock + { + public int PID; + + public override int Length + { + get + { + return 4; + } + } + + public PidStatBlock() { } + public PidStatBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(PID, bytes, i); i += 4; + } + + } + + /// + public sealed class RegionInfoBlock : PacketBlock + { + public ulong RegionFlagsExtended; + + public override int Length + { + get + { + return 8; + } + } + + public RegionInfoBlock() { } + public RegionInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionFlagsExtended = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionFlagsExtended, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 12; + length += Region.Length; + for (int j = 0; j < Stat.Length; j++) + length += Stat[j].Length; + length += PidStat.Length; + for (int j = 0; j < RegionInfo.Length; j++) + length += RegionInfo[j].Length; + return length; + } + } + public RegionBlock Region; + public StatBlock[] Stat; + public PidStatBlock PidStat; + public RegionInfoBlock[] RegionInfo; + + public SimStatsPacket() + { + HasVariableBlocks = true; + Type = PacketType.SimStats; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 140; + Header.Reliable = true; + Region = new RegionBlock(); + Stat = null; + PidStat = new PidStatBlock(); + RegionInfo = null; + } + + public SimStatsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Region.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Stat == null || Stat.Length != -1) { + Stat = new StatBlock[count]; + for(int j = 0; j < count; j++) + { Stat[j] = new StatBlock(); } + } + for (int j = 0; j < count; j++) + { Stat[j].FromBytes(bytes, ref i); } + PidStat.FromBytes(bytes, ref i); + count = (int)bytes[i++]; + if(RegionInfo == null || RegionInfo.Length != -1) { + RegionInfo = new RegionInfoBlock[count]; + for(int j = 0; j < count; j++) + { RegionInfo[j] = new RegionInfoBlock(); } + } + for (int j = 0; j < count; j++) + { RegionInfo[j].FromBytes(bytes, ref i); } + } + + public SimStatsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Region.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Stat == null || Stat.Length != count) { + Stat = new StatBlock[count]; + for(int j = 0; j < count; j++) + { Stat[j] = new StatBlock(); } + } + for (int j = 0; j < count; j++) + { Stat[j].FromBytes(bytes, ref i); } + PidStat.FromBytes(bytes, ref i); + count = (int)bytes[i++]; + if(RegionInfo == null || RegionInfo.Length != count) { + RegionInfo = new RegionInfoBlock[count]; + for(int j = 0; j < count; j++) + { RegionInfo[j] = new RegionInfoBlock(); } + } + for (int j = 0; j < count; j++) + { RegionInfo[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += Region.Length; + length += PidStat.Length; + length++; + for (int j = 0; j < Stat.Length; j++) { length += Stat[j].Length; } + length++; + for (int j = 0; j < RegionInfo.Length; j++) { length += RegionInfo[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Region.ToBytes(bytes, ref i); + bytes[i++] = (byte)Stat.Length; + for (int j = 0; j < Stat.Length; j++) { Stat[j].ToBytes(bytes, ref i); } + PidStat.ToBytes(bytes, ref i); + bytes[i++] = (byte)RegionInfo.Length; + for (int j = 0; j < RegionInfo.Length; j++) { RegionInfo[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RequestRegionInfoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public RequestRegionInfoPacket() + { + HasVariableBlocks = false; + Type = PacketType.RequestRegionInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 141; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public RequestRegionInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public RequestRegionInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RegionInfoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RegionInfoBlock : PacketBlock + { + public byte[] SimName; + public uint EstateID; + public uint ParentEstateID; + public uint RegionFlags; + public byte SimAccess; + public byte MaxAgents; + public float BillableFactor; + public float ObjectBonusFactor; + public float WaterHeight; + public float TerrainRaiseLimit; + public float TerrainLowerLimit; + public int PricePerMeter; + public int RedirectGridX; + public int RedirectGridY; + public bool UseEstateSun; + public float SunHour; + + public override int Length + { + get + { + int length = 52; + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public RegionInfoBlock() { } + public RegionInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + EstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParentEstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RegionFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SimAccess = (byte)bytes[i++]; + MaxAgents = (byte)bytes[i++]; + BillableFactor = Utils.BytesToFloat(bytes, i); i += 4; + ObjectBonusFactor = Utils.BytesToFloat(bytes, i); i += 4; + WaterHeight = Utils.BytesToFloat(bytes, i); i += 4; + TerrainRaiseLimit = Utils.BytesToFloat(bytes, i); i += 4; + TerrainLowerLimit = Utils.BytesToFloat(bytes, i); i += 4; + PricePerMeter = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RedirectGridX = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RedirectGridY = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + UseEstateSun = (bytes[i++] != 0) ? (bool)true : (bool)false; + SunHour = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + Utils.UIntToBytes(EstateID, bytes, i); i += 4; + Utils.UIntToBytes(ParentEstateID, bytes, i); i += 4; + Utils.UIntToBytes(RegionFlags, bytes, i); i += 4; + bytes[i++] = SimAccess; + bytes[i++] = MaxAgents; + Utils.FloatToBytes(BillableFactor, bytes, i); i += 4; + Utils.FloatToBytes(ObjectBonusFactor, bytes, i); i += 4; + Utils.FloatToBytes(WaterHeight, bytes, i); i += 4; + Utils.FloatToBytes(TerrainRaiseLimit, bytes, i); i += 4; + Utils.FloatToBytes(TerrainLowerLimit, bytes, i); i += 4; + Utils.IntToBytes(PricePerMeter, bytes, i); i += 4; + Utils.IntToBytes(RedirectGridX, bytes, i); i += 4; + Utils.IntToBytes(RedirectGridY, bytes, i); i += 4; + bytes[i++] = (byte)((UseEstateSun) ? 1 : 0); + Utils.FloatToBytes(SunHour, bytes, i); i += 4; + } + + } + + /// + public sealed class RegionInfo2Block : PacketBlock + { + public byte[] ProductSKU; + public byte[] ProductName; + public uint MaxAgents32; + public uint HardMaxAgents; + public uint HardMaxObjects; + + public override int Length + { + get + { + int length = 14; + if (ProductSKU != null) { length += ProductSKU.Length; } + if (ProductName != null) { length += ProductName.Length; } + return length; + } + } + + public RegionInfo2Block() { } + public RegionInfo2Block(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + ProductSKU = new byte[length]; + Buffer.BlockCopy(bytes, i, ProductSKU, 0, length); i += length; + length = bytes[i++]; + ProductName = new byte[length]; + Buffer.BlockCopy(bytes, i, ProductName, 0, length); i += length; + MaxAgents32 = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + HardMaxAgents = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + HardMaxObjects = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)ProductSKU.Length; + Buffer.BlockCopy(ProductSKU, 0, bytes, i, ProductSKU.Length); i += ProductSKU.Length; + bytes[i++] = (byte)ProductName.Length; + Buffer.BlockCopy(ProductName, 0, bytes, i, ProductName.Length); i += ProductName.Length; + Utils.UIntToBytes(MaxAgents32, bytes, i); i += 4; + Utils.UIntToBytes(HardMaxAgents, bytes, i); i += 4; + Utils.UIntToBytes(HardMaxObjects, bytes, i); i += 4; + } + + } + + /// + public sealed class RegionInfo3Block : PacketBlock + { + public ulong RegionFlagsExtended; + + public override int Length + { + get + { + return 8; + } + } + + public RegionInfo3Block() { } + public RegionInfo3Block(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionFlagsExtended = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionFlagsExtended, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += RegionInfo.Length; + length += RegionInfo2.Length; + for (int j = 0; j < RegionInfo3.Length; j++) + length += RegionInfo3[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RegionInfoBlock RegionInfo; + public RegionInfo2Block RegionInfo2; + public RegionInfo3Block[] RegionInfo3; + + public RegionInfoPacket() + { + HasVariableBlocks = true; + Type = PacketType.RegionInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 142; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + RegionInfo = new RegionInfoBlock(); + RegionInfo2 = new RegionInfo2Block(); + RegionInfo3 = null; + } + + public RegionInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RegionInfo.FromBytes(bytes, ref i); + RegionInfo2.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RegionInfo3 == null || RegionInfo3.Length != -1) { + RegionInfo3 = new RegionInfo3Block[count]; + for(int j = 0; j < count; j++) + { RegionInfo3[j] = new RegionInfo3Block(); } + } + for (int j = 0; j < count; j++) + { RegionInfo3[j].FromBytes(bytes, ref i); } + } + + public RegionInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RegionInfo.FromBytes(bytes, ref i); + RegionInfo2.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RegionInfo3 == null || RegionInfo3.Length != count) { + RegionInfo3 = new RegionInfo3Block[count]; + for(int j = 0; j < count; j++) + { RegionInfo3[j] = new RegionInfo3Block(); } + } + for (int j = 0; j < count; j++) + { RegionInfo3[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RegionInfo.Length; + length += RegionInfo2.Length; + length++; + for (int j = 0; j < RegionInfo3.Length; j++) { length += RegionInfo3[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RegionInfo.ToBytes(bytes, ref i); + RegionInfo2.ToBytes(bytes, ref i); + bytes[i++] = (byte)RegionInfo3.Length; + for (int j = 0; j < RegionInfo3.Length; j++) { RegionInfo3[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += RegionInfo.Length; + fixedLength += RegionInfo2.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + RegionInfo.ToBytes(fixedBytes, ref i); + RegionInfo2.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RegionInfo3Start = 0; + do + { + int variableLength = 0; + int RegionInfo3Count = 0; + + i = RegionInfo3Start; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < RegionInfo3.Length) { + int blockLength = RegionInfo3[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RegionInfo3Count; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RegionInfo3Count; + for (i = RegionInfo3Start; i < RegionInfo3Start + RegionInfo3Count; i++) { RegionInfo3[i].ToBytes(packet, ref length); } + RegionInfo3Start += RegionInfo3Count; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RegionInfo3Start < RegionInfo3.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GodUpdateRegionInfoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RegionInfoBlock : PacketBlock + { + public byte[] SimName; + public uint EstateID; + public uint ParentEstateID; + public uint RegionFlags; + public float BillableFactor; + public int PricePerMeter; + public int RedirectGridX; + public int RedirectGridY; + + public override int Length + { + get + { + int length = 29; + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public RegionInfoBlock() { } + public RegionInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + EstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParentEstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RegionFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + BillableFactor = Utils.BytesToFloat(bytes, i); i += 4; + PricePerMeter = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RedirectGridX = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RedirectGridY = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + Utils.UIntToBytes(EstateID, bytes, i); i += 4; + Utils.UIntToBytes(ParentEstateID, bytes, i); i += 4; + Utils.UIntToBytes(RegionFlags, bytes, i); i += 4; + Utils.FloatToBytes(BillableFactor, bytes, i); i += 4; + Utils.IntToBytes(PricePerMeter, bytes, i); i += 4; + Utils.IntToBytes(RedirectGridX, bytes, i); i += 4; + Utils.IntToBytes(RedirectGridY, bytes, i); i += 4; + } + + } + + /// + public sealed class RegionInfo2Block : PacketBlock + { + public ulong RegionFlagsExtended; + + public override int Length + { + get + { + return 8; + } + } + + public RegionInfo2Block() { } + public RegionInfo2Block(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionFlagsExtended = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionFlagsExtended, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += RegionInfo.Length; + for (int j = 0; j < RegionInfo2.Length; j++) + length += RegionInfo2[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RegionInfoBlock RegionInfo; + public RegionInfo2Block[] RegionInfo2; + + public GodUpdateRegionInfoPacket() + { + HasVariableBlocks = true; + Type = PacketType.GodUpdateRegionInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 143; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + RegionInfo = new RegionInfoBlock(); + RegionInfo2 = null; + } + + public GodUpdateRegionInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RegionInfo.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RegionInfo2 == null || RegionInfo2.Length != -1) { + RegionInfo2 = new RegionInfo2Block[count]; + for(int j = 0; j < count; j++) + { RegionInfo2[j] = new RegionInfo2Block(); } + } + for (int j = 0; j < count; j++) + { RegionInfo2[j].FromBytes(bytes, ref i); } + } + + public GodUpdateRegionInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RegionInfo.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RegionInfo2 == null || RegionInfo2.Length != count) { + RegionInfo2 = new RegionInfo2Block[count]; + for(int j = 0; j < count; j++) + { RegionInfo2[j] = new RegionInfo2Block(); } + } + for (int j = 0; j < count; j++) + { RegionInfo2[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RegionInfo.Length; + length++; + for (int j = 0; j < RegionInfo2.Length; j++) { length += RegionInfo2[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RegionInfo.ToBytes(bytes, ref i); + bytes[i++] = (byte)RegionInfo2.Length; + for (int j = 0; j < RegionInfo2.Length; j++) { RegionInfo2[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += RegionInfo.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + RegionInfo.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RegionInfo2Start = 0; + do + { + int variableLength = 0; + int RegionInfo2Count = 0; + + i = RegionInfo2Start; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < RegionInfo2.Length) { + int blockLength = RegionInfo2[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RegionInfo2Count; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RegionInfo2Count; + for (i = RegionInfo2Start; i < RegionInfo2Start + RegionInfo2Count; i++) { RegionInfo2[i].ToBytes(packet, ref length); } + RegionInfo2Start += RegionInfo2Count; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RegionInfo2Start < RegionInfo2.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RegionHandshakePacket : Packet + { + /// + public sealed class RegionInfoBlock : PacketBlock + { + public uint RegionFlags; + public byte SimAccess; + public byte[] SimName; + public UUID SimOwner; + public bool IsEstateManager; + public float WaterHeight; + public float BillableFactor; + public UUID CacheID; + public UUID TerrainBase0; + public UUID TerrainBase1; + public UUID TerrainBase2; + public UUID TerrainBase3; + public UUID TerrainDetail0; + public UUID TerrainDetail1; + public UUID TerrainDetail2; + public UUID TerrainDetail3; + public float TerrainStartHeight00; + public float TerrainStartHeight01; + public float TerrainStartHeight10; + public float TerrainStartHeight11; + public float TerrainHeightRange00; + public float TerrainHeightRange01; + public float TerrainHeightRange10; + public float TerrainHeightRange11; + + public override int Length + { + get + { + int length = 207; + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public RegionInfoBlock() { } + public RegionInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RegionFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SimAccess = (byte)bytes[i++]; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + SimOwner.FromBytes(bytes, i); i += 16; + IsEstateManager = (bytes[i++] != 0) ? (bool)true : (bool)false; + WaterHeight = Utils.BytesToFloat(bytes, i); i += 4; + BillableFactor = Utils.BytesToFloat(bytes, i); i += 4; + CacheID.FromBytes(bytes, i); i += 16; + TerrainBase0.FromBytes(bytes, i); i += 16; + TerrainBase1.FromBytes(bytes, i); i += 16; + TerrainBase2.FromBytes(bytes, i); i += 16; + TerrainBase3.FromBytes(bytes, i); i += 16; + TerrainDetail0.FromBytes(bytes, i); i += 16; + TerrainDetail1.FromBytes(bytes, i); i += 16; + TerrainDetail2.FromBytes(bytes, i); i += 16; + TerrainDetail3.FromBytes(bytes, i); i += 16; + TerrainStartHeight00 = Utils.BytesToFloat(bytes, i); i += 4; + TerrainStartHeight01 = Utils.BytesToFloat(bytes, i); i += 4; + TerrainStartHeight10 = Utils.BytesToFloat(bytes, i); i += 4; + TerrainStartHeight11 = Utils.BytesToFloat(bytes, i); i += 4; + TerrainHeightRange00 = Utils.BytesToFloat(bytes, i); i += 4; + TerrainHeightRange01 = Utils.BytesToFloat(bytes, i); i += 4; + TerrainHeightRange10 = Utils.BytesToFloat(bytes, i); i += 4; + TerrainHeightRange11 = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(RegionFlags, bytes, i); i += 4; + bytes[i++] = SimAccess; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + SimOwner.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsEstateManager) ? 1 : 0); + Utils.FloatToBytes(WaterHeight, bytes, i); i += 4; + Utils.FloatToBytes(BillableFactor, bytes, i); i += 4; + CacheID.ToBytes(bytes, i); i += 16; + TerrainBase0.ToBytes(bytes, i); i += 16; + TerrainBase1.ToBytes(bytes, i); i += 16; + TerrainBase2.ToBytes(bytes, i); i += 16; + TerrainBase3.ToBytes(bytes, i); i += 16; + TerrainDetail0.ToBytes(bytes, i); i += 16; + TerrainDetail1.ToBytes(bytes, i); i += 16; + TerrainDetail2.ToBytes(bytes, i); i += 16; + TerrainDetail3.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(TerrainStartHeight00, bytes, i); i += 4; + Utils.FloatToBytes(TerrainStartHeight01, bytes, i); i += 4; + Utils.FloatToBytes(TerrainStartHeight10, bytes, i); i += 4; + Utils.FloatToBytes(TerrainStartHeight11, bytes, i); i += 4; + Utils.FloatToBytes(TerrainHeightRange00, bytes, i); i += 4; + Utils.FloatToBytes(TerrainHeightRange01, bytes, i); i += 4; + Utils.FloatToBytes(TerrainHeightRange10, bytes, i); i += 4; + Utils.FloatToBytes(TerrainHeightRange11, bytes, i); i += 4; + } + + } + + /// + public sealed class RegionInfo2Block : PacketBlock + { + public UUID RegionID; + + public override int Length + { + get + { + return 16; + } + } + + public RegionInfo2Block() { } + public RegionInfo2Block(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RegionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RegionInfo3Block : PacketBlock + { + public int CPUClassID; + public int CPURatio; + public byte[] ColoName; + public byte[] ProductSKU; + public byte[] ProductName; + + public override int Length + { + get + { + int length = 11; + if (ColoName != null) { length += ColoName.Length; } + if (ProductSKU != null) { length += ProductSKU.Length; } + if (ProductName != null) { length += ProductName.Length; } + return length; + } + } + + public RegionInfo3Block() { } + public RegionInfo3Block(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + CPUClassID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CPURatio = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + ColoName = new byte[length]; + Buffer.BlockCopy(bytes, i, ColoName, 0, length); i += length; + length = bytes[i++]; + ProductSKU = new byte[length]; + Buffer.BlockCopy(bytes, i, ProductSKU, 0, length); i += length; + length = bytes[i++]; + ProductName = new byte[length]; + Buffer.BlockCopy(bytes, i, ProductName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(CPUClassID, bytes, i); i += 4; + Utils.IntToBytes(CPURatio, bytes, i); i += 4; + bytes[i++] = (byte)ColoName.Length; + Buffer.BlockCopy(ColoName, 0, bytes, i, ColoName.Length); i += ColoName.Length; + bytes[i++] = (byte)ProductSKU.Length; + Buffer.BlockCopy(ProductSKU, 0, bytes, i, ProductSKU.Length); i += ProductSKU.Length; + bytes[i++] = (byte)ProductName.Length; + Buffer.BlockCopy(ProductName, 0, bytes, i, ProductName.Length); i += ProductName.Length; + } + + } + + /// + public sealed class RegionInfo4Block : PacketBlock + { + public ulong RegionFlagsExtended; + public ulong RegionProtocols; + + public override int Length + { + get + { + return 16; + } + } + + public RegionInfo4Block() { } + public RegionInfo4Block(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionFlagsExtended = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + RegionProtocols = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionFlagsExtended, bytes, i); i += 8; + Utils.UInt64ToBytes(RegionProtocols, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 11; + length += RegionInfo.Length; + length += RegionInfo2.Length; + length += RegionInfo3.Length; + for (int j = 0; j < RegionInfo4.Length; j++) + length += RegionInfo4[j].Length; + return length; + } + } + public RegionInfoBlock RegionInfo; + public RegionInfo2Block RegionInfo2; + public RegionInfo3Block RegionInfo3; + public RegionInfo4Block[] RegionInfo4; + + public RegionHandshakePacket() + { + HasVariableBlocks = true; + Type = PacketType.RegionHandshake; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 148; + Header.Reliable = true; + Header.Zerocoded = true; + RegionInfo = new RegionInfoBlock(); + RegionInfo2 = new RegionInfo2Block(); + RegionInfo3 = new RegionInfo3Block(); + RegionInfo4 = null; + } + + public RegionHandshakePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RegionInfo.FromBytes(bytes, ref i); + RegionInfo2.FromBytes(bytes, ref i); + RegionInfo3.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RegionInfo4 == null || RegionInfo4.Length != -1) { + RegionInfo4 = new RegionInfo4Block[count]; + for(int j = 0; j < count; j++) + { RegionInfo4[j] = new RegionInfo4Block(); } + } + for (int j = 0; j < count; j++) + { RegionInfo4[j].FromBytes(bytes, ref i); } + } + + public RegionHandshakePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RegionInfo.FromBytes(bytes, ref i); + RegionInfo2.FromBytes(bytes, ref i); + RegionInfo3.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RegionInfo4 == null || RegionInfo4.Length != count) { + RegionInfo4 = new RegionInfo4Block[count]; + for(int j = 0; j < count; j++) + { RegionInfo4[j] = new RegionInfo4Block(); } + } + for (int j = 0; j < count; j++) + { RegionInfo4[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += RegionInfo.Length; + length += RegionInfo2.Length; + length += RegionInfo3.Length; + length++; + for (int j = 0; j < RegionInfo4.Length; j++) { length += RegionInfo4[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RegionInfo.ToBytes(bytes, ref i); + RegionInfo2.ToBytes(bytes, ref i); + RegionInfo3.ToBytes(bytes, ref i); + bytes[i++] = (byte)RegionInfo4.Length; + for (int j = 0; j < RegionInfo4.Length; j++) { RegionInfo4[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += RegionInfo.Length; + fixedLength += RegionInfo2.Length; + fixedLength += RegionInfo3.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + RegionInfo.ToBytes(fixedBytes, ref i); + RegionInfo2.ToBytes(fixedBytes, ref i); + RegionInfo3.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RegionInfo4Start = 0; + do + { + int variableLength = 0; + int RegionInfo4Count = 0; + + i = RegionInfo4Start; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < RegionInfo4.Length) { + int blockLength = RegionInfo4[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RegionInfo4Count; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RegionInfo4Count; + for (i = RegionInfo4Start; i < RegionInfo4Start + RegionInfo4Count; i++) { RegionInfo4[i].ToBytes(packet, ref length); } + RegionInfo4Start += RegionInfo4Count; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RegionInfo4Start < RegionInfo4.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RegionHandshakeReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RegionInfoBlock : PacketBlock + { + public uint Flags; + + public override int Length + { + get + { + return 4; + } + } + + public RegionInfoBlock() { } + public RegionInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += RegionInfo.Length; + return length; + } + } + public AgentDataBlock AgentData; + public RegionInfoBlock RegionInfo; + + public RegionHandshakeReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.RegionHandshakeReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 149; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + RegionInfo = new RegionInfoBlock(); + } + + public RegionHandshakeReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RegionInfo.FromBytes(bytes, ref i); + } + + public RegionHandshakeReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RegionInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RegionInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RegionInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SimulatorViewerTimeMessagePacket : Packet + { + /// + public sealed class TimeInfoBlock : PacketBlock + { + public ulong UsecSinceStart; + public uint SecPerDay; + public uint SecPerYear; + public Vector3 SunDirection; + public float SunPhase; + public Vector3 SunAngVelocity; + + public override int Length + { + get + { + return 44; + } + } + + public TimeInfoBlock() { } + public TimeInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + UsecSinceStart = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + SecPerDay = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SecPerYear = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SunDirection.FromBytes(bytes, i); i += 12; + SunPhase = Utils.BytesToFloat(bytes, i); i += 4; + SunAngVelocity.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(UsecSinceStart, bytes, i); i += 8; + Utils.UIntToBytes(SecPerDay, bytes, i); i += 4; + Utils.UIntToBytes(SecPerYear, bytes, i); i += 4; + SunDirection.ToBytes(bytes, i); i += 12; + Utils.FloatToBytes(SunPhase, bytes, i); i += 4; + SunAngVelocity.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TimeInfo.Length; + return length; + } + } + public TimeInfoBlock TimeInfo; + + public SimulatorViewerTimeMessagePacket() + { + HasVariableBlocks = false; + Type = PacketType.SimulatorViewerTimeMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 150; + Header.Reliable = true; + TimeInfo = new TimeInfoBlock(); + } + + public SimulatorViewerTimeMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TimeInfo.FromBytes(bytes, ref i); + } + + public SimulatorViewerTimeMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TimeInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TimeInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TimeInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EnableSimulatorPacket : Packet + { + /// + public sealed class SimulatorInfoBlock : PacketBlock + { + public ulong Handle; + public uint IP; + public ushort Port; + + public override int Length + { + get + { + return 14; + } + } + + public SimulatorInfoBlock() { } + public SimulatorInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Handle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + IP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Port = (ushort)((bytes[i++] << 8) + bytes[i++]); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(Handle, bytes, i); i += 8; + Utils.UIntToBytes(IP, bytes, i); i += 4; + bytes[i++] = (byte)((Port >> 8) % 256); + bytes[i++] = (byte)(Port % 256); + } + + } + + public override int Length + { + get + { + int length = 10; + length += SimulatorInfo.Length; + return length; + } + } + public SimulatorInfoBlock SimulatorInfo; + + public EnableSimulatorPacket() + { + HasVariableBlocks = false; + Type = PacketType.EnableSimulator; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 151; + Header.Reliable = true; + SimulatorInfo = new SimulatorInfoBlock(); + } + + public EnableSimulatorPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + SimulatorInfo.FromBytes(bytes, ref i); + } + + public EnableSimulatorPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + SimulatorInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += SimulatorInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + SimulatorInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DisableSimulatorPacket : Packet + { + public override int Length + { + get + { + int length = 10; + return length; + } + } + + public DisableSimulatorPacket() + { + HasVariableBlocks = false; + Type = PacketType.DisableSimulator; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 152; + Header.Reliable = true; + } + + public DisableSimulatorPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + } + + public DisableSimulatorPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + } + + public override byte[] ToBytes() + { + int length = 10; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TransferRequestPacket : Packet + { + /// + public sealed class TransferInfoBlock : PacketBlock + { + public UUID TransferID; + public int ChannelType; + public int SourceType; + public float Priority; + public byte[] Params; + + public override int Length + { + get + { + int length = 30; + if (Params != null) { length += Params.Length; } + return length; + } + } + + public TransferInfoBlock() { } + public TransferInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TransferID.FromBytes(bytes, i); i += 16; + ChannelType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SourceType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Priority = Utils.BytesToFloat(bytes, i); i += 4; + length = (bytes[i++] + (bytes[i++] << 8)); + Params = new byte[length]; + Buffer.BlockCopy(bytes, i, Params, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransferID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(ChannelType, bytes, i); i += 4; + Utils.IntToBytes(SourceType, bytes, i); i += 4; + Utils.FloatToBytes(Priority, bytes, i); i += 4; + bytes[i++] = (byte)(Params.Length % 256); + bytes[i++] = (byte)((Params.Length >> 8) % 256); + Buffer.BlockCopy(Params, 0, bytes, i, Params.Length); i += Params.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TransferInfo.Length; + return length; + } + } + public TransferInfoBlock TransferInfo; + + public TransferRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.TransferRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 153; + Header.Reliable = true; + Header.Zerocoded = true; + TransferInfo = new TransferInfoBlock(); + } + + public TransferRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TransferInfo.FromBytes(bytes, ref i); + } + + public TransferRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TransferInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TransferInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TransferInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TransferInfoPacket : Packet + { + /// + public sealed class TransferInfoBlock : PacketBlock + { + public UUID TransferID; + public int ChannelType; + public int TargetType; + public int Status; + public int Size; + public byte[] Params; + + public override int Length + { + get + { + int length = 34; + if (Params != null) { length += Params.Length; } + return length; + } + } + + public TransferInfoBlock() { } + public TransferInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TransferID.FromBytes(bytes, i); i += 16; + ChannelType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TargetType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Status = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Size = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = (bytes[i++] + (bytes[i++] << 8)); + Params = new byte[length]; + Buffer.BlockCopy(bytes, i, Params, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransferID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(ChannelType, bytes, i); i += 4; + Utils.IntToBytes(TargetType, bytes, i); i += 4; + Utils.IntToBytes(Status, bytes, i); i += 4; + Utils.IntToBytes(Size, bytes, i); i += 4; + bytes[i++] = (byte)(Params.Length % 256); + bytes[i++] = (byte)((Params.Length >> 8) % 256); + Buffer.BlockCopy(Params, 0, bytes, i, Params.Length); i += Params.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TransferInfo.Length; + return length; + } + } + public TransferInfoBlock TransferInfo; + + public TransferInfoPacket() + { + HasVariableBlocks = false; + Type = PacketType.TransferInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 154; + Header.Reliable = true; + Header.Zerocoded = true; + TransferInfo = new TransferInfoBlock(); + } + + public TransferInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TransferInfo.FromBytes(bytes, ref i); + } + + public TransferInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TransferInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TransferInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TransferInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TransferAbortPacket : Packet + { + /// + public sealed class TransferInfoBlock : PacketBlock + { + public UUID TransferID; + public int ChannelType; + + public override int Length + { + get + { + return 20; + } + } + + public TransferInfoBlock() { } + public TransferInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransferID.FromBytes(bytes, i); i += 16; + ChannelType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransferID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(ChannelType, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TransferInfo.Length; + return length; + } + } + public TransferInfoBlock TransferInfo; + + public TransferAbortPacket() + { + HasVariableBlocks = false; + Type = PacketType.TransferAbort; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 155; + Header.Reliable = true; + Header.Zerocoded = true; + TransferInfo = new TransferInfoBlock(); + } + + public TransferAbortPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TransferInfo.FromBytes(bytes, ref i); + } + + public TransferAbortPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TransferInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TransferInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TransferInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RequestXferPacket : Packet + { + /// + public sealed class XferIDBlock : PacketBlock + { + public ulong ID; + public byte[] Filename; + public byte FilePath; + public bool DeleteOnCompletion; + public bool UseBigPackets; + public UUID VFileID; + public short VFileType; + + public override int Length + { + get + { + int length = 30; + if (Filename != null) { length += Filename.Length; } + return length; + } + } + + public XferIDBlock() { } + public XferIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ID = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + length = bytes[i++]; + Filename = new byte[length]; + Buffer.BlockCopy(bytes, i, Filename, 0, length); i += length; + FilePath = (byte)bytes[i++]; + DeleteOnCompletion = (bytes[i++] != 0) ? (bool)true : (bool)false; + UseBigPackets = (bytes[i++] != 0) ? (bool)true : (bool)false; + VFileID.FromBytes(bytes, i); i += 16; + VFileType = (short)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(ID, bytes, i); i += 8; + bytes[i++] = (byte)Filename.Length; + Buffer.BlockCopy(Filename, 0, bytes, i, Filename.Length); i += Filename.Length; + bytes[i++] = FilePath; + bytes[i++] = (byte)((DeleteOnCompletion) ? 1 : 0); + bytes[i++] = (byte)((UseBigPackets) ? 1 : 0); + VFileID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(VFileType % 256); + bytes[i++] = (byte)((VFileType >> 8) % 256); + } + + } + + public override int Length + { + get + { + int length = 10; + length += XferID.Length; + return length; + } + } + public XferIDBlock XferID; + + public RequestXferPacket() + { + HasVariableBlocks = false; + Type = PacketType.RequestXfer; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 156; + Header.Reliable = true; + Header.Zerocoded = true; + XferID = new XferIDBlock(); + } + + public RequestXferPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + XferID.FromBytes(bytes, ref i); + } + + public RequestXferPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + XferID.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += XferID.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + XferID.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AbortXferPacket : Packet + { + /// + public sealed class XferIDBlock : PacketBlock + { + public ulong ID; + public int Result; + + public override int Length + { + get + { + return 12; + } + } + + public XferIDBlock() { } + public XferIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + Result = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(ID, bytes, i); i += 8; + Utils.IntToBytes(Result, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += XferID.Length; + return length; + } + } + public XferIDBlock XferID; + + public AbortXferPacket() + { + HasVariableBlocks = false; + Type = PacketType.AbortXfer; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 157; + Header.Reliable = true; + XferID = new XferIDBlock(); + } + + public AbortXferPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + XferID.FromBytes(bytes, ref i); + } + + public AbortXferPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + XferID.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += XferID.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + XferID.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarAppearancePacket : Packet + { + /// + public sealed class SenderBlock : PacketBlock + { + public UUID ID; + public bool IsTrial; + + public override int Length + { + get + { + return 17; + } + } + + public SenderBlock() { } + public SenderBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + IsTrial = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsTrial) ? 1 : 0); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public byte[] TextureEntry; + + public override int Length + { + get + { + int length = 2; + if (TextureEntry != null) { length += TextureEntry.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + TextureEntry = new byte[length]; + Buffer.BlockCopy(bytes, i, TextureEntry, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(TextureEntry.Length % 256); + bytes[i++] = (byte)((TextureEntry.Length >> 8) % 256); + Buffer.BlockCopy(TextureEntry, 0, bytes, i, TextureEntry.Length); i += TextureEntry.Length; + } + + } + + /// + public sealed class VisualParamBlock : PacketBlock + { + public byte ParamValue; + + public override int Length + { + get + { + return 1; + } + } + + public VisualParamBlock() { } + public VisualParamBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ParamValue = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = ParamValue; + } + + } + + /// + public sealed class AppearanceDataBlock : PacketBlock + { + public byte AppearanceVersion; + public int CofVersion; + public uint Flags; + + public override int Length + { + get + { + return 9; + } + } + + public AppearanceDataBlock() { } + public AppearanceDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AppearanceVersion = (byte)bytes[i++]; + CofVersion = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = AppearanceVersion; + Utils.IntToBytes(CofVersion, bytes, i); i += 4; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + /// + public sealed class AppearanceHoverBlock : PacketBlock + { + public Vector3 HoverHeight; + + public AppearanceHoverBlock() { } + public AppearanceHoverBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override int Length + { + get + { + return 12; + } + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + HoverHeight.FromBytes(bytes, i);// i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + HoverHeight.ToBytes(bytes, i); + } + } + + public override int Length + { + get + { + int length = 13; + length += Sender.Length; + length += ObjectData.Length; + for (int j = 0; j < VisualParam.Length; j++) + length += VisualParam[j].Length; + for (int j = 0; j < AppearanceData.Length; j++) + length += AppearanceData[j].Length; + for (int j = 0; j < AppearanceHover.Length; j++) + length += AppearanceHover[j].Length; + return length; + } + } + public SenderBlock Sender; + public ObjectDataBlock ObjectData; + public VisualParamBlock[] VisualParam; + public AppearanceDataBlock[] AppearanceData; + public AppearanceHoverBlock[] AppearanceHover; + + public AvatarAppearancePacket() + { + HasVariableBlocks = true; + Type = PacketType.AvatarAppearance; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 158; + Header.Reliable = true; + Header.Zerocoded = true; + Sender = new SenderBlock(); + ObjectData = new ObjectDataBlock(); + VisualParam = null; + AppearanceData = null; + AppearanceHover = null; + } + + public AvatarAppearancePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Sender.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(VisualParam == null || VisualParam.Length != -1) { + VisualParam = new VisualParamBlock[count]; + for(int j = 0; j < count; j++) + { VisualParam[j] = new VisualParamBlock(); } + } + for (int j = 0; j < count; j++) + { VisualParam[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AppearanceData == null || AppearanceData.Length != -1) { + AppearanceData = new AppearanceDataBlock[count]; + for(int j = 0; j < count; j++) + { AppearanceData[j] = new AppearanceDataBlock(); } + } + for (int j = 0; j < count; j++) + { AppearanceData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AppearanceHover == null || AppearanceHover.Length != -1) { + AppearanceHover = new AppearanceHoverBlock[count]; + for(int j = 0; j < count; j++) + { AppearanceHover[j] = new AppearanceHoverBlock(); } + } + for (int j = 0; j < count; j++) + { AppearanceHover[j].FromBytes(bytes, ref i); } + } + + public AvatarAppearancePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Sender.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(VisualParam == null || VisualParam.Length != count) { + VisualParam = new VisualParamBlock[count]; + for(int j = 0; j < count; j++) + { VisualParam[j] = new VisualParamBlock(); } + } + for (int j = 0; j < count; j++) + { VisualParam[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AppearanceData == null || AppearanceData.Length != count) { + AppearanceData = new AppearanceDataBlock[count]; + for(int j = 0; j < count; j++) + { AppearanceData[j] = new AppearanceDataBlock(); } + } + for (int j = 0; j < count; j++) + { AppearanceData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AppearanceHover == null || AppearanceHover.Length != count) { + AppearanceHover = new AppearanceHoverBlock[count]; + for(int j = 0; j < count; j++) + { AppearanceHover[j] = new AppearanceHoverBlock(); } + } + for (int j = 0; j < count; j++) + { AppearanceHover[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += Sender.Length; + length += ObjectData.Length; + length++; + for (int j = 0; j < VisualParam.Length; j++) { length += VisualParam[j].Length; } + length++; + for (int j = 0; j < AppearanceData.Length; j++) { length += AppearanceData[j].Length; } + length++; + for (int j = 0; j < AppearanceHover.Length; j++) { length += AppearanceHover[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Sender.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + bytes[i++] = (byte)VisualParam.Length; + for (int j = 0; j < VisualParam.Length; j++) { VisualParam[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)AppearanceData.Length; + for (int j = 0; j < AppearanceData.Length; j++) { AppearanceData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)AppearanceHover.Length; + for (int j = 0; j < AppearanceHover.Length; j++) { AppearanceHover[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += Sender.Length; + fixedLength += ObjectData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + Sender.ToBytes(fixedBytes, ref i); + ObjectData.ToBytes(fixedBytes, ref i); + fixedLength += 3; + + int VisualParamStart = 0; + int AppearanceDataStart = 0; + int AppearanceHoverStart = 0; + do + { + int variableLength = 0; + int VisualParamCount = 0; + int AppearanceDataCount = 0; + int AppearanceHoverCount = 0; + + i = VisualParamStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < VisualParam.Length) { + int blockLength = VisualParam[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++VisualParamCount; + } + else { break; } + ++i; + } + + i = AppearanceDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AppearanceData.Length) { + int blockLength = AppearanceData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AppearanceDataCount; + } + else { break; } + ++i; + } + + i = AppearanceHoverStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AppearanceHover.Length) { + int blockLength = AppearanceHover[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AppearanceHoverCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)VisualParamCount; + for (i = VisualParamStart; i < VisualParamStart + VisualParamCount; i++) { VisualParam[i].ToBytes(packet, ref length); } + VisualParamStart += VisualParamCount; + + packet[length++] = (byte)AppearanceDataCount; + for (i = AppearanceDataStart; i < AppearanceDataStart + AppearanceDataCount; i++) { AppearanceData[i].ToBytes(packet, ref length); } + AppearanceDataStart += AppearanceDataCount; + + packet[length++] = (byte)AppearanceHoverCount; + for (i = AppearanceHoverStart; i < AppearanceHoverStart + AppearanceHoverCount; i++) { AppearanceHover[i].ToBytes(packet, ref length); } + AppearanceHoverStart += AppearanceHoverCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + VisualParamStart < VisualParam.Length || + AppearanceDataStart < AppearanceData.Length || + AppearanceHoverStart < AppearanceHover.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class SetFollowCamPropertiesPacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class CameraPropertyBlock : PacketBlock + { + public int Type; + public float Value; + + public override int Length + { + get + { + return 8; + } + } + + public CameraPropertyBlock() { } + public CameraPropertyBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Type = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Value = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(Type, bytes, i); i += 4; + Utils.FloatToBytes(Value, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += ObjectData.Length; + for (int j = 0; j < CameraProperty.Length; j++) + length += CameraProperty[j].Length; + return length; + } + } + public ObjectDataBlock ObjectData; + public CameraPropertyBlock[] CameraProperty; + + public SetFollowCamPropertiesPacket() + { + HasVariableBlocks = true; + Type = PacketType.SetFollowCamProperties; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 159; + Header.Reliable = true; + ObjectData = new ObjectDataBlock(); + CameraProperty = null; + } + + public SetFollowCamPropertiesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(CameraProperty == null || CameraProperty.Length != -1) { + CameraProperty = new CameraPropertyBlock[count]; + for(int j = 0; j < count; j++) + { CameraProperty[j] = new CameraPropertyBlock(); } + } + for (int j = 0; j < count; j++) + { CameraProperty[j].FromBytes(bytes, ref i); } + } + + public SetFollowCamPropertiesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(CameraProperty == null || CameraProperty.Length != count) { + CameraProperty = new CameraPropertyBlock[count]; + for(int j = 0; j < count; j++) + { CameraProperty[j] = new CameraPropertyBlock(); } + } + for (int j = 0; j < count; j++) + { CameraProperty[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += ObjectData.Length; + length++; + for (int j = 0; j < CameraProperty.Length; j++) { length += CameraProperty[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + bytes[i++] = (byte)CameraProperty.Length; + for (int j = 0; j < CameraProperty.Length; j++) { CameraProperty[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += ObjectData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + ObjectData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int CameraPropertyStart = 0; + do + { + int variableLength = 0; + int CameraPropertyCount = 0; + + i = CameraPropertyStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < CameraProperty.Length) { + int blockLength = CameraProperty[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++CameraPropertyCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)CameraPropertyCount; + for (i = CameraPropertyStart; i < CameraPropertyStart + CameraPropertyCount; i++) { CameraProperty[i].ToBytes(packet, ref length); } + CameraPropertyStart += CameraPropertyCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + CameraPropertyStart < CameraProperty.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ClearFollowCamPropertiesPacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ObjectData.Length; + return length; + } + } + public ObjectDataBlock ObjectData; + + public ClearFollowCamPropertiesPacket() + { + HasVariableBlocks = false; + Type = PacketType.ClearFollowCamProperties; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 160; + Header.Reliable = true; + ObjectData = new ObjectDataBlock(); + } + + public ClearFollowCamPropertiesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ObjectData.FromBytes(bytes, ref i); + } + + public ClearFollowCamPropertiesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RequestPayPricePacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ObjectData.Length; + return length; + } + } + public ObjectDataBlock ObjectData; + + public RequestPayPricePacket() + { + HasVariableBlocks = false; + Type = PacketType.RequestPayPrice; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 161; + Header.Reliable = true; + ObjectData = new ObjectDataBlock(); + } + + public RequestPayPricePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ObjectData.FromBytes(bytes, ref i); + } + + public RequestPayPricePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PayPriceReplyPacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + public int DefaultPayPrice; + + public override int Length + { + get + { + return 20; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + DefaultPayPrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(DefaultPayPrice, bytes, i); i += 4; + } + + } + + /// + public sealed class ButtonDataBlock : PacketBlock + { + public int PayButton; + + public override int Length + { + get + { + return 4; + } + } + + public ButtonDataBlock() { } + public ButtonDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PayButton = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(PayButton, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += ObjectData.Length; + for (int j = 0; j < ButtonData.Length; j++) + length += ButtonData[j].Length; + return length; + } + } + public ObjectDataBlock ObjectData; + public ButtonDataBlock[] ButtonData; + + public PayPriceReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.PayPriceReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 162; + Header.Reliable = true; + ObjectData = new ObjectDataBlock(); + ButtonData = null; + } + + public PayPriceReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ButtonData == null || ButtonData.Length != -1) { + ButtonData = new ButtonDataBlock[count]; + for(int j = 0; j < count; j++) + { ButtonData[j] = new ButtonDataBlock(); } + } + for (int j = 0; j < count; j++) + { ButtonData[j].FromBytes(bytes, ref i); } + } + + public PayPriceReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ObjectData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ButtonData == null || ButtonData.Length != count) { + ButtonData = new ButtonDataBlock[count]; + for(int j = 0; j < count; j++) + { ButtonData[j] = new ButtonDataBlock(); } + } + for (int j = 0; j < count; j++) + { ButtonData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += ObjectData.Length; + length++; + for (int j = 0; j < ButtonData.Length; j++) { length += ButtonData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ButtonData.Length; + for (int j = 0; j < ButtonData.Length; j++) { ButtonData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += ObjectData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + ObjectData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ButtonDataStart = 0; + do + { + int variableLength = 0; + int ButtonDataCount = 0; + + i = ButtonDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ButtonData.Length) { + int blockLength = ButtonData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ButtonDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ButtonDataCount; + for (i = ButtonDataStart; i < ButtonDataStart + ButtonDataCount; i++) { ButtonData[i].ToBytes(packet, ref length); } + ButtonDataStart += ButtonDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ButtonDataStart < ButtonData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class KickUserPacket : Packet + { + /// + public sealed class TargetBlockBlock : PacketBlock + { + public uint TargetIP; + public ushort TargetPort; + + public override int Length + { + get + { + return 6; + } + } + + public TargetBlockBlock() { } + public TargetBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TargetIP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TargetPort = (ushort)((bytes[i++] << 8) + bytes[i++]); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(TargetIP, bytes, i); i += 4; + bytes[i++] = (byte)((TargetPort >> 8) % 256); + bytes[i++] = (byte)(TargetPort % 256); + } + + } + + /// + public sealed class UserInfoBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public byte[] Reason; + + public override int Length + { + get + { + int length = 34; + if (Reason != null) { length += Reason.Length; } + return length; + } + } + + public UserInfoBlock() { } + public UserInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + length = (bytes[i++] + (bytes[i++] << 8)); + Reason = new byte[length]; + Buffer.BlockCopy(bytes, i, Reason, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(Reason.Length % 256); + bytes[i++] = (byte)((Reason.Length >> 8) % 256); + Buffer.BlockCopy(Reason, 0, bytes, i, Reason.Length); i += Reason.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TargetBlock.Length; + length += UserInfo.Length; + return length; + } + } + public TargetBlockBlock TargetBlock; + public UserInfoBlock UserInfo; + + public KickUserPacket() + { + HasVariableBlocks = false; + Type = PacketType.KickUser; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 163; + Header.Reliable = true; + TargetBlock = new TargetBlockBlock(); + UserInfo = new UserInfoBlock(); + } + + public KickUserPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TargetBlock.FromBytes(bytes, ref i); + UserInfo.FromBytes(bytes, ref i); + } + + public KickUserPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TargetBlock.FromBytes(bytes, ref i); + UserInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TargetBlock.Length; + length += UserInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TargetBlock.ToBytes(bytes, ref i); + UserInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GodKickUserPacket : Packet + { + /// + public sealed class UserInfoBlock : PacketBlock + { + public UUID GodID; + public UUID GodSessionID; + public UUID AgentID; + public uint KickFlags; + public byte[] Reason; + + public override int Length + { + get + { + int length = 54; + if (Reason != null) { length += Reason.Length; } + return length; + } + } + + public UserInfoBlock() { } + public UserInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GodID.FromBytes(bytes, i); i += 16; + GodSessionID.FromBytes(bytes, i); i += 16; + AgentID.FromBytes(bytes, i); i += 16; + KickFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = (bytes[i++] + (bytes[i++] << 8)); + Reason = new byte[length]; + Buffer.BlockCopy(bytes, i, Reason, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GodID.ToBytes(bytes, i); i += 16; + GodSessionID.ToBytes(bytes, i); i += 16; + AgentID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(KickFlags, bytes, i); i += 4; + bytes[i++] = (byte)(Reason.Length % 256); + bytes[i++] = (byte)((Reason.Length >> 8) % 256); + Buffer.BlockCopy(Reason, 0, bytes, i, Reason.Length); i += Reason.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += UserInfo.Length; + return length; + } + } + public UserInfoBlock UserInfo; + + public GodKickUserPacket() + { + HasVariableBlocks = false; + Type = PacketType.GodKickUser; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 165; + Header.Reliable = true; + UserInfo = new UserInfoBlock(); + } + + public GodKickUserPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + UserInfo.FromBytes(bytes, ref i); + } + + public GodKickUserPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + UserInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += UserInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + UserInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EjectUserPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID TargetID; + public uint Flags; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TargetID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TargetID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public EjectUserPacket() + { + HasVariableBlocks = false; + Type = PacketType.EjectUser; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 167; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public EjectUserPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public EjectUserPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class FreezeUserPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID TargetID; + public uint Flags; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TargetID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TargetID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public FreezeUserPacket() + { + HasVariableBlocks = false; + Type = PacketType.FreezeUser; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 168; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public FreezeUserPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public FreezeUserPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarPropertiesRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID AvatarID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + AvatarID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + AvatarID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AvatarPropertiesRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarPropertiesRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 169; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public AvatarPropertiesRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AvatarPropertiesRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarPropertiesReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID AvatarID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + AvatarID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + AvatarID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class PropertiesDataBlock : PacketBlock + { + public UUID ImageID; + public UUID FLImageID; + public UUID PartnerID; + public byte[] AboutText; + public byte[] FLAboutText; + public byte[] BornOn; + public byte[] ProfileURL; + public byte[] CharterMember; + public uint Flags; + + public override int Length + { + get + { + int length = 58; + if (AboutText != null) { length += AboutText.Length; } + if (FLAboutText != null) { length += FLAboutText.Length; } + if (BornOn != null) { length += BornOn.Length; } + if (ProfileURL != null) { length += ProfileURL.Length; } + if (CharterMember != null) { length += CharterMember.Length; } + return length; + } + } + + public PropertiesDataBlock() { } + public PropertiesDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ImageID.FromBytes(bytes, i); i += 16; + FLImageID.FromBytes(bytes, i); i += 16; + PartnerID.FromBytes(bytes, i); i += 16; + length = (bytes[i++] + (bytes[i++] << 8)); + AboutText = new byte[length]; + Buffer.BlockCopy(bytes, i, AboutText, 0, length); i += length; + length = bytes[i++]; + FLAboutText = new byte[length]; + Buffer.BlockCopy(bytes, i, FLAboutText, 0, length); i += length; + length = bytes[i++]; + BornOn = new byte[length]; + Buffer.BlockCopy(bytes, i, BornOn, 0, length); i += length; + length = bytes[i++]; + ProfileURL = new byte[length]; + Buffer.BlockCopy(bytes, i, ProfileURL, 0, length); i += length; + length = bytes[i++]; + CharterMember = new byte[length]; + Buffer.BlockCopy(bytes, i, CharterMember, 0, length); i += length; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ImageID.ToBytes(bytes, i); i += 16; + FLImageID.ToBytes(bytes, i); i += 16; + PartnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(AboutText.Length % 256); + bytes[i++] = (byte)((AboutText.Length >> 8) % 256); + Buffer.BlockCopy(AboutText, 0, bytes, i, AboutText.Length); i += AboutText.Length; + bytes[i++] = (byte)FLAboutText.Length; + Buffer.BlockCopy(FLAboutText, 0, bytes, i, FLAboutText.Length); i += FLAboutText.Length; + bytes[i++] = (byte)BornOn.Length; + Buffer.BlockCopy(BornOn, 0, bytes, i, BornOn.Length); i += BornOn.Length; + bytes[i++] = (byte)ProfileURL.Length; + Buffer.BlockCopy(ProfileURL, 0, bytes, i, ProfileURL.Length); i += ProfileURL.Length; + bytes[i++] = (byte)CharterMember.Length; + Buffer.BlockCopy(CharterMember, 0, bytes, i, CharterMember.Length); i += CharterMember.Length; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public PropertiesDataBlock PropertiesData; + + public AvatarPropertiesReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarPropertiesReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 171; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + PropertiesData = new PropertiesDataBlock(); + } + + public AvatarPropertiesReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public AvatarPropertiesReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + PropertiesData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarInterestsReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID AvatarID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + AvatarID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + AvatarID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class PropertiesDataBlock : PacketBlock + { + public uint WantToMask; + public byte[] WantToText; + public uint SkillsMask; + public byte[] SkillsText; + public byte[] LanguagesText; + + public override int Length + { + get + { + int length = 11; + if (WantToText != null) { length += WantToText.Length; } + if (SkillsText != null) { length += SkillsText.Length; } + if (LanguagesText != null) { length += LanguagesText.Length; } + return length; + } + } + + public PropertiesDataBlock() { } + public PropertiesDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + WantToMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + WantToText = new byte[length]; + Buffer.BlockCopy(bytes, i, WantToText, 0, length); i += length; + SkillsMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + SkillsText = new byte[length]; + Buffer.BlockCopy(bytes, i, SkillsText, 0, length); i += length; + length = bytes[i++]; + LanguagesText = new byte[length]; + Buffer.BlockCopy(bytes, i, LanguagesText, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(WantToMask, bytes, i); i += 4; + bytes[i++] = (byte)WantToText.Length; + Buffer.BlockCopy(WantToText, 0, bytes, i, WantToText.Length); i += WantToText.Length; + Utils.UIntToBytes(SkillsMask, bytes, i); i += 4; + bytes[i++] = (byte)SkillsText.Length; + Buffer.BlockCopy(SkillsText, 0, bytes, i, SkillsText.Length); i += SkillsText.Length; + bytes[i++] = (byte)LanguagesText.Length; + Buffer.BlockCopy(LanguagesText, 0, bytes, i, LanguagesText.Length); i += LanguagesText.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public PropertiesDataBlock PropertiesData; + + public AvatarInterestsReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarInterestsReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 172; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + PropertiesData = new PropertiesDataBlock(); + } + + public AvatarInterestsReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public AvatarInterestsReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + PropertiesData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarGroupsReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID AvatarID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + AvatarID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + AvatarID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public ulong GroupPowers; + public bool AcceptNotices; + public byte[] GroupTitle; + public UUID GroupID; + public byte[] GroupName; + public UUID GroupInsigniaID; + + public override int Length + { + get + { + int length = 43; + if (GroupTitle != null) { length += GroupTitle.Length; } + if (GroupName != null) { length += GroupName.Length; } + return length; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GroupPowers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + AcceptNotices = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + GroupTitle = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupTitle, 0, length); i += length; + GroupID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + GroupName = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupName, 0, length); i += length; + GroupInsigniaID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(GroupPowers, bytes, i); i += 8; + bytes[i++] = (byte)((AcceptNotices) ? 1 : 0); + bytes[i++] = (byte)GroupTitle.Length; + Buffer.BlockCopy(GroupTitle, 0, bytes, i, GroupTitle.Length); i += GroupTitle.Length; + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)GroupName.Length; + Buffer.BlockCopy(GroupName, 0, bytes, i, GroupName.Length); i += GroupName.Length; + GroupInsigniaID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class NewGroupDataBlock : PacketBlock + { + public bool ListInProfile; + + public override int Length + { + get + { + return 1; + } + } + + public NewGroupDataBlock() { } + public NewGroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ListInProfile = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((ListInProfile) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < GroupData.Length; j++) + length += GroupData[j].Length; + length += NewGroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock[] GroupData; + public NewGroupDataBlock NewGroupData; + + public AvatarGroupsReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.AvatarGroupsReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 173; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = null; + NewGroupData = new NewGroupDataBlock(); + } + + public AvatarGroupsReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != -1) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + NewGroupData.FromBytes(bytes, ref i); + } + + public AvatarGroupsReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != count) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + NewGroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += NewGroupData.Length; + length++; + for (int j = 0; j < GroupData.Length; j++) { length += GroupData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)GroupData.Length; + for (int j = 0; j < GroupData.Length; j++) { GroupData[j].ToBytes(bytes, ref i); } + NewGroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarPropertiesUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class PropertiesDataBlock : PacketBlock + { + public UUID ImageID; + public UUID FLImageID; + public byte[] AboutText; + public byte[] FLAboutText; + public bool AllowPublish; + public bool MaturePublish; + public byte[] ProfileURL; + + public override int Length + { + get + { + int length = 38; + if (AboutText != null) { length += AboutText.Length; } + if (FLAboutText != null) { length += FLAboutText.Length; } + if (ProfileURL != null) { length += ProfileURL.Length; } + return length; + } + } + + public PropertiesDataBlock() { } + public PropertiesDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ImageID.FromBytes(bytes, i); i += 16; + FLImageID.FromBytes(bytes, i); i += 16; + length = (bytes[i++] + (bytes[i++] << 8)); + AboutText = new byte[length]; + Buffer.BlockCopy(bytes, i, AboutText, 0, length); i += length; + length = bytes[i++]; + FLAboutText = new byte[length]; + Buffer.BlockCopy(bytes, i, FLAboutText, 0, length); i += length; + AllowPublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + MaturePublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + ProfileURL = new byte[length]; + Buffer.BlockCopy(bytes, i, ProfileURL, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ImageID.ToBytes(bytes, i); i += 16; + FLImageID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(AboutText.Length % 256); + bytes[i++] = (byte)((AboutText.Length >> 8) % 256); + Buffer.BlockCopy(AboutText, 0, bytes, i, AboutText.Length); i += AboutText.Length; + bytes[i++] = (byte)FLAboutText.Length; + Buffer.BlockCopy(FLAboutText, 0, bytes, i, FLAboutText.Length); i += FLAboutText.Length; + bytes[i++] = (byte)((AllowPublish) ? 1 : 0); + bytes[i++] = (byte)((MaturePublish) ? 1 : 0); + bytes[i++] = (byte)ProfileURL.Length; + Buffer.BlockCopy(ProfileURL, 0, bytes, i, ProfileURL.Length); i += ProfileURL.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public PropertiesDataBlock PropertiesData; + + public AvatarPropertiesUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarPropertiesUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 174; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + PropertiesData = new PropertiesDataBlock(); + } + + public AvatarPropertiesUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public AvatarPropertiesUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + PropertiesData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarInterestsUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class PropertiesDataBlock : PacketBlock + { + public uint WantToMask; + public byte[] WantToText; + public uint SkillsMask; + public byte[] SkillsText; + public byte[] LanguagesText; + + public override int Length + { + get + { + int length = 11; + if (WantToText != null) { length += WantToText.Length; } + if (SkillsText != null) { length += SkillsText.Length; } + if (LanguagesText != null) { length += LanguagesText.Length; } + return length; + } + } + + public PropertiesDataBlock() { } + public PropertiesDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + WantToMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + WantToText = new byte[length]; + Buffer.BlockCopy(bytes, i, WantToText, 0, length); i += length; + SkillsMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + SkillsText = new byte[length]; + Buffer.BlockCopy(bytes, i, SkillsText, 0, length); i += length; + length = bytes[i++]; + LanguagesText = new byte[length]; + Buffer.BlockCopy(bytes, i, LanguagesText, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(WantToMask, bytes, i); i += 4; + bytes[i++] = (byte)WantToText.Length; + Buffer.BlockCopy(WantToText, 0, bytes, i, WantToText.Length); i += WantToText.Length; + Utils.UIntToBytes(SkillsMask, bytes, i); i += 4; + bytes[i++] = (byte)SkillsText.Length; + Buffer.BlockCopy(SkillsText, 0, bytes, i, SkillsText.Length); i += SkillsText.Length; + bytes[i++] = (byte)LanguagesText.Length; + Buffer.BlockCopy(LanguagesText, 0, bytes, i, LanguagesText.Length); i += LanguagesText.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public PropertiesDataBlock PropertiesData; + + public AvatarInterestsUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarInterestsUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 175; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + PropertiesData = new PropertiesDataBlock(); + } + + public AvatarInterestsUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public AvatarInterestsUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + PropertiesData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += PropertiesData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + PropertiesData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarNotesReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID TargetID; + public byte[] Notes; + + public override int Length + { + get + { + int length = 18; + if (Notes != null) { length += Notes.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TargetID.FromBytes(bytes, i); i += 16; + length = (bytes[i++] + (bytes[i++] << 8)); + Notes = new byte[length]; + Buffer.BlockCopy(bytes, i, Notes, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TargetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(Notes.Length % 256); + bytes[i++] = (byte)((Notes.Length >> 8) % 256); + Buffer.BlockCopy(Notes, 0, bytes, i, Notes.Length); i += Notes.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public AvatarNotesReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarNotesReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 176; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public AvatarNotesReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public AvatarNotesReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarNotesUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID TargetID; + public byte[] Notes; + + public override int Length + { + get + { + int length = 18; + if (Notes != null) { length += Notes.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TargetID.FromBytes(bytes, i); i += 16; + length = (bytes[i++] + (bytes[i++] << 8)); + Notes = new byte[length]; + Buffer.BlockCopy(bytes, i, Notes, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TargetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(Notes.Length % 256); + bytes[i++] = (byte)((Notes.Length >> 8) % 256); + Buffer.BlockCopy(Notes, 0, bytes, i, Notes.Length); i += Notes.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public AvatarNotesUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarNotesUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 177; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public AvatarNotesUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public AvatarNotesUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarPicksReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID TargetID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + TargetID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + TargetID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID PickID; + public byte[] PickName; + + public override int Length + { + get + { + int length = 17; + if (PickName != null) { length += PickName.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + PickID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + PickName = new byte[length]; + Buffer.BlockCopy(bytes, i, PickName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + PickID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)PickName.Length; + Buffer.BlockCopy(PickName, 0, bytes, i, PickName.Length); i += PickName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock[] Data; + + public AvatarPicksReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.AvatarPicksReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 178; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = null; + } + + public AvatarPicksReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public AvatarPicksReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class EventInfoRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EventDataBlock : PacketBlock + { + public uint EventID; + + public override int Length + { + get + { + return 4; + } + } + + public EventDataBlock() { } + public EventDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + EventID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(EventID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public EventDataBlock EventData; + + public EventInfoRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.EventInfoRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 179; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + EventData = new EventDataBlock(); + } + + public EventInfoRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public EventInfoRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + EventData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EventInfoReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EventDataBlock : PacketBlock + { + public uint EventID; + public byte[] Creator; + public byte[] Name; + public byte[] Category; + public byte[] Desc; + public byte[] Date; + public uint DateUTC; + public uint Duration; + public uint Cover; + public uint Amount; + public byte[] SimName; + public Vector3d GlobalPos; + public uint EventFlags; + + public override int Length + { + get + { + int length = 55; + if (Creator != null) { length += Creator.Length; } + if (Name != null) { length += Name.Length; } + if (Category != null) { length += Category.Length; } + if (Desc != null) { length += Desc.Length; } + if (Date != null) { length += Date.Length; } + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public EventDataBlock() { } + public EventDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + EventID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Creator = new byte[length]; + Buffer.BlockCopy(bytes, i, Creator, 0, length); i += length; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Category = new byte[length]; + Buffer.BlockCopy(bytes, i, Category, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + length = bytes[i++]; + Date = new byte[length]; + Buffer.BlockCopy(bytes, i, Date, 0, length); i += length; + DateUTC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Duration = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Cover = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Amount = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + GlobalPos.FromBytes(bytes, i); i += 24; + EventFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(EventID, bytes, i); i += 4; + bytes[i++] = (byte)Creator.Length; + Buffer.BlockCopy(Creator, 0, bytes, i, Creator.Length); i += Creator.Length; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Category.Length; + Buffer.BlockCopy(Category, 0, bytes, i, Category.Length); i += Category.Length; + bytes[i++] = (byte)(Desc.Length % 256); + bytes[i++] = (byte)((Desc.Length >> 8) % 256); + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + bytes[i++] = (byte)Date.Length; + Buffer.BlockCopy(Date, 0, bytes, i, Date.Length); i += Date.Length; + Utils.UIntToBytes(DateUTC, bytes, i); i += 4; + Utils.UIntToBytes(Duration, bytes, i); i += 4; + Utils.UIntToBytes(Cover, bytes, i); i += 4; + Utils.UIntToBytes(Amount, bytes, i); i += 4; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + GlobalPos.ToBytes(bytes, i); i += 24; + Utils.UIntToBytes(EventFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public EventDataBlock EventData; + + public EventInfoReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.EventInfoReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 180; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + EventData = new EventDataBlock(); + } + + public EventInfoReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public EventInfoReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + EventData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EventNotificationAddRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EventDataBlock : PacketBlock + { + public uint EventID; + + public override int Length + { + get + { + return 4; + } + } + + public EventDataBlock() { } + public EventDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + EventID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(EventID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public EventDataBlock EventData; + + public EventNotificationAddRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.EventNotificationAddRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 181; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + EventData = new EventDataBlock(); + } + + public EventNotificationAddRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public EventNotificationAddRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + EventData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EventNotificationRemoveRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EventDataBlock : PacketBlock + { + public uint EventID; + + public override int Length + { + get + { + return 4; + } + } + + public EventDataBlock() { } + public EventDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + EventID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(EventID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public EventDataBlock EventData; + + public EventNotificationRemoveRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.EventNotificationRemoveRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 182; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + EventData = new EventDataBlock(); + } + + public EventNotificationRemoveRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public EventNotificationRemoveRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + EventData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EventGodDeletePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EventDataBlock : PacketBlock + { + public uint EventID; + + public override int Length + { + get + { + return 4; + } + } + + public EventDataBlock() { } + public EventDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + EventID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(EventID, bytes, i); i += 4; + } + + } + + /// + public sealed class QueryDataBlock : PacketBlock + { + public UUID QueryID; + public byte[] QueryText; + public uint QueryFlags; + public int QueryStart; + + public override int Length + { + get + { + int length = 25; + if (QueryText != null) { length += QueryText.Length; } + return length; + } + } + + public QueryDataBlock() { } + public QueryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + QueryID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + QueryText = new byte[length]; + Buffer.BlockCopy(bytes, i, QueryText, 0, length); i += length; + QueryFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + QueryStart = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + QueryID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)QueryText.Length; + Buffer.BlockCopy(QueryText, 0, bytes, i, QueryText.Length); i += QueryText.Length; + Utils.UIntToBytes(QueryFlags, bytes, i); i += 4; + Utils.IntToBytes(QueryStart, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + length += QueryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public EventDataBlock EventData; + public QueryDataBlock QueryData; + + public EventGodDeletePacket() + { + HasVariableBlocks = false; + Type = PacketType.EventGodDelete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 183; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + EventData = new EventDataBlock(); + QueryData = new QueryDataBlock(); + } + + public EventGodDeletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public EventGodDeletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + QueryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + length += QueryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + EventData.ToBytes(bytes, ref i); + QueryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PickInfoReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID PickID; + public UUID CreatorID; + public bool TopPick; + public UUID ParcelID; + public byte[] Name; + public byte[] Desc; + public UUID SnapshotID; + public byte[] User; + public byte[] OriginalName; + public byte[] SimName; + public Vector3d PosGlobal; + public int SortOrder; + public bool Enabled; + + public override int Length + { + get + { + int length = 100; + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + if (User != null) { length += User.Length; } + if (OriginalName != null) { length += OriginalName.Length; } + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + PickID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + TopPick = (bytes[i++] != 0) ? (bool)true : (bool)false; + ParcelID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + SnapshotID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + User = new byte[length]; + Buffer.BlockCopy(bytes, i, User, 0, length); i += length; + length = bytes[i++]; + OriginalName = new byte[length]; + Buffer.BlockCopy(bytes, i, OriginalName, 0, length); i += length; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + PosGlobal.FromBytes(bytes, i); i += 24; + SortOrder = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Enabled = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + PickID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((TopPick) ? 1 : 0); + ParcelID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)(Desc.Length % 256); + bytes[i++] = (byte)((Desc.Length >> 8) % 256); + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + SnapshotID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)User.Length; + Buffer.BlockCopy(User, 0, bytes, i, User.Length); i += User.Length; + bytes[i++] = (byte)OriginalName.Length; + Buffer.BlockCopy(OriginalName, 0, bytes, i, OriginalName.Length); i += OriginalName.Length; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + PosGlobal.ToBytes(bytes, i); i += 24; + Utils.IntToBytes(SortOrder, bytes, i); i += 4; + bytes[i++] = (byte)((Enabled) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public PickInfoReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.PickInfoReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 184; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public PickInfoReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public PickInfoReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PickInfoUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID PickID; + public UUID CreatorID; + public bool TopPick; + public UUID ParcelID; + public byte[] Name; + public byte[] Desc; + public UUID SnapshotID; + public Vector3d PosGlobal; + public int SortOrder; + public bool Enabled; + + public override int Length + { + get + { + int length = 97; + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + PickID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + TopPick = (bytes[i++] != 0) ? (bool)true : (bool)false; + ParcelID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + SnapshotID.FromBytes(bytes, i); i += 16; + PosGlobal.FromBytes(bytes, i); i += 24; + SortOrder = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Enabled = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + PickID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((TopPick) ? 1 : 0); + ParcelID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)(Desc.Length % 256); + bytes[i++] = (byte)((Desc.Length >> 8) % 256); + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + SnapshotID.ToBytes(bytes, i); i += 16; + PosGlobal.ToBytes(bytes, i); i += 24; + Utils.IntToBytes(SortOrder, bytes, i); i += 4; + bytes[i++] = (byte)((Enabled) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public PickInfoUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.PickInfoUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 185; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public PickInfoUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public PickInfoUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PickDeletePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID PickID; + + public override int Length + { + get + { + return 16; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PickID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + PickID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public PickDeletePacket() + { + HasVariableBlocks = false; + Type = PacketType.PickDelete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 186; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public PickDeletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public PickDeletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PickGodDeletePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID PickID; + public UUID QueryID; + + public override int Length + { + get + { + return 32; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PickID.FromBytes(bytes, i); i += 16; + QueryID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + PickID.ToBytes(bytes, i); i += 16; + QueryID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public PickGodDeletePacket() + { + HasVariableBlocks = false; + Type = PacketType.PickGodDelete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 187; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public PickGodDeletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public PickGodDeletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ScriptQuestionPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public UUID TaskID; + public UUID ItemID; + public byte[] ObjectName; + public byte[] ObjectOwner; + public int Questions; + + public override int Length + { + get + { + int length = 38; + if (ObjectName != null) { length += ObjectName.Length; } + if (ObjectOwner != null) { length += ObjectOwner.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TaskID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + ObjectName = new byte[length]; + Buffer.BlockCopy(bytes, i, ObjectName, 0, length); i += length; + length = bytes[i++]; + ObjectOwner = new byte[length]; + Buffer.BlockCopy(bytes, i, ObjectOwner, 0, length); i += length; + Questions = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TaskID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)ObjectName.Length; + Buffer.BlockCopy(ObjectName, 0, bytes, i, ObjectName.Length); i += ObjectName.Length; + bytes[i++] = (byte)ObjectOwner.Length; + Buffer.BlockCopy(ObjectOwner, 0, bytes, i, ObjectOwner.Length); i += ObjectOwner.Length; + Utils.IntToBytes(Questions, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Data.Length; + return length; + } + } + public DataBlock Data; + + public ScriptQuestionPacket() + { + HasVariableBlocks = false; + Type = PacketType.ScriptQuestion; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 188; + Header.Reliable = true; + Data = new DataBlock(); + } + + public ScriptQuestionPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Data.FromBytes(bytes, ref i); + } + + public ScriptQuestionPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ScriptControlChangePacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public bool TakeControls; + public uint Controls; + public bool PassToAgent; + + public override int Length + { + get + { + return 6; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TakeControls = (bytes[i++] != 0) ? (bool)true : (bool)false; + Controls = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PassToAgent = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((TakeControls) ? 1 : 0); + Utils.UIntToBytes(Controls, bytes, i); i += 4; + bytes[i++] = (byte)((PassToAgent) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public DataBlock[] Data; + + public ScriptControlChangePacket() + { + HasVariableBlocks = true; + Type = PacketType.ScriptControlChange; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 189; + Header.Reliable = true; + Data = null; + } + + public ScriptControlChangePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public ScriptControlChangePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ScriptDialogPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public UUID ObjectID; + public byte[] FirstName; + public byte[] LastName; + public byte[] ObjectName; + public byte[] Message; + public int ChatChannel; + public UUID ImageID; + + public override int Length + { + get + { + int length = 41; + if (FirstName != null) { length += FirstName.Length; } + if (LastName != null) { length += LastName.Length; } + if (ObjectName != null) { length += ObjectName.Length; } + if (Message != null) { length += Message.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + FirstName = new byte[length]; + Buffer.BlockCopy(bytes, i, FirstName, 0, length); i += length; + length = bytes[i++]; + LastName = new byte[length]; + Buffer.BlockCopy(bytes, i, LastName, 0, length); i += length; + length = bytes[i++]; + ObjectName = new byte[length]; + Buffer.BlockCopy(bytes, i, ObjectName, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + ChatChannel = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ImageID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)FirstName.Length; + Buffer.BlockCopy(FirstName, 0, bytes, i, FirstName.Length); i += FirstName.Length; + bytes[i++] = (byte)LastName.Length; + Buffer.BlockCopy(LastName, 0, bytes, i, LastName.Length); i += LastName.Length; + bytes[i++] = (byte)ObjectName.Length; + Buffer.BlockCopy(ObjectName, 0, bytes, i, ObjectName.Length); i += ObjectName.Length; + bytes[i++] = (byte)(Message.Length % 256); + bytes[i++] = (byte)((Message.Length >> 8) % 256); + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + Utils.IntToBytes(ChatChannel, bytes, i); i += 4; + ImageID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ButtonsBlock : PacketBlock + { + public byte[] ButtonLabel; + + public override int Length + { + get + { + int length = 1; + if (ButtonLabel != null) { length += ButtonLabel.Length; } + return length; + } + } + + public ButtonsBlock() { } + public ButtonsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + ButtonLabel = new byte[length]; + Buffer.BlockCopy(bytes, i, ButtonLabel, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)ButtonLabel.Length; + Buffer.BlockCopy(ButtonLabel, 0, bytes, i, ButtonLabel.Length); i += ButtonLabel.Length; + } + + } + + /// + public sealed class OwnerDataBlock : PacketBlock + { + public UUID OwnerID; + + public override int Length + { + get + { + return 16; + } + } + + public OwnerDataBlock() { } + public OwnerDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OwnerID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 12; + length += Data.Length; + for (int j = 0; j < Buttons.Length; j++) + length += Buttons[j].Length; + for (int j = 0; j < OwnerData.Length; j++) + length += OwnerData[j].Length; + return length; + } + } + public DataBlock Data; + public ButtonsBlock[] Buttons; + public OwnerDataBlock[] OwnerData; + + public ScriptDialogPacket() + { + HasVariableBlocks = true; + Type = PacketType.ScriptDialog; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 190; + Header.Reliable = true; + Header.Zerocoded = true; + Data = new DataBlock(); + Buttons = null; + OwnerData = null; + } + + public ScriptDialogPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Buttons == null || Buttons.Length != -1) { + Buttons = new ButtonsBlock[count]; + for(int j = 0; j < count; j++) + { Buttons[j] = new ButtonsBlock(); } + } + for (int j = 0; j < count; j++) + { Buttons[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(OwnerData == null || OwnerData.Length != -1) { + OwnerData = new OwnerDataBlock[count]; + for(int j = 0; j < count; j++) + { OwnerData[j] = new OwnerDataBlock(); } + } + for (int j = 0; j < count; j++) + { OwnerData[j].FromBytes(bytes, ref i); } + } + + public ScriptDialogPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Buttons == null || Buttons.Length != count) { + Buttons = new ButtonsBlock[count]; + for(int j = 0; j < count; j++) + { Buttons[j] = new ButtonsBlock(); } + } + for (int j = 0; j < count; j++) + { Buttons[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(OwnerData == null || OwnerData.Length != count) { + OwnerData = new OwnerDataBlock[count]; + for(int j = 0; j < count; j++) + { OwnerData[j] = new OwnerDataBlock(); } + } + for (int j = 0; j < count; j++) + { OwnerData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += Data.Length; + length++; + for (int j = 0; j < Buttons.Length; j++) { length += Buttons[j].Length; } + length++; + for (int j = 0; j < OwnerData.Length; j++) { length += OwnerData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + bytes[i++] = (byte)Buttons.Length; + for (int j = 0; j < Buttons.Length; j++) { Buttons[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)OwnerData.Length; + for (int j = 0; j < OwnerData.Length; j++) { OwnerData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += Data.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + Data.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int ButtonsStart = 0; + int OwnerDataStart = 0; + do + { + int variableLength = 0; + int ButtonsCount = 0; + int OwnerDataCount = 0; + + i = ButtonsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Buttons.Length) { + int blockLength = Buttons[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ButtonsCount; + } + else { break; } + ++i; + } + + i = OwnerDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < OwnerData.Length) { + int blockLength = OwnerData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++OwnerDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ButtonsCount; + for (i = ButtonsStart; i < ButtonsStart + ButtonsCount; i++) { Buttons[i].ToBytes(packet, ref length); } + ButtonsStart += ButtonsCount; + + packet[length++] = (byte)OwnerDataCount; + for (i = OwnerDataStart; i < OwnerDataStart + OwnerDataCount; i++) { OwnerData[i].ToBytes(packet, ref length); } + OwnerDataStart += OwnerDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ButtonsStart < Buttons.Length || + OwnerDataStart < OwnerData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ScriptDialogReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ObjectID; + public int ChatChannel; + public int ButtonIndex; + public byte[] ButtonLabel; + + public override int Length + { + get + { + int length = 25; + if (ButtonLabel != null) { length += ButtonLabel.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectID.FromBytes(bytes, i); i += 16; + ChatChannel = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ButtonIndex = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + ButtonLabel = new byte[length]; + Buffer.BlockCopy(bytes, i, ButtonLabel, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(ChatChannel, bytes, i); i += 4; + Utils.IntToBytes(ButtonIndex, bytes, i); i += 4; + bytes[i++] = (byte)ButtonLabel.Length; + Buffer.BlockCopy(ButtonLabel, 0, bytes, i, ButtonLabel.Length); i += ButtonLabel.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ScriptDialogReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.ScriptDialogReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 191; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ScriptDialogReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ScriptDialogReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ForceScriptControlReleasePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public ForceScriptControlReleasePacket() + { + HasVariableBlocks = false; + Type = PacketType.ForceScriptControlRelease; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 192; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public ForceScriptControlReleasePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public ForceScriptControlReleasePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RevokePermissionsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ObjectID; + public uint ObjectPermissions; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + ObjectPermissions = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(ObjectPermissions, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public RevokePermissionsPacket() + { + HasVariableBlocks = false; + Type = PacketType.RevokePermissions; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 193; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public RevokePermissionsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public RevokePermissionsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LoadURLPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public byte[] ObjectName; + public UUID ObjectID; + public UUID OwnerID; + public bool OwnerIsGroup; + public byte[] Message; + public byte[] URL; + + public override int Length + { + get + { + int length = 36; + if (ObjectName != null) { length += ObjectName.Length; } + if (Message != null) { length += Message.Length; } + if (URL != null) { length += URL.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + ObjectName = new byte[length]; + Buffer.BlockCopy(bytes, i, ObjectName, 0, length); i += length; + ObjectID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + OwnerIsGroup = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + length = bytes[i++]; + URL = new byte[length]; + Buffer.BlockCopy(bytes, i, URL, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)ObjectName.Length; + Buffer.BlockCopy(ObjectName, 0, bytes, i, ObjectName.Length); i += ObjectName.Length; + ObjectID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((OwnerIsGroup) ? 1 : 0); + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + bytes[i++] = (byte)URL.Length; + Buffer.BlockCopy(URL, 0, bytes, i, URL.Length); i += URL.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Data.Length; + return length; + } + } + public DataBlock Data; + + public LoadURLPacket() + { + HasVariableBlocks = false; + Type = PacketType.LoadURL; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 194; + Header.Reliable = true; + Data = new DataBlock(); + } + + public LoadURLPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Data.FromBytes(bytes, ref i); + } + + public LoadURLPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ScriptTeleportRequestPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public byte[] ObjectName; + public byte[] SimName; + public Vector3 SimPosition; + public Vector3 LookAt; + + public override int Length + { + get + { + int length = 26; + if (ObjectName != null) { length += ObjectName.Length; } + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + ObjectName = new byte[length]; + Buffer.BlockCopy(bytes, i, ObjectName, 0, length); i += length; + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + SimPosition.FromBytes(bytes, i); i += 12; + LookAt.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)ObjectName.Length; + Buffer.BlockCopy(ObjectName, 0, bytes, i, ObjectName.Length); i += ObjectName.Length; + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + SimPosition.ToBytes(bytes, i); i += 12; + LookAt.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Data.Length; + return length; + } + } + public DataBlock Data; + + public ScriptTeleportRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ScriptTeleportRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 195; + Header.Reliable = true; + Data = new DataBlock(); + } + + public ScriptTeleportRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Data.FromBytes(bytes, ref i); + } + + public ScriptTeleportRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelOverlayPacket : Packet + { + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int SequenceID; + public byte[] Data; + + public override int Length + { + get + { + int length = 6; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + SequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(SequenceID, bytes, i); i += 4; + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ParcelData.Length; + return length; + } + } + public ParcelDataBlock ParcelData; + + public ParcelOverlayPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelOverlay; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 196; + Header.Reliable = true; + Header.Zerocoded = true; + ParcelData = new ParcelDataBlock(); + } + + public ParcelOverlayPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelOverlayPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelPropertiesRequestByIDPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int SequenceID; + public int LocalID; + + public override int Length + { + get + { + return 8; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(SequenceID, bytes, i); i += 4; + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelPropertiesRequestByIDPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelPropertiesRequestByID; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 197; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelPropertiesRequestByIDPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelPropertiesRequestByIDPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelPropertiesUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + public uint Flags; + public uint ParcelFlags; + public int SalePrice; + public byte[] Name; + public byte[] Desc; + public byte[] MusicURL; + public byte[] MediaURL; + public UUID MediaID; + public byte MediaAutoScale; + public UUID GroupID; + public int PassPrice; + public float PassHours; + public byte Category; + public UUID AuthBuyerID; + public UUID SnapshotID; + public Vector3 UserLocation; + public Vector3 UserLookAt; + public byte LandingType; + + public override int Length + { + get + { + int length = 119; + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + if (MusicURL != null) { length += MusicURL.Length; } + if (MediaURL != null) { length += MediaURL.Length; } + return length; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParcelFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + length = bytes[i++]; + MusicURL = new byte[length]; + Buffer.BlockCopy(bytes, i, MusicURL, 0, length); i += length; + length = bytes[i++]; + MediaURL = new byte[length]; + Buffer.BlockCopy(bytes, i, MediaURL, 0, length); i += length; + MediaID.FromBytes(bytes, i); i += 16; + MediaAutoScale = (byte)bytes[i++]; + GroupID.FromBytes(bytes, i); i += 16; + PassPrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PassHours = Utils.BytesToFloat(bytes, i); i += 4; + Category = (byte)bytes[i++]; + AuthBuyerID.FromBytes(bytes, i); i += 16; + SnapshotID.FromBytes(bytes, i); i += 16; + UserLocation.FromBytes(bytes, i); i += 12; + UserLookAt.FromBytes(bytes, i); i += 12; + LandingType = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.UIntToBytes(ParcelFlags, bytes, i); i += 4; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Desc.Length; + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + bytes[i++] = (byte)MusicURL.Length; + Buffer.BlockCopy(MusicURL, 0, bytes, i, MusicURL.Length); i += MusicURL.Length; + bytes[i++] = (byte)MediaURL.Length; + Buffer.BlockCopy(MediaURL, 0, bytes, i, MediaURL.Length); i += MediaURL.Length; + MediaID.ToBytes(bytes, i); i += 16; + bytes[i++] = MediaAutoScale; + GroupID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(PassPrice, bytes, i); i += 4; + Utils.FloatToBytes(PassHours, bytes, i); i += 4; + bytes[i++] = Category; + AuthBuyerID.ToBytes(bytes, i); i += 16; + SnapshotID.ToBytes(bytes, i); i += 16; + UserLocation.ToBytes(bytes, i); i += 12; + UserLookAt.ToBytes(bytes, i); i += 12; + bytes[i++] = LandingType; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelPropertiesUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelPropertiesUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 198; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelPropertiesUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelPropertiesUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelReturnObjectsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + public uint ReturnType; + + public override int Length + { + get + { + return 8; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ReturnType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + Utils.UIntToBytes(ReturnType, bytes, i); i += 4; + } + + } + + /// + public sealed class TaskIDsBlock : PacketBlock + { + public UUID TaskID; + + public override int Length + { + get + { + return 16; + } + } + + public TaskIDsBlock() { } + public TaskIDsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TaskID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TaskID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class OwnerIDsBlock : PacketBlock + { + public UUID OwnerID; + + public override int Length + { + get + { + return 16; + } + } + + public OwnerIDsBlock() { } + public OwnerIDsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OwnerID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + length += ParcelData.Length; + for (int j = 0; j < TaskIDs.Length; j++) + length += TaskIDs[j].Length; + for (int j = 0; j < OwnerIDs.Length; j++) + length += OwnerIDs[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + public TaskIDsBlock[] TaskIDs; + public OwnerIDsBlock[] OwnerIDs; + + public ParcelReturnObjectsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ParcelReturnObjects; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 199; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + TaskIDs = null; + OwnerIDs = null; + } + + public ParcelReturnObjectsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(TaskIDs == null || TaskIDs.Length != -1) { + TaskIDs = new TaskIDsBlock[count]; + for(int j = 0; j < count; j++) + { TaskIDs[j] = new TaskIDsBlock(); } + } + for (int j = 0; j < count; j++) + { TaskIDs[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(OwnerIDs == null || OwnerIDs.Length != -1) { + OwnerIDs = new OwnerIDsBlock[count]; + for(int j = 0; j < count; j++) + { OwnerIDs[j] = new OwnerIDsBlock(); } + } + for (int j = 0; j < count; j++) + { OwnerIDs[j].FromBytes(bytes, ref i); } + } + + public ParcelReturnObjectsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(TaskIDs == null || TaskIDs.Length != count) { + TaskIDs = new TaskIDsBlock[count]; + for(int j = 0; j < count; j++) + { TaskIDs[j] = new TaskIDsBlock(); } + } + for (int j = 0; j < count; j++) + { TaskIDs[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(OwnerIDs == null || OwnerIDs.Length != count) { + OwnerIDs = new OwnerIDsBlock[count]; + for(int j = 0; j < count; j++) + { OwnerIDs[j] = new OwnerIDsBlock(); } + } + for (int j = 0; j < count; j++) + { OwnerIDs[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + length++; + for (int j = 0; j < TaskIDs.Length; j++) { length += TaskIDs[j].Length; } + length++; + for (int j = 0; j < OwnerIDs.Length; j++) { length += OwnerIDs[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + bytes[i++] = (byte)TaskIDs.Length; + for (int j = 0; j < TaskIDs.Length; j++) { TaskIDs[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)OwnerIDs.Length; + for (int j = 0; j < OwnerIDs.Length; j++) { OwnerIDs[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += ParcelData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + ParcelData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int TaskIDsStart = 0; + int OwnerIDsStart = 0; + do + { + int variableLength = 0; + int TaskIDsCount = 0; + int OwnerIDsCount = 0; + + i = TaskIDsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < TaskIDs.Length) { + int blockLength = TaskIDs[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++TaskIDsCount; + } + else { break; } + ++i; + } + + i = OwnerIDsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < OwnerIDs.Length) { + int blockLength = OwnerIDs[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++OwnerIDsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)TaskIDsCount; + for (i = TaskIDsStart; i < TaskIDsStart + TaskIDsCount; i++) { TaskIDs[i].ToBytes(packet, ref length); } + TaskIDsStart += TaskIDsCount; + + packet[length++] = (byte)OwnerIDsCount; + for (i = OwnerIDsStart; i < OwnerIDsStart + OwnerIDsCount; i++) { OwnerIDs[i].ToBytes(packet, ref length); } + OwnerIDsStart += OwnerIDsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + TaskIDsStart < TaskIDs.Length || + OwnerIDsStart < OwnerIDs.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ParcelSetOtherCleanTimePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + public int OtherCleanTime; + + public override int Length + { + get + { + return 8; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OtherCleanTime = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + Utils.IntToBytes(OtherCleanTime, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelSetOtherCleanTimePacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelSetOtherCleanTime; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 200; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelSetOtherCleanTimePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelSetOtherCleanTimePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelDisableObjectsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + public uint ReturnType; + + public override int Length + { + get + { + return 8; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ReturnType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + Utils.UIntToBytes(ReturnType, bytes, i); i += 4; + } + + } + + /// + public sealed class TaskIDsBlock : PacketBlock + { + public UUID TaskID; + + public override int Length + { + get + { + return 16; + } + } + + public TaskIDsBlock() { } + public TaskIDsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TaskID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TaskID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class OwnerIDsBlock : PacketBlock + { + public UUID OwnerID; + + public override int Length + { + get + { + return 16; + } + } + + public OwnerIDsBlock() { } + public OwnerIDsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OwnerID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + length += ParcelData.Length; + for (int j = 0; j < TaskIDs.Length; j++) + length += TaskIDs[j].Length; + for (int j = 0; j < OwnerIDs.Length; j++) + length += OwnerIDs[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + public TaskIDsBlock[] TaskIDs; + public OwnerIDsBlock[] OwnerIDs; + + public ParcelDisableObjectsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ParcelDisableObjects; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 201; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + TaskIDs = null; + OwnerIDs = null; + } + + public ParcelDisableObjectsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(TaskIDs == null || TaskIDs.Length != -1) { + TaskIDs = new TaskIDsBlock[count]; + for(int j = 0; j < count; j++) + { TaskIDs[j] = new TaskIDsBlock(); } + } + for (int j = 0; j < count; j++) + { TaskIDs[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(OwnerIDs == null || OwnerIDs.Length != -1) { + OwnerIDs = new OwnerIDsBlock[count]; + for(int j = 0; j < count; j++) + { OwnerIDs[j] = new OwnerIDsBlock(); } + } + for (int j = 0; j < count; j++) + { OwnerIDs[j].FromBytes(bytes, ref i); } + } + + public ParcelDisableObjectsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(TaskIDs == null || TaskIDs.Length != count) { + TaskIDs = new TaskIDsBlock[count]; + for(int j = 0; j < count; j++) + { TaskIDs[j] = new TaskIDsBlock(); } + } + for (int j = 0; j < count; j++) + { TaskIDs[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(OwnerIDs == null || OwnerIDs.Length != count) { + OwnerIDs = new OwnerIDsBlock[count]; + for(int j = 0; j < count; j++) + { OwnerIDs[j] = new OwnerIDsBlock(); } + } + for (int j = 0; j < count; j++) + { OwnerIDs[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + length++; + for (int j = 0; j < TaskIDs.Length; j++) { length += TaskIDs[j].Length; } + length++; + for (int j = 0; j < OwnerIDs.Length; j++) { length += OwnerIDs[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + bytes[i++] = (byte)TaskIDs.Length; + for (int j = 0; j < TaskIDs.Length; j++) { TaskIDs[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)OwnerIDs.Length; + for (int j = 0; j < OwnerIDs.Length; j++) { OwnerIDs[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += ParcelData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + ParcelData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int TaskIDsStart = 0; + int OwnerIDsStart = 0; + do + { + int variableLength = 0; + int TaskIDsCount = 0; + int OwnerIDsCount = 0; + + i = TaskIDsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < TaskIDs.Length) { + int blockLength = TaskIDs[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++TaskIDsCount; + } + else { break; } + ++i; + } + + i = OwnerIDsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < OwnerIDs.Length) { + int blockLength = OwnerIDs[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++OwnerIDsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)TaskIDsCount; + for (i = TaskIDsStart; i < TaskIDsStart + TaskIDsCount; i++) { TaskIDs[i].ToBytes(packet, ref length); } + TaskIDsStart += TaskIDsCount; + + packet[length++] = (byte)OwnerIDsCount; + for (i = OwnerIDsStart; i < OwnerIDsStart + OwnerIDsCount; i++) { OwnerIDs[i].ToBytes(packet, ref length); } + OwnerIDsStart += OwnerIDsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + TaskIDsStart < TaskIDs.Length || + OwnerIDsStart < OwnerIDs.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ParcelSelectObjectsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + public uint ReturnType; + + public override int Length + { + get + { + return 8; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ReturnType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + Utils.UIntToBytes(ReturnType, bytes, i); i += 4; + } + + } + + /// + public sealed class ReturnIDsBlock : PacketBlock + { + public UUID ReturnID; + + public override int Length + { + get + { + return 16; + } + } + + public ReturnIDsBlock() { } + public ReturnIDsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ReturnID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ReturnID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += ParcelData.Length; + for (int j = 0; j < ReturnIDs.Length; j++) + length += ReturnIDs[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + public ReturnIDsBlock[] ReturnIDs; + + public ParcelSelectObjectsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ParcelSelectObjects; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 202; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + ReturnIDs = null; + } + + public ParcelSelectObjectsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ReturnIDs == null || ReturnIDs.Length != -1) { + ReturnIDs = new ReturnIDsBlock[count]; + for(int j = 0; j < count; j++) + { ReturnIDs[j] = new ReturnIDsBlock(); } + } + for (int j = 0; j < count; j++) + { ReturnIDs[j].FromBytes(bytes, ref i); } + } + + public ParcelSelectObjectsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ReturnIDs == null || ReturnIDs.Length != count) { + ReturnIDs = new ReturnIDsBlock[count]; + for(int j = 0; j < count; j++) + { ReturnIDs[j] = new ReturnIDsBlock(); } + } + for (int j = 0; j < count; j++) + { ReturnIDs[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + length++; + for (int j = 0; j < ReturnIDs.Length; j++) { length += ReturnIDs[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ReturnIDs.Length; + for (int j = 0; j < ReturnIDs.Length; j++) { ReturnIDs[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += ParcelData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + ParcelData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ReturnIDsStart = 0; + do + { + int variableLength = 0; + int ReturnIDsCount = 0; + + i = ReturnIDsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ReturnIDs.Length) { + int blockLength = ReturnIDs[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ReturnIDsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ReturnIDsCount; + for (i = ReturnIDsStart; i < ReturnIDsStart + ReturnIDsCount; i++) { ReturnIDs[i].ToBytes(packet, ref length); } + ReturnIDsStart += ReturnIDsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ReturnIDsStart < ReturnIDs.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class EstateCovenantRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public EstateCovenantRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.EstateCovenantRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 203; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public EstateCovenantRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public EstateCovenantRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EstateCovenantReplyPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public UUID CovenantID; + public uint CovenantTimestamp; + public byte[] EstateName; + public UUID EstateOwnerID; + + public override int Length + { + get + { + int length = 37; + if (EstateName != null) { length += EstateName.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + CovenantID.FromBytes(bytes, i); i += 16; + CovenantTimestamp = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + EstateName = new byte[length]; + Buffer.BlockCopy(bytes, i, EstateName, 0, length); i += length; + EstateOwnerID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + CovenantID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CovenantTimestamp, bytes, i); i += 4; + bytes[i++] = (byte)EstateName.Length; + Buffer.BlockCopy(EstateName, 0, bytes, i, EstateName.Length); i += EstateName.Length; + EstateOwnerID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Data.Length; + return length; + } + } + public DataBlock Data; + + public EstateCovenantReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.EstateCovenantReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 204; + Header.Reliable = true; + Data = new DataBlock(); + } + + public EstateCovenantReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Data.FromBytes(bytes, ref i); + } + + public EstateCovenantReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ForceObjectSelectPacket : Packet + { + /// + public sealed class HeaderBlock : PacketBlock + { + public bool ResetList; + + public override int Length + { + get + { + return 1; + } + } + + public HeaderBlock() { } + public HeaderBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ResetList = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((ResetList) ? 1 : 0); + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public uint LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += _Header.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public HeaderBlock _Header; + public DataBlock[] Data; + + public ForceObjectSelectPacket() + { + HasVariableBlocks = true; + Type = PacketType.ForceObjectSelect; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 205; + Header.Reliable = true; + _Header = new HeaderBlock(); + Data = null; + } + + public ForceObjectSelectPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + _Header.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public ForceObjectSelectPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + _Header.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += _Header.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + _Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += _Header.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + _Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ParcelBuyPassPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelBuyPassPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelBuyPass; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 206; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelBuyPassPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelBuyPassPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelDeedToGroupPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID GroupID; + public int LocalID; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelDeedToGroupPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelDeedToGroup; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 207; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelDeedToGroupPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelDeedToGroupPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelReclaimPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public int LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelReclaimPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelReclaim; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 208; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelReclaimPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelReclaimPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelClaimPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID GroupID; + public bool IsGroupOwned; + public bool Final; + + public override int Length + { + get + { + return 18; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + IsGroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + Final = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsGroupOwned) ? 1 : 0); + bytes[i++] = (byte)((Final) ? 1 : 0); + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public float West; + public float South; + public float East; + public float North; + + public override int Length + { + get + { + return 16; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + West = Utils.BytesToFloat(bytes, i); i += 4; + South = Utils.BytesToFloat(bytes, i); i += 4; + East = Utils.BytesToFloat(bytes, i); i += 4; + North = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.FloatToBytes(West, bytes, i); i += 4; + Utils.FloatToBytes(South, bytes, i); i += 4; + Utils.FloatToBytes(East, bytes, i); i += 4; + Utils.FloatToBytes(North, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += Data.Length; + for (int j = 0; j < ParcelData.Length; j++) + length += ParcelData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + public ParcelDataBlock[] ParcelData; + + public ParcelClaimPacket() + { + HasVariableBlocks = true; + Type = PacketType.ParcelClaim; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 209; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + ParcelData = null; + } + + public ParcelClaimPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParcelData == null || ParcelData.Length != -1) { + ParcelData = new ParcelDataBlock[count]; + for(int j = 0; j < count; j++) + { ParcelData[j] = new ParcelDataBlock(); } + } + for (int j = 0; j < count; j++) + { ParcelData[j].FromBytes(bytes, ref i); } + } + + public ParcelClaimPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParcelData == null || ParcelData.Length != count) { + ParcelData = new ParcelDataBlock[count]; + for(int j = 0; j < count; j++) + { ParcelData[j] = new ParcelDataBlock(); } + } + for (int j = 0; j < count; j++) + { ParcelData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length++; + for (int j = 0; j < ParcelData.Length; j++) { length += ParcelData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + bytes[i++] = (byte)ParcelData.Length; + for (int j = 0; j < ParcelData.Length; j++) { ParcelData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += Data.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + Data.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ParcelDataStart = 0; + do + { + int variableLength = 0; + int ParcelDataCount = 0; + + i = ParcelDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ParcelData.Length) { + int blockLength = ParcelData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ParcelDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ParcelDataCount; + for (i = ParcelDataStart; i < ParcelDataStart + ParcelDataCount; i++) { ParcelData[i].ToBytes(packet, ref length); } + ParcelDataStart += ParcelDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ParcelDataStart < ParcelData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ParcelJoinPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public float West; + public float South; + public float East; + public float North; + + public override int Length + { + get + { + return 16; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + West = Utils.BytesToFloat(bytes, i); i += 4; + South = Utils.BytesToFloat(bytes, i); i += 4; + East = Utils.BytesToFloat(bytes, i); i += 4; + North = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.FloatToBytes(West, bytes, i); i += 4; + Utils.FloatToBytes(South, bytes, i); i += 4; + Utils.FloatToBytes(East, bytes, i); i += 4; + Utils.FloatToBytes(North, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelJoinPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelJoin; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 210; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelJoinPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelJoinPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelDividePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public float West; + public float South; + public float East; + public float North; + + public override int Length + { + get + { + return 16; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + West = Utils.BytesToFloat(bytes, i); i += 4; + South = Utils.BytesToFloat(bytes, i); i += 4; + East = Utils.BytesToFloat(bytes, i); i += 4; + North = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.FloatToBytes(West, bytes, i); i += 4; + Utils.FloatToBytes(South, bytes, i); i += 4; + Utils.FloatToBytes(East, bytes, i); i += 4; + Utils.FloatToBytes(North, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelDividePacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelDivide; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 211; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelDividePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelDividePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelReleasePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public int LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelReleasePacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelRelease; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 212; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelReleasePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelReleasePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelBuyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID GroupID; + public bool IsGroupOwned; + public bool RemoveContribution; + public int LocalID; + public bool Final; + + public override int Length + { + get + { + return 23; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + IsGroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + RemoveContribution = (bytes[i++] != 0) ? (bool)true : (bool)false; + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Final = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsGroupOwned) ? 1 : 0); + bytes[i++] = (byte)((RemoveContribution) ? 1 : 0); + Utils.IntToBytes(LocalID, bytes, i); i += 4; + bytes[i++] = (byte)((Final) ? 1 : 0); + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int Price; + public int Area; + + public override int Length + { + get + { + return 8; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Price = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Area = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(Price, bytes, i); i += 4; + Utils.IntToBytes(Area, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + public ParcelDataBlock ParcelData; + + public ParcelBuyPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelBuy; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 213; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelBuyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelBuyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelGodForceOwnerPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID OwnerID; + public int LocalID; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OwnerID.FromBytes(bytes, i); i += 16; + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelGodForceOwnerPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelGodForceOwner; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 214; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelGodForceOwnerPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelGodForceOwnerPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelAccessListRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public int SequenceID; + public uint Flags; + public int LocalID; + + public override int Length + { + get + { + return 12; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(SequenceID, bytes, i); i += 4; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelAccessListRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelAccessListRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 215; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelAccessListRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelAccessListRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelAccessListReplyPacket : Packet + { + /// + public sealed class DataBlock : PacketBlock + { + public UUID AgentID; + public int SequenceID; + public uint Flags; + public int LocalID; + + public override int Length + { + get + { + return 28; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(SequenceID, bytes, i); i += 4; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + /// + public sealed class ListBlock : PacketBlock + { + public UUID ID; + public int Time; + public uint Flags; + + public override int Length + { + get + { + return 24; + } + } + + public ListBlock() { } + public ListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + Time = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Time, bytes, i); i += 4; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += Data.Length; + for (int j = 0; j < List.Length; j++) + length += List[j].Length; + return length; + } + } + public DataBlock Data; + public ListBlock[] List; + + public ParcelAccessListReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.ParcelAccessListReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 216; + Header.Reliable = true; + Header.Zerocoded = true; + Data = new DataBlock(); + List = null; + } + + public ParcelAccessListReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(List == null || List.Length != -1) { + List = new ListBlock[count]; + for(int j = 0; j < count; j++) + { List[j] = new ListBlock(); } + } + for (int j = 0; j < count; j++) + { List[j].FromBytes(bytes, ref i); } + } + + public ParcelAccessListReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(List == null || List.Length != count) { + List = new ListBlock[count]; + for(int j = 0; j < count; j++) + { List[j] = new ListBlock(); } + } + for (int j = 0; j < count; j++) + { List[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += Data.Length; + length++; + for (int j = 0; j < List.Length; j++) { length += List[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + bytes[i++] = (byte)List.Length; + for (int j = 0; j < List.Length; j++) { List[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += Data.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + Data.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ListStart = 0; + do + { + int variableLength = 0; + int ListCount = 0; + + i = ListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < List.Length) { + int blockLength = List[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ListCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ListCount; + for (i = ListStart; i < ListStart + ListCount; i++) { List[i].ToBytes(packet, ref length); } + ListStart += ListCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ListStart < List.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ParcelAccessListUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public uint Flags; + public int LocalID; + public UUID TransactionID; + public int SequenceID; + public int Sections; + + public override int Length + { + get + { + return 32; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TransactionID.FromBytes(bytes, i); i += 16; + SequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Sections = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.IntToBytes(LocalID, bytes, i); i += 4; + TransactionID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(SequenceID, bytes, i); i += 4; + Utils.IntToBytes(Sections, bytes, i); i += 4; + } + + } + + /// + public sealed class ListBlock : PacketBlock + { + public UUID ID; + public int Time; + public uint Flags; + + public override int Length + { + get + { + return 24; + } + } + + public ListBlock() { } + public ListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + Time = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Time, bytes, i); i += 4; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += Data.Length; + for (int j = 0; j < List.Length; j++) + length += List[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + public ListBlock[] List; + + public ParcelAccessListUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.ParcelAccessListUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 217; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + List = null; + } + + public ParcelAccessListUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(List == null || List.Length != -1) { + List = new ListBlock[count]; + for(int j = 0; j < count; j++) + { List[j] = new ListBlock(); } + } + for (int j = 0; j < count; j++) + { List[j].FromBytes(bytes, ref i); } + } + + public ParcelAccessListUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(List == null || List.Length != count) { + List = new ListBlock[count]; + for(int j = 0; j < count; j++) + { List[j] = new ListBlock(); } + } + for (int j = 0; j < count; j++) + { List[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length++; + for (int j = 0; j < List.Length; j++) { length += List[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + bytes[i++] = (byte)List.Length; + for (int j = 0; j < List.Length; j++) { List[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += Data.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + Data.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ListStart = 0; + do + { + int variableLength = 0; + int ListCount = 0; + + i = ListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < List.Length) { + int blockLength = List[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ListCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ListCount; + for (i = ListStart; i < ListStart + ListCount; i++) { List[i].ToBytes(packet, ref length); } + ListStart += ListCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ListStart < List.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ParcelDwellRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public int LocalID; + public UUID ParcelID; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParcelID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + ParcelID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelDwellRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelDwellRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 218; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelDwellRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelDwellRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelDwellReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public int LocalID; + public UUID ParcelID; + public float Dwell; + + public override int Length + { + get + { + return 24; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParcelID.FromBytes(bytes, i); i += 16; + Dwell = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + ParcelID.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(Dwell, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ParcelDwellReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelDwellReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 219; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ParcelDwellReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ParcelDwellReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelGodMarkAsContentPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelGodMarkAsContentPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelGodMarkAsContent; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 227; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelGodMarkAsContentPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelGodMarkAsContentPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ViewerStartAuctionPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int LocalID; + public UUID SnapshotID; + + public override int Length + { + get + { + return 20; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SnapshotID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(LocalID, bytes, i); i += 4; + SnapshotID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ViewerStartAuctionPacket() + { + HasVariableBlocks = false; + Type = PacketType.ViewerStartAuction; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 228; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ViewerStartAuctionPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ViewerStartAuctionPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UUIDNameRequestPacket : Packet + { + /// + public sealed class UUIDNameBlockBlock : PacketBlock + { + public UUID ID; + + public override int Length + { + get + { + return 16; + } + } + + public UUIDNameBlockBlock() { } + public UUIDNameBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < UUIDNameBlock.Length; j++) + length += UUIDNameBlock[j].Length; + return length; + } + } + public UUIDNameBlockBlock[] UUIDNameBlock; + + public UUIDNameRequestPacket() + { + HasVariableBlocks = true; + Type = PacketType.UUIDNameRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 235; + Header.Reliable = true; + UUIDNameBlock = null; + } + + public UUIDNameRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != -1) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public UUIDNameRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != count) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < UUIDNameBlock.Length; j++) { length += UUIDNameBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)UUIDNameBlock.Length; + for (int j = 0; j < UUIDNameBlock.Length; j++) { UUIDNameBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int UUIDNameBlockStart = 0; + do + { + int variableLength = 0; + int UUIDNameBlockCount = 0; + + i = UUIDNameBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < UUIDNameBlock.Length) { + int blockLength = UUIDNameBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++UUIDNameBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)UUIDNameBlockCount; + for (i = UUIDNameBlockStart; i < UUIDNameBlockStart + UUIDNameBlockCount; i++) { UUIDNameBlock[i].ToBytes(packet, ref length); } + UUIDNameBlockStart += UUIDNameBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + UUIDNameBlockStart < UUIDNameBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UUIDNameReplyPacket : Packet + { + /// + public sealed class UUIDNameBlockBlock : PacketBlock + { + public UUID ID; + public byte[] FirstName; + public byte[] LastName; + + public override int Length + { + get + { + int length = 18; + if (FirstName != null) { length += FirstName.Length; } + if (LastName != null) { length += LastName.Length; } + return length; + } + } + + public UUIDNameBlockBlock() { } + public UUIDNameBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + FirstName = new byte[length]; + Buffer.BlockCopy(bytes, i, FirstName, 0, length); i += length; + length = bytes[i++]; + LastName = new byte[length]; + Buffer.BlockCopy(bytes, i, LastName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)FirstName.Length; + Buffer.BlockCopy(FirstName, 0, bytes, i, FirstName.Length); i += FirstName.Length; + bytes[i++] = (byte)LastName.Length; + Buffer.BlockCopy(LastName, 0, bytes, i, LastName.Length); i += LastName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < UUIDNameBlock.Length; j++) + length += UUIDNameBlock[j].Length; + return length; + } + } + public UUIDNameBlockBlock[] UUIDNameBlock; + + public UUIDNameReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.UUIDNameReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 236; + Header.Reliable = true; + UUIDNameBlock = null; + } + + public UUIDNameReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != -1) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public UUIDNameReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != count) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < UUIDNameBlock.Length; j++) { length += UUIDNameBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)UUIDNameBlock.Length; + for (int j = 0; j < UUIDNameBlock.Length; j++) { UUIDNameBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int UUIDNameBlockStart = 0; + do + { + int variableLength = 0; + int UUIDNameBlockCount = 0; + + i = UUIDNameBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < UUIDNameBlock.Length) { + int blockLength = UUIDNameBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++UUIDNameBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)UUIDNameBlockCount; + for (i = UUIDNameBlockStart; i < UUIDNameBlockStart + UUIDNameBlockCount; i++) { UUIDNameBlock[i].ToBytes(packet, ref length); } + UUIDNameBlockStart += UUIDNameBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + UUIDNameBlockStart < UUIDNameBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UUIDGroupNameRequestPacket : Packet + { + /// + public sealed class UUIDNameBlockBlock : PacketBlock + { + public UUID ID; + + public override int Length + { + get + { + return 16; + } + } + + public UUIDNameBlockBlock() { } + public UUIDNameBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < UUIDNameBlock.Length; j++) + length += UUIDNameBlock[j].Length; + return length; + } + } + public UUIDNameBlockBlock[] UUIDNameBlock; + + public UUIDGroupNameRequestPacket() + { + HasVariableBlocks = true; + Type = PacketType.UUIDGroupNameRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 237; + Header.Reliable = true; + UUIDNameBlock = null; + } + + public UUIDGroupNameRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != -1) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public UUIDGroupNameRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != count) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < UUIDNameBlock.Length; j++) { length += UUIDNameBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)UUIDNameBlock.Length; + for (int j = 0; j < UUIDNameBlock.Length; j++) { UUIDNameBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int UUIDNameBlockStart = 0; + do + { + int variableLength = 0; + int UUIDNameBlockCount = 0; + + i = UUIDNameBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < UUIDNameBlock.Length) { + int blockLength = UUIDNameBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++UUIDNameBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)UUIDNameBlockCount; + for (i = UUIDNameBlockStart; i < UUIDNameBlockStart + UUIDNameBlockCount; i++) { UUIDNameBlock[i].ToBytes(packet, ref length); } + UUIDNameBlockStart += UUIDNameBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + UUIDNameBlockStart < UUIDNameBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UUIDGroupNameReplyPacket : Packet + { + /// + public sealed class UUIDNameBlockBlock : PacketBlock + { + public UUID ID; + public byte[] GroupName; + + public override int Length + { + get + { + int length = 17; + if (GroupName != null) { length += GroupName.Length; } + return length; + } + } + + public UUIDNameBlockBlock() { } + public UUIDNameBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + GroupName = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)GroupName.Length; + Buffer.BlockCopy(GroupName, 0, bytes, i, GroupName.Length); i += GroupName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < UUIDNameBlock.Length; j++) + length += UUIDNameBlock[j].Length; + return length; + } + } + public UUIDNameBlockBlock[] UUIDNameBlock; + + public UUIDGroupNameReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.UUIDGroupNameReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 238; + Header.Reliable = true; + UUIDNameBlock = null; + } + + public UUIDGroupNameReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != -1) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public UUIDGroupNameReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(UUIDNameBlock == null || UUIDNameBlock.Length != count) { + UUIDNameBlock = new UUIDNameBlockBlock[count]; + for(int j = 0; j < count; j++) + { UUIDNameBlock[j] = new UUIDNameBlockBlock(); } + } + for (int j = 0; j < count; j++) + { UUIDNameBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < UUIDNameBlock.Length; j++) { length += UUIDNameBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)UUIDNameBlock.Length; + for (int j = 0; j < UUIDNameBlock.Length; j++) { UUIDNameBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int UUIDNameBlockStart = 0; + do + { + int variableLength = 0; + int UUIDNameBlockCount = 0; + + i = UUIDNameBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < UUIDNameBlock.Length) { + int blockLength = UUIDNameBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++UUIDNameBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)UUIDNameBlockCount; + for (i = UUIDNameBlockStart; i < UUIDNameBlockStart + UUIDNameBlockCount; i++) { UUIDNameBlock[i].ToBytes(packet, ref length); } + UUIDNameBlockStart += UUIDNameBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + UUIDNameBlockStart < UUIDNameBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ChildAgentDyingPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public ChildAgentDyingPacket() + { + HasVariableBlocks = false; + Type = PacketType.ChildAgentDying; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 240; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + } + + public ChildAgentDyingPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public ChildAgentDyingPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ChildAgentUnknownPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public ChildAgentUnknownPacket() + { + HasVariableBlocks = false; + Type = PacketType.ChildAgentUnknown; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 241; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public ChildAgentUnknownPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public ChildAgentUnknownPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GetScriptRunningPacket : Packet + { + /// + public sealed class ScriptBlock : PacketBlock + { + public UUID ObjectID; + public UUID ItemID; + + public override int Length + { + get + { + return 32; + } + } + + public ScriptBlock() { } + public ScriptBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Script.Length; + return length; + } + } + public ScriptBlock Script; + + public GetScriptRunningPacket() + { + HasVariableBlocks = false; + Type = PacketType.GetScriptRunning; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 243; + Header.Reliable = true; + Script = new ScriptBlock(); + } + + public GetScriptRunningPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Script.FromBytes(bytes, ref i); + } + + public GetScriptRunningPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Script.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Script.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Script.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ScriptRunningReplyPacket : Packet + { + /// + public sealed class ScriptBlock : PacketBlock + { + public UUID ObjectID; + public UUID ItemID; + public bool Running; + + public override int Length + { + get + { + return 33; + } + } + + public ScriptBlock() { } + public ScriptBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + Running = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Running) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += Script.Length; + return length; + } + } + public ScriptBlock Script; + + public ScriptRunningReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.ScriptRunningReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 244; + Header.Reliable = true; + Script = new ScriptBlock(); + } + + public ScriptRunningReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Script.FromBytes(bytes, ref i); + } + + public ScriptRunningReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Script.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Script.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Script.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SetScriptRunningPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ScriptBlock : PacketBlock + { + public UUID ObjectID; + public UUID ItemID; + public bool Running; + + public override int Length + { + get + { + return 33; + } + } + + public ScriptBlock() { } + public ScriptBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + Running = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Running) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Script.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ScriptBlock Script; + + public SetScriptRunningPacket() + { + HasVariableBlocks = false; + Type = PacketType.SetScriptRunning; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 245; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Script = new ScriptBlock(); + } + + public SetScriptRunningPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Script.FromBytes(bytes, ref i); + } + + public SetScriptRunningPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Script.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Script.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Script.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ScriptResetPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ScriptBlock : PacketBlock + { + public UUID ObjectID; + public UUID ItemID; + + public override int Length + { + get + { + return 32; + } + } + + public ScriptBlock() { } + public ScriptBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Script.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ScriptBlock Script; + + public ScriptResetPacket() + { + HasVariableBlocks = false; + Type = PacketType.ScriptReset; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 246; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Script = new ScriptBlock(); + } + + public ScriptResetPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Script.FromBytes(bytes, ref i); + } + + public ScriptResetPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Script.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Script.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Script.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ScriptSensorRequestPacket : Packet + { + /// + public sealed class RequesterBlock : PacketBlock + { + public UUID SourceID; + public UUID RequestID; + public UUID SearchID; + public Vector3 SearchPos; + public Quaternion SearchDir; + public byte[] SearchName; + public int Type; + public float Range; + public float Arc; + public ulong RegionHandle; + public byte SearchRegions; + + public override int Length + { + get + { + int length = 94; + if (SearchName != null) { length += SearchName.Length; } + return length; + } + } + + public RequesterBlock() { } + public RequesterBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + SourceID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + SearchID.FromBytes(bytes, i); i += 16; + SearchPos.FromBytes(bytes, i); i += 12; + SearchDir.FromBytes(bytes, i, true); i += 12; + length = bytes[i++]; + SearchName = new byte[length]; + Buffer.BlockCopy(bytes, i, SearchName, 0, length); i += length; + Type = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Range = Utils.BytesToFloat(bytes, i); i += 4; + Arc = Utils.BytesToFloat(bytes, i); i += 4; + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + SearchRegions = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + SourceID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + SearchID.ToBytes(bytes, i); i += 16; + SearchPos.ToBytes(bytes, i); i += 12; + SearchDir.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)SearchName.Length; + Buffer.BlockCopy(SearchName, 0, bytes, i, SearchName.Length); i += SearchName.Length; + Utils.IntToBytes(Type, bytes, i); i += 4; + Utils.FloatToBytes(Range, bytes, i); i += 4; + Utils.FloatToBytes(Arc, bytes, i); i += 4; + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + bytes[i++] = SearchRegions; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Requester.Length; + return length; + } + } + public RequesterBlock Requester; + + public ScriptSensorRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ScriptSensorRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 247; + Header.Reliable = true; + Header.Zerocoded = true; + Requester = new RequesterBlock(); + } + + public ScriptSensorRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Requester.FromBytes(bytes, ref i); + } + + public ScriptSensorRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Requester.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += Requester.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Requester.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ScriptSensorReplyPacket : Packet + { + /// + public sealed class RequesterBlock : PacketBlock + { + public UUID SourceID; + + public override int Length + { + get + { + return 16; + } + } + + public RequesterBlock() { } + public RequesterBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SourceID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + SourceID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class SensedDataBlock : PacketBlock + { + public UUID ObjectID; + public UUID OwnerID; + public UUID GroupID; + public Vector3 Position; + public Vector3 Velocity; + public Quaternion Rotation; + public byte[] Name; + public int Type; + public float Range; + + public override int Length + { + get + { + int length = 93; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public SensedDataBlock() { } + public SensedDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + Position.FromBytes(bytes, i); i += 12; + Velocity.FromBytes(bytes, i); i += 12; + Rotation.FromBytes(bytes, i, true); i += 12; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + Type = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Range = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Position.ToBytes(bytes, i); i += 12; + Velocity.ToBytes(bytes, i); i += 12; + Rotation.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + Utils.IntToBytes(Type, bytes, i); i += 4; + Utils.FloatToBytes(Range, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += Requester.Length; + for (int j = 0; j < SensedData.Length; j++) + length += SensedData[j].Length; + return length; + } + } + public RequesterBlock Requester; + public SensedDataBlock[] SensedData; + + public ScriptSensorReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.ScriptSensorReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 248; + Header.Reliable = true; + Header.Zerocoded = true; + Requester = new RequesterBlock(); + SensedData = null; + } + + public ScriptSensorReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Requester.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SensedData == null || SensedData.Length != -1) { + SensedData = new SensedDataBlock[count]; + for(int j = 0; j < count; j++) + { SensedData[j] = new SensedDataBlock(); } + } + for (int j = 0; j < count; j++) + { SensedData[j].FromBytes(bytes, ref i); } + } + + public ScriptSensorReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Requester.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(SensedData == null || SensedData.Length != count) { + SensedData = new SensedDataBlock[count]; + for(int j = 0; j < count; j++) + { SensedData[j] = new SensedDataBlock(); } + } + for (int j = 0; j < count; j++) + { SensedData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += Requester.Length; + length++; + for (int j = 0; j < SensedData.Length; j++) { length += SensedData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Requester.ToBytes(bytes, ref i); + bytes[i++] = (byte)SensedData.Length; + for (int j = 0; j < SensedData.Length; j++) { SensedData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += Requester.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + Requester.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int SensedDataStart = 0; + do + { + int variableLength = 0; + int SensedDataCount = 0; + + i = SensedDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < SensedData.Length) { + int blockLength = SensedData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++SensedDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)SensedDataCount; + for (i = SensedDataStart; i < SensedDataStart + SensedDataCount; i++) { SensedData[i].ToBytes(packet, ref length); } + SensedDataStart += SensedDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + SensedDataStart < SensedData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class CompleteAgentMovementPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint CircuitCode; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + CircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CircuitCode, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public CompleteAgentMovementPacket() + { + HasVariableBlocks = false; + Type = PacketType.CompleteAgentMovement; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 249; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public CompleteAgentMovementPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public CompleteAgentMovementPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentMovementCompletePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public Vector3 Position; + public Vector3 LookAt; + public ulong RegionHandle; + public uint Timestamp; + + public override int Length + { + get + { + return 36; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Position.FromBytes(bytes, i); i += 12; + LookAt.FromBytes(bytes, i); i += 12; + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + Timestamp = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Position.ToBytes(bytes, i); i += 12; + LookAt.ToBytes(bytes, i); i += 12; + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + Utils.UIntToBytes(Timestamp, bytes, i); i += 4; + } + + } + + /// + public sealed class SimDataBlock : PacketBlock + { + public byte[] ChannelVersion; + + public override int Length + { + get + { + int length = 2; + if (ChannelVersion != null) { length += ChannelVersion.Length; } + return length; + } + } + + public SimDataBlock() { } + public SimDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + ChannelVersion = new byte[length]; + Buffer.BlockCopy(bytes, i, ChannelVersion, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(ChannelVersion.Length % 256); + bytes[i++] = (byte)((ChannelVersion.Length >> 8) % 256); + Buffer.BlockCopy(ChannelVersion, 0, bytes, i, ChannelVersion.Length); i += ChannelVersion.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length += SimData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + public SimDataBlock SimData; + + public AgentMovementCompletePacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentMovementComplete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 250; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + SimData = new SimDataBlock(); + } + + public AgentMovementCompletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + SimData.FromBytes(bytes, ref i); + } + + public AgentMovementCompletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + SimData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length += SimData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + SimData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LogoutRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public LogoutRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.LogoutRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 252; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public LogoutRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public LogoutRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LogoutReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + + public override int Length + { + get + { + return 16; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public LogoutReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.LogoutReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 253; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public LogoutReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public LogoutReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ImprovedInstantMessagePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MessageBlockBlock : PacketBlock + { + public bool FromGroup; + public UUID ToAgentID; + public uint ParentEstateID; + public UUID RegionID; + public Vector3 Position; + public byte Offline; + public byte Dialog; + public UUID ID; + public uint Timestamp; + public byte[] FromAgentName; + public byte[] Message; + public byte[] BinaryBucket; + + public override int Length + { + get + { + int length = 76; + if (FromAgentName != null) { length += FromAgentName.Length; } + if (Message != null) { length += Message.Length; } + if (BinaryBucket != null) { length += BinaryBucket.Length; } + return length; + } + } + + public MessageBlockBlock() { } + public MessageBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + FromGroup = (bytes[i++] != 0) ? (bool)true : (bool)false; + ToAgentID.FromBytes(bytes, i); i += 16; + ParentEstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RegionID.FromBytes(bytes, i); i += 16; + Position.FromBytes(bytes, i); i += 12; + Offline = (byte)bytes[i++]; + Dialog = (byte)bytes[i++]; + ID.FromBytes(bytes, i); i += 16; + Timestamp = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + FromAgentName = new byte[length]; + Buffer.BlockCopy(bytes, i, FromAgentName, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + BinaryBucket = new byte[length]; + Buffer.BlockCopy(bytes, i, BinaryBucket, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((FromGroup) ? 1 : 0); + ToAgentID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(ParentEstateID, bytes, i); i += 4; + RegionID.ToBytes(bytes, i); i += 16; + Position.ToBytes(bytes, i); i += 12; + bytes[i++] = Offline; + bytes[i++] = Dialog; + ID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Timestamp, bytes, i); i += 4; + bytes[i++] = (byte)FromAgentName.Length; + Buffer.BlockCopy(FromAgentName, 0, bytes, i, FromAgentName.Length); i += FromAgentName.Length; + bytes[i++] = (byte)(Message.Length % 256); + bytes[i++] = (byte)((Message.Length >> 8) % 256); + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + bytes[i++] = (byte)(BinaryBucket.Length % 256); + bytes[i++] = (byte)((BinaryBucket.Length >> 8) % 256); + Buffer.BlockCopy(BinaryBucket, 0, bytes, i, BinaryBucket.Length); i += BinaryBucket.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MessageBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MessageBlockBlock MessageBlock; + + public ImprovedInstantMessagePacket() + { + HasVariableBlocks = false; + Type = PacketType.ImprovedInstantMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 254; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MessageBlock = new MessageBlockBlock(); + } + + public ImprovedInstantMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MessageBlock.FromBytes(bytes, ref i); + } + + public ImprovedInstantMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MessageBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MessageBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MessageBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RetrieveInstantMessagesPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public RetrieveInstantMessagesPacket() + { + HasVariableBlocks = false; + Type = PacketType.RetrieveInstantMessages; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 255; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public RetrieveInstantMessagesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public RetrieveInstantMessagesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class FindAgentPacket : Packet + { + /// + public sealed class AgentBlockBlock : PacketBlock + { + public UUID Hunter; + public UUID Prey; + public uint SpaceIP; + + public override int Length + { + get + { + return 36; + } + } + + public AgentBlockBlock() { } + public AgentBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Hunter.FromBytes(bytes, i); i += 16; + Prey.FromBytes(bytes, i); i += 16; + SpaceIP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Hunter.ToBytes(bytes, i); i += 16; + Prey.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(SpaceIP, bytes, i); i += 4; + } + + } + + /// + public sealed class LocationBlockBlock : PacketBlock + { + public double GlobalX; + public double GlobalY; + + public override int Length + { + get + { + return 16; + } + } + + public LocationBlockBlock() { } + public LocationBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GlobalX = Utils.BytesToDouble(bytes, i); i += 8; + GlobalY = Utils.BytesToDouble(bytes, i); i += 8; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.DoubleToBytes(GlobalX, bytes, i); i += 8; + Utils.DoubleToBytes(GlobalY, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentBlock.Length; + for (int j = 0; j < LocationBlock.Length; j++) + length += LocationBlock[j].Length; + return length; + } + } + public AgentBlockBlock AgentBlock; + public LocationBlockBlock[] LocationBlock; + + public FindAgentPacket() + { + HasVariableBlocks = true; + Type = PacketType.FindAgent; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 256; + Header.Reliable = true; + AgentBlock = new AgentBlockBlock(); + LocationBlock = null; + } + + public FindAgentPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(LocationBlock == null || LocationBlock.Length != -1) { + LocationBlock = new LocationBlockBlock[count]; + for(int j = 0; j < count; j++) + { LocationBlock[j] = new LocationBlockBlock(); } + } + for (int j = 0; j < count; j++) + { LocationBlock[j].FromBytes(bytes, ref i); } + } + + public FindAgentPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(LocationBlock == null || LocationBlock.Length != count) { + LocationBlock = new LocationBlockBlock[count]; + for(int j = 0; j < count; j++) + { LocationBlock[j] = new LocationBlockBlock(); } + } + for (int j = 0; j < count; j++) + { LocationBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentBlock.Length; + length++; + for (int j = 0; j < LocationBlock.Length; j++) { length += LocationBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentBlock.ToBytes(bytes, ref i); + bytes[i++] = (byte)LocationBlock.Length; + for (int j = 0; j < LocationBlock.Length; j++) { LocationBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentBlock.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentBlock.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int LocationBlockStart = 0; + do + { + int variableLength = 0; + int LocationBlockCount = 0; + + i = LocationBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < LocationBlock.Length) { + int blockLength = LocationBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++LocationBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)LocationBlockCount; + for (i = LocationBlockStart; i < LocationBlockStart + LocationBlockCount; i++) { LocationBlock[i].ToBytes(packet, ref length); } + LocationBlockStart += LocationBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + LocationBlockStart < LocationBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RequestGodlikePowersPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RequestBlockBlock : PacketBlock + { + public bool Godlike; + public UUID Token; + + public override int Length + { + get + { + return 17; + } + } + + public RequestBlockBlock() { } + public RequestBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Godlike = (bytes[i++] != 0) ? (bool)true : (bool)false; + Token.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((Godlike) ? 1 : 0); + Token.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += RequestBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public RequestBlockBlock RequestBlock; + + public RequestGodlikePowersPacket() + { + HasVariableBlocks = false; + Type = PacketType.RequestGodlikePowers; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 257; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RequestBlock = new RequestBlockBlock(); + } + + public RequestGodlikePowersPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RequestBlock.FromBytes(bytes, ref i); + } + + public RequestGodlikePowersPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RequestBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RequestBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RequestBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GrantGodlikePowersPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GrantDataBlock : PacketBlock + { + public byte GodLevel; + public UUID Token; + + public override int Length + { + get + { + return 17; + } + } + + public GrantDataBlock() { } + public GrantDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GodLevel = (byte)bytes[i++]; + Token.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = GodLevel; + Token.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GrantData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GrantDataBlock GrantData; + + public GrantGodlikePowersPacket() + { + HasVariableBlocks = false; + Type = PacketType.GrantGodlikePowers; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 258; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GrantData = new GrantDataBlock(); + } + + public GrantGodlikePowersPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GrantData.FromBytes(bytes, ref i); + } + + public GrantGodlikePowersPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GrantData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GrantData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GrantData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GodlikeMessagePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID TransactionID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MethodDataBlock : PacketBlock + { + public byte[] Method; + public UUID Invoice; + + public override int Length + { + get + { + int length = 17; + if (Method != null) { length += Method.Length; } + return length; + } + } + + public MethodDataBlock() { } + public MethodDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Method = new byte[length]; + Buffer.BlockCopy(bytes, i, Method, 0, length); i += length; + Invoice.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Method.Length; + Buffer.BlockCopy(Method, 0, bytes, i, Method.Length); i += Method.Length; + Invoice.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParamListBlock : PacketBlock + { + public byte[] Parameter; + + public override int Length + { + get + { + int length = 1; + if (Parameter != null) { length += Parameter.Length; } + return length; + } + } + + public ParamListBlock() { } + public ParamListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Parameter = new byte[length]; + Buffer.BlockCopy(bytes, i, Parameter, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Parameter.Length; + Buffer.BlockCopy(Parameter, 0, bytes, i, Parameter.Length); i += Parameter.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += MethodData.Length; + for (int j = 0; j < ParamList.Length; j++) + length += ParamList[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public MethodDataBlock MethodData; + public ParamListBlock[] ParamList; + + public GodlikeMessagePacket() + { + HasVariableBlocks = true; + Type = PacketType.GodlikeMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 259; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MethodData = new MethodDataBlock(); + ParamList = null; + } + + public GodlikeMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MethodData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParamList == null || ParamList.Length != -1) { + ParamList = new ParamListBlock[count]; + for(int j = 0; j < count; j++) + { ParamList[j] = new ParamListBlock(); } + } + for (int j = 0; j < count; j++) + { ParamList[j].FromBytes(bytes, ref i); } + } + + public GodlikeMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MethodData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParamList == null || ParamList.Length != count) { + ParamList = new ParamListBlock[count]; + for(int j = 0; j < count; j++) + { ParamList[j] = new ParamListBlock(); } + } + for (int j = 0; j < count; j++) + { ParamList[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MethodData.Length; + length++; + for (int j = 0; j < ParamList.Length; j++) { length += ParamList[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MethodData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ParamList.Length; + for (int j = 0; j < ParamList.Length; j++) { ParamList[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += MethodData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + MethodData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ParamListStart = 0; + do + { + int variableLength = 0; + int ParamListCount = 0; + + i = ParamListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ParamList.Length) { + int blockLength = ParamList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ParamListCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ParamListCount; + for (i = ParamListStart; i < ParamListStart + ParamListCount; i++) { ParamList[i].ToBytes(packet, ref length); } + ParamListStart += ParamListCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ParamListStart < ParamList.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class EstateOwnerMessagePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID TransactionID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MethodDataBlock : PacketBlock + { + public byte[] Method; + public UUID Invoice; + + public override int Length + { + get + { + int length = 17; + if (Method != null) { length += Method.Length; } + return length; + } + } + + public MethodDataBlock() { } + public MethodDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Method = new byte[length]; + Buffer.BlockCopy(bytes, i, Method, 0, length); i += length; + Invoice.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Method.Length; + Buffer.BlockCopy(Method, 0, bytes, i, Method.Length); i += Method.Length; + Invoice.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParamListBlock : PacketBlock + { + public byte[] Parameter; + + public override int Length + { + get + { + int length = 1; + if (Parameter != null) { length += Parameter.Length; } + return length; + } + } + + public ParamListBlock() { } + public ParamListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Parameter = new byte[length]; + Buffer.BlockCopy(bytes, i, Parameter, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Parameter.Length; + Buffer.BlockCopy(Parameter, 0, bytes, i, Parameter.Length); i += Parameter.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += MethodData.Length; + for (int j = 0; j < ParamList.Length; j++) + length += ParamList[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public MethodDataBlock MethodData; + public ParamListBlock[] ParamList; + + public EstateOwnerMessagePacket() + { + HasVariableBlocks = true; + Type = PacketType.EstateOwnerMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 260; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MethodData = new MethodDataBlock(); + ParamList = null; + } + + public EstateOwnerMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MethodData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParamList == null || ParamList.Length != -1) { + ParamList = new ParamListBlock[count]; + for(int j = 0; j < count; j++) + { ParamList[j] = new ParamListBlock(); } + } + for (int j = 0; j < count; j++) + { ParamList[j].FromBytes(bytes, ref i); } + } + + public EstateOwnerMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MethodData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParamList == null || ParamList.Length != count) { + ParamList = new ParamListBlock[count]; + for(int j = 0; j < count; j++) + { ParamList[j] = new ParamListBlock(); } + } + for (int j = 0; j < count; j++) + { ParamList[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MethodData.Length; + length++; + for (int j = 0; j < ParamList.Length; j++) { length += ParamList[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MethodData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ParamList.Length; + for (int j = 0; j < ParamList.Length; j++) { ParamList[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += MethodData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + MethodData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ParamListStart = 0; + do + { + int variableLength = 0; + int ParamListCount = 0; + + i = ParamListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ParamList.Length) { + int blockLength = ParamList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ParamListCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ParamListCount; + for (i = ParamListStart; i < ParamListStart + ParamListCount; i++) { ParamList[i].ToBytes(packet, ref length); } + ParamListStart += ParamListCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ParamListStart < ParamList.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GenericMessagePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID TransactionID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MethodDataBlock : PacketBlock + { + public byte[] Method; + public UUID Invoice; + + public override int Length + { + get + { + int length = 17; + if (Method != null) { length += Method.Length; } + return length; + } + } + + public MethodDataBlock() { } + public MethodDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Method = new byte[length]; + Buffer.BlockCopy(bytes, i, Method, 0, length); i += length; + Invoice.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Method.Length; + Buffer.BlockCopy(Method, 0, bytes, i, Method.Length); i += Method.Length; + Invoice.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParamListBlock : PacketBlock + { + public byte[] Parameter; + + public override int Length + { + get + { + int length = 1; + if (Parameter != null) { length += Parameter.Length; } + return length; + } + } + + public ParamListBlock() { } + public ParamListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Parameter = new byte[length]; + Buffer.BlockCopy(bytes, i, Parameter, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Parameter.Length; + Buffer.BlockCopy(Parameter, 0, bytes, i, Parameter.Length); i += Parameter.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += MethodData.Length; + for (int j = 0; j < ParamList.Length; j++) + length += ParamList[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public MethodDataBlock MethodData; + public ParamListBlock[] ParamList; + + public GenericMessagePacket() + { + HasVariableBlocks = true; + Type = PacketType.GenericMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 261; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MethodData = new MethodDataBlock(); + ParamList = null; + } + + public GenericMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MethodData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParamList == null || ParamList.Length != -1) { + ParamList = new ParamListBlock[count]; + for(int j = 0; j < count; j++) + { ParamList[j] = new ParamListBlock(); } + } + for (int j = 0; j < count; j++) + { ParamList[j].FromBytes(bytes, ref i); } + } + + public GenericMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MethodData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ParamList == null || ParamList.Length != count) { + ParamList = new ParamListBlock[count]; + for(int j = 0; j < count; j++) + { ParamList[j] = new ParamListBlock(); } + } + for (int j = 0; j < count; j++) + { ParamList[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MethodData.Length; + length++; + for (int j = 0; j < ParamList.Length; j++) { length += ParamList[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MethodData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ParamList.Length; + for (int j = 0; j < ParamList.Length; j++) { ParamList[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += MethodData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + MethodData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ParamListStart = 0; + do + { + int variableLength = 0; + int ParamListCount = 0; + + i = ParamListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ParamList.Length) { + int blockLength = ParamList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ParamListCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ParamListCount; + for (i = ParamListStart; i < ParamListStart + ParamListCount; i++) { ParamList[i].ToBytes(packet, ref length); } + ParamListStart += ParamListCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ParamListStart < ParamList.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class MuteListRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MuteDataBlock : PacketBlock + { + public uint MuteCRC; + + public override int Length + { + get + { + return 4; + } + } + + public MuteDataBlock() { } + public MuteDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + MuteCRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(MuteCRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MuteData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MuteDataBlock MuteData; + + public MuteListRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.MuteListRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 262; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + MuteData = new MuteDataBlock(); + } + + public MuteListRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MuteData.FromBytes(bytes, ref i); + } + + public MuteListRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MuteData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MuteData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MuteData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UpdateMuteListEntryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MuteDataBlock : PacketBlock + { + public UUID MuteID; + public byte[] MuteName; + public int MuteType; + public uint MuteFlags; + + public override int Length + { + get + { + int length = 25; + if (MuteName != null) { length += MuteName.Length; } + return length; + } + } + + public MuteDataBlock() { } + public MuteDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + MuteID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + MuteName = new byte[length]; + Buffer.BlockCopy(bytes, i, MuteName, 0, length); i += length; + MuteType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + MuteFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + MuteID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)MuteName.Length; + Buffer.BlockCopy(MuteName, 0, bytes, i, MuteName.Length); i += MuteName.Length; + Utils.IntToBytes(MuteType, bytes, i); i += 4; + Utils.UIntToBytes(MuteFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MuteData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MuteDataBlock MuteData; + + public UpdateMuteListEntryPacket() + { + HasVariableBlocks = false; + Type = PacketType.UpdateMuteListEntry; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 263; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + MuteData = new MuteDataBlock(); + } + + public UpdateMuteListEntryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MuteData.FromBytes(bytes, ref i); + } + + public UpdateMuteListEntryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MuteData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MuteData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MuteData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RemoveMuteListEntryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MuteDataBlock : PacketBlock + { + public UUID MuteID; + public byte[] MuteName; + + public override int Length + { + get + { + int length = 17; + if (MuteName != null) { length += MuteName.Length; } + return length; + } + } + + public MuteDataBlock() { } + public MuteDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + MuteID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + MuteName = new byte[length]; + Buffer.BlockCopy(bytes, i, MuteName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + MuteID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)MuteName.Length; + Buffer.BlockCopy(MuteName, 0, bytes, i, MuteName.Length); i += MuteName.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MuteData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MuteDataBlock MuteData; + + public RemoveMuteListEntryPacket() + { + HasVariableBlocks = false; + Type = PacketType.RemoveMuteListEntry; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 264; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + MuteData = new MuteDataBlock(); + } + + public RemoveMuteListEntryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MuteData.FromBytes(bytes, ref i); + } + + public RemoveMuteListEntryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MuteData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MuteData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MuteData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CopyInventoryFromNotecardPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class NotecardDataBlock : PacketBlock + { + public UUID NotecardItemID; + public UUID ObjectID; + + public override int Length + { + get + { + return 32; + } + } + + public NotecardDataBlock() { } + public NotecardDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + NotecardItemID.FromBytes(bytes, i); i += 16; + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + NotecardItemID.ToBytes(bytes, i); i += 16; + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + + public override int Length + { + get + { + return 32; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += NotecardData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public NotecardDataBlock NotecardData; + public InventoryDataBlock[] InventoryData; + + public CopyInventoryFromNotecardPacket() + { + HasVariableBlocks = true; + Type = PacketType.CopyInventoryFromNotecard; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 265; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + NotecardData = new NotecardDataBlock(); + InventoryData = null; + } + + public CopyInventoryFromNotecardPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + NotecardData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public CopyInventoryFromNotecardPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + NotecardData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += NotecardData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + NotecardData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += NotecardData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + NotecardData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UpdateInventoryItemPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID TransactionID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public uint CallbackID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID TransactionID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 142; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CallbackID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + TransactionID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CallbackID, bytes, i); i += 4; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public UpdateInventoryItemPacket() + { + HasVariableBlocks = true; + Type = PacketType.UpdateInventoryItem; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 266; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public UpdateInventoryItemPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public UpdateInventoryItemPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UpdateCreateInventoryItemPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public bool SimApproved; + public UUID TransactionID; + + public override int Length + { + get + { + return 33; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SimApproved = (bytes[i++] != 0) ? (bool)true : (bool)false; + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((SimApproved) ? 1 : 0); + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public uint CallbackID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID AssetID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 142; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CallbackID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + AssetID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CallbackID, bytes, i); i += 4; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + AssetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public UpdateCreateInventoryItemPacket() + { + HasVariableBlocks = true; + Type = PacketType.UpdateCreateInventoryItem; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 267; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public UpdateCreateInventoryItemPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public UpdateCreateInventoryItemPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class MoveInventoryItemPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public bool Stamp; + + public override int Length + { + get + { + return 33; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Stamp = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Stamp) ? 1 : 0); + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public byte[] NewName; + + public override int Length + { + get + { + int length = 33; + if (NewName != null) { length += NewName.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + NewName = new byte[length]; + Buffer.BlockCopy(bytes, i, NewName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)NewName.Length; + Buffer.BlockCopy(NewName, 0, bytes, i, NewName.Length); i += NewName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public MoveInventoryItemPacket() + { + HasVariableBlocks = true; + Type = PacketType.MoveInventoryItem; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 268; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public MoveInventoryItemPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public MoveInventoryItemPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class CopyInventoryItemPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public uint CallbackID; + public UUID OldAgentID; + public UUID OldItemID; + public UUID NewFolderID; + public byte[] NewName; + + public override int Length + { + get + { + int length = 53; + if (NewName != null) { length += NewName.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + CallbackID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OldAgentID.FromBytes(bytes, i); i += 16; + OldItemID.FromBytes(bytes, i); i += 16; + NewFolderID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + NewName = new byte[length]; + Buffer.BlockCopy(bytes, i, NewName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(CallbackID, bytes, i); i += 4; + OldAgentID.ToBytes(bytes, i); i += 16; + OldItemID.ToBytes(bytes, i); i += 16; + NewFolderID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)NewName.Length; + Buffer.BlockCopy(NewName, 0, bytes, i, NewName.Length); i += NewName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public CopyInventoryItemPacket() + { + HasVariableBlocks = true; + Type = PacketType.CopyInventoryItem; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 269; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public CopyInventoryItemPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public CopyInventoryItemPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RemoveInventoryItemPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + + public override int Length + { + get + { + return 16; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public RemoveInventoryItemPacket() + { + HasVariableBlocks = true; + Type = PacketType.RemoveInventoryItem; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 270; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public RemoveInventoryItemPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public RemoveInventoryItemPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ChangeInventoryItemFlagsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public uint Flags; + + public override int Length + { + get + { + return 20; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public ChangeInventoryItemFlagsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ChangeInventoryItemFlags; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 271; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public ChangeInventoryItemFlagsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public ChangeInventoryItemFlagsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class SaveAssetIntoInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID NewAssetID; + + public override int Length + { + get + { + return 32; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + NewAssetID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + NewAssetID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock InventoryData; + + public SaveAssetIntoInventoryPacket() + { + HasVariableBlocks = false; + Type = PacketType.SaveAssetIntoInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 272; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public SaveAssetIntoInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public SaveAssetIntoInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CreateInventoryFolderPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + public UUID ParentID; + public sbyte Type; + public byte[] Name; + + public override int Length + { + get + { + int length = 34; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + FolderID.FromBytes(bytes, i); i += 16; + ParentID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + ParentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += FolderData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public FolderDataBlock FolderData; + + public CreateInventoryFolderPacket() + { + HasVariableBlocks = false; + Type = PacketType.CreateInventoryFolder; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 273; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + FolderData = new FolderDataBlock(); + } + + public CreateInventoryFolderPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + FolderData.FromBytes(bytes, ref i); + } + + public CreateInventoryFolderPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + FolderData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += FolderData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + FolderData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UpdateInventoryFolderPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + public UUID ParentID; + public sbyte Type; + public byte[] Name; + + public override int Length + { + get + { + int length = 34; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + FolderID.FromBytes(bytes, i); i += 16; + ParentID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + ParentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < FolderData.Length; j++) + length += FolderData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public FolderDataBlock[] FolderData; + + public UpdateInventoryFolderPacket() + { + HasVariableBlocks = true; + Type = PacketType.UpdateInventoryFolder; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 274; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + FolderData = null; + } + + public UpdateInventoryFolderPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != -1) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public UpdateInventoryFolderPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != count) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < FolderData.Length; j++) { length += FolderData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)FolderData.Length; + for (int j = 0; j < FolderData.Length; j++) { FolderData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int FolderDataStart = 0; + do + { + int variableLength = 0; + int FolderDataCount = 0; + + i = FolderDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < FolderData.Length) { + int blockLength = FolderData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++FolderDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)FolderDataCount; + for (i = FolderDataStart; i < FolderDataStart + FolderDataCount; i++) { FolderData[i].ToBytes(packet, ref length); } + FolderDataStart += FolderDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + FolderDataStart < FolderData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class MoveInventoryFolderPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public bool Stamp; + + public override int Length + { + get + { + return 33; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Stamp = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Stamp) ? 1 : 0); + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID FolderID; + public UUID ParentID; + + public override int Length + { + get + { + return 32; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FolderID.FromBytes(bytes, i); i += 16; + ParentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + ParentID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public MoveInventoryFolderPacket() + { + HasVariableBlocks = true; + Type = PacketType.MoveInventoryFolder; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 275; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public MoveInventoryFolderPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public MoveInventoryFolderPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RemoveInventoryFolderPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + + public override int Length + { + get + { + return 16; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < FolderData.Length; j++) + length += FolderData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public FolderDataBlock[] FolderData; + + public RemoveInventoryFolderPacket() + { + HasVariableBlocks = true; + Type = PacketType.RemoveInventoryFolder; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 276; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + FolderData = null; + } + + public RemoveInventoryFolderPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != -1) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public RemoveInventoryFolderPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != count) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < FolderData.Length; j++) { length += FolderData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)FolderData.Length; + for (int j = 0; j < FolderData.Length; j++) { FolderData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int FolderDataStart = 0; + do + { + int variableLength = 0; + int FolderDataCount = 0; + + i = FolderDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < FolderData.Length) { + int blockLength = FolderData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++FolderDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)FolderDataCount; + for (i = FolderDataStart; i < FolderDataStart + FolderDataCount; i++) { FolderData[i].ToBytes(packet, ref length); } + FolderDataStart += FolderDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + FolderDataStart < FolderData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class FetchInventoryDescendentsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID FolderID; + public UUID OwnerID; + public int SortOrder; + public bool FetchFolders; + public bool FetchItems; + + public override int Length + { + get + { + return 38; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FolderID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + SortOrder = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + FetchFolders = (bytes[i++] != 0) ? (bool)true : (bool)false; + FetchItems = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(SortOrder, bytes, i); i += 4; + bytes[i++] = (byte)((FetchFolders) ? 1 : 0); + bytes[i++] = (byte)((FetchItems) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock InventoryData; + + public FetchInventoryDescendentsPacket() + { + HasVariableBlocks = false; + Type = PacketType.FetchInventoryDescendents; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 277; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public FetchInventoryDescendentsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public FetchInventoryDescendentsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class InventoryDescendentsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID FolderID; + public UUID OwnerID; + public int Version; + public int Descendents; + + public override int Length + { + get + { + return 56; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + Version = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Descendents = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Version, bytes, i); i += 4; + Utils.IntToBytes(Descendents, bytes, i); i += 4; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + public UUID ParentID; + public sbyte Type; + public byte[] Name; + + public override int Length + { + get + { + int length = 34; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + FolderID.FromBytes(bytes, i); i += 16; + ParentID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + ParentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + /// + public sealed class ItemDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID AssetID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 138; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public ItemDataBlock() { } + public ItemDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + AssetID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + AssetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + for (int j = 0; j < FolderData.Length; j++) + length += FolderData[j].Length; + for (int j = 0; j < ItemData.Length; j++) + length += ItemData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public FolderDataBlock[] FolderData; + public ItemDataBlock[] ItemData; + + public InventoryDescendentsPacket() + { + HasVariableBlocks = true; + Type = PacketType.InventoryDescendents; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 278; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + FolderData = null; + ItemData = null; + } + + public InventoryDescendentsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != -1) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ItemData == null || ItemData.Length != -1) { + ItemData = new ItemDataBlock[count]; + for(int j = 0; j < count; j++) + { ItemData[j] = new ItemDataBlock(); } + } + for (int j = 0; j < count; j++) + { ItemData[j].FromBytes(bytes, ref i); } + } + + public InventoryDescendentsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != count) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ItemData == null || ItemData.Length != count) { + ItemData = new ItemDataBlock[count]; + for(int j = 0; j < count; j++) + { ItemData[j] = new ItemDataBlock(); } + } + for (int j = 0; j < count; j++) + { ItemData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < FolderData.Length; j++) { length += FolderData[j].Length; } + length++; + for (int j = 0; j < ItemData.Length; j++) { length += ItemData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)FolderData.Length; + for (int j = 0; j < FolderData.Length; j++) { FolderData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)ItemData.Length; + for (int j = 0; j < ItemData.Length; j++) { ItemData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int FolderDataStart = 0; + int ItemDataStart = 0; + do + { + int variableLength = 0; + int FolderDataCount = 0; + int ItemDataCount = 0; + + i = FolderDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < FolderData.Length) { + int blockLength = FolderData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++FolderDataCount; + } + else { break; } + ++i; + } + + i = ItemDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ItemData.Length) { + int blockLength = ItemData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ItemDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)FolderDataCount; + for (i = FolderDataStart; i < FolderDataStart + FolderDataCount; i++) { FolderData[i].ToBytes(packet, ref length); } + FolderDataStart += FolderDataCount; + + packet[length++] = (byte)ItemDataCount; + for (i = ItemDataStart; i < ItemDataStart + ItemDataCount; i++) { ItemData[i].ToBytes(packet, ref length); } + ItemDataStart += ItemDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + FolderDataStart < FolderData.Length || + ItemDataStart < ItemData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class FetchInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID OwnerID; + public UUID ItemID; + + public override int Length + { + get + { + return 32; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OwnerID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OwnerID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public FetchInventoryPacket() + { + HasVariableBlocks = true; + Type = PacketType.FetchInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 279; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public FetchInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public FetchInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class FetchInventoryReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID AssetID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 138; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + AssetID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + AssetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock[] InventoryData; + + public FetchInventoryReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.FetchInventoryReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 280; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = null; + } + + public FetchInventoryReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public FetchInventoryReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class BulkUpdateInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID TransactionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + public UUID ParentID; + public sbyte Type; + public byte[] Name; + + public override int Length + { + get + { + int length = 34; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + FolderID.FromBytes(bytes, i); i += 16; + ParentID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + ParentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + /// + public sealed class ItemDataBlock : PacketBlock + { + public UUID ItemID; + public uint CallbackID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID AssetID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 142; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public ItemDataBlock() { } + public ItemDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + CallbackID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + FolderID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + AssetID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CallbackID, bytes, i); i += 4; + FolderID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + AssetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + for (int j = 0; j < FolderData.Length; j++) + length += FolderData[j].Length; + for (int j = 0; j < ItemData.Length; j++) + length += ItemData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public FolderDataBlock[] FolderData; + public ItemDataBlock[] ItemData; + + public BulkUpdateInventoryPacket() + { + HasVariableBlocks = true; + Type = PacketType.BulkUpdateInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 281; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + FolderData = null; + ItemData = null; + } + + public BulkUpdateInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != -1) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ItemData == null || ItemData.Length != -1) { + ItemData = new ItemDataBlock[count]; + for(int j = 0; j < count; j++) + { ItemData[j] = new ItemDataBlock(); } + } + for (int j = 0; j < count; j++) + { ItemData[j].FromBytes(bytes, ref i); } + } + + public BulkUpdateInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != count) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ItemData == null || ItemData.Length != count) { + ItemData = new ItemDataBlock[count]; + for(int j = 0; j < count; j++) + { ItemData[j] = new ItemDataBlock(); } + } + for (int j = 0; j < count; j++) + { ItemData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < FolderData.Length; j++) { length += FolderData[j].Length; } + length++; + for (int j = 0; j < ItemData.Length; j++) { length += ItemData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)FolderData.Length; + for (int j = 0; j < FolderData.Length; j++) { FolderData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)ItemData.Length; + for (int j = 0; j < ItemData.Length; j++) { ItemData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int FolderDataStart = 0; + int ItemDataStart = 0; + do + { + int variableLength = 0; + int FolderDataCount = 0; + int ItemDataCount = 0; + + i = FolderDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < FolderData.Length) { + int blockLength = FolderData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++FolderDataCount; + } + else { break; } + ++i; + } + + i = ItemDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ItemData.Length) { + int blockLength = ItemData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ItemDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)FolderDataCount; + for (i = FolderDataStart; i < FolderDataStart + FolderDataCount; i++) { FolderData[i].ToBytes(packet, ref length); } + FolderDataStart += FolderDataCount; + + packet[length++] = (byte)ItemDataCount; + for (i = ItemDataStart; i < ItemDataStart + ItemDataCount; i++) { ItemData[i].ToBytes(packet, ref length); } + ItemDataStart += ItemDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + FolderDataStart < FolderData.Length || + ItemDataStart < ItemData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RemoveInventoryObjectsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + + public override int Length + { + get + { + return 16; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ItemDataBlock : PacketBlock + { + public UUID ItemID; + + public override int Length + { + get + { + return 16; + } + } + + public ItemDataBlock() { } + public ItemDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + for (int j = 0; j < FolderData.Length; j++) + length += FolderData[j].Length; + for (int j = 0; j < ItemData.Length; j++) + length += ItemData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public FolderDataBlock[] FolderData; + public ItemDataBlock[] ItemData; + + public RemoveInventoryObjectsPacket() + { + HasVariableBlocks = true; + Type = PacketType.RemoveInventoryObjects; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 284; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + FolderData = null; + ItemData = null; + } + + public RemoveInventoryObjectsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != -1) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ItemData == null || ItemData.Length != -1) { + ItemData = new ItemDataBlock[count]; + for(int j = 0; j < count; j++) + { ItemData[j] = new ItemDataBlock(); } + } + for (int j = 0; j < count; j++) + { ItemData[j].FromBytes(bytes, ref i); } + } + + public RemoveInventoryObjectsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != count) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(ItemData == null || ItemData.Length != count) { + ItemData = new ItemDataBlock[count]; + for(int j = 0; j < count; j++) + { ItemData[j] = new ItemDataBlock(); } + } + for (int j = 0; j < count; j++) + { ItemData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < FolderData.Length; j++) { length += FolderData[j].Length; } + length++; + for (int j = 0; j < ItemData.Length; j++) { length += ItemData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)FolderData.Length; + for (int j = 0; j < FolderData.Length; j++) { FolderData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)ItemData.Length; + for (int j = 0; j < ItemData.Length; j++) { ItemData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int FolderDataStart = 0; + int ItemDataStart = 0; + do + { + int variableLength = 0; + int FolderDataCount = 0; + int ItemDataCount = 0; + + i = FolderDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < FolderData.Length) { + int blockLength = FolderData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++FolderDataCount; + } + else { break; } + ++i; + } + + i = ItemDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ItemData.Length) { + int blockLength = ItemData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ItemDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)FolderDataCount; + for (i = FolderDataStart; i < FolderDataStart + FolderDataCount; i++) { FolderData[i].ToBytes(packet, ref length); } + FolderDataStart += FolderDataCount; + + packet[length++] = (byte)ItemDataCount; + for (i = ItemDataStart; i < ItemDataStart + ItemDataCount; i++) { ItemData[i].ToBytes(packet, ref length); } + ItemDataStart += ItemDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + FolderDataStart < FolderData.Length || + ItemDataStart < ItemData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class PurgeInventoryDescendentsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID FolderID; + + public override int Length + { + get + { + return 16; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock InventoryData; + + public PurgeInventoryDescendentsPacket() + { + HasVariableBlocks = false; + Type = PacketType.PurgeInventoryDescendents; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 285; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public PurgeInventoryDescendentsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public PurgeInventoryDescendentsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UpdateTaskInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class UpdateDataBlock : PacketBlock + { + public uint LocalID; + public byte Key; + + public override int Length + { + get + { + return 5; + } + } + + public UpdateDataBlock() { } + public UpdateDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Key = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + bytes[i++] = Key; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID TransactionID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 138; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + TransactionID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += UpdateData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public UpdateDataBlock UpdateData; + public InventoryDataBlock InventoryData; + + public UpdateTaskInventoryPacket() + { + HasVariableBlocks = false; + Type = PacketType.UpdateTaskInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 286; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + UpdateData = new UpdateDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public UpdateTaskInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + UpdateData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public UpdateTaskInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + UpdateData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += UpdateData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + UpdateData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RemoveTaskInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public uint LocalID; + public UUID ItemID; + + public override int Length + { + get + { + return 20; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock InventoryData; + + public RemoveTaskInventoryPacket() + { + HasVariableBlocks = false; + Type = PacketType.RemoveTaskInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 287; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public RemoveTaskInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public RemoveTaskInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MoveTaskInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID FolderID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public uint LocalID; + public UUID ItemID; + + public override int Length + { + get + { + return 20; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock InventoryData; + + public MoveTaskInventoryPacket() + { + HasVariableBlocks = false; + Type = PacketType.MoveTaskInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 288; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public MoveTaskInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public MoveTaskInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RequestTaskInventoryPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public uint LocalID; + + public override int Length + { + get + { + return 4; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + LocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(LocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock InventoryData; + + public RequestTaskInventoryPacket() + { + HasVariableBlocks = false; + Type = PacketType.RequestTaskInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 289; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public RequestTaskInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public RequestTaskInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ReplyTaskInventoryPacket : Packet + { + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID TaskID; + public short Serial; + public byte[] Filename; + + public override int Length + { + get + { + int length = 19; + if (Filename != null) { length += Filename.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TaskID.FromBytes(bytes, i); i += 16; + Serial = (short)(bytes[i++] + (bytes[i++] << 8)); + length = bytes[i++]; + Filename = new byte[length]; + Buffer.BlockCopy(bytes, i, Filename, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TaskID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(Serial % 256); + bytes[i++] = (byte)((Serial >> 8) % 256); + bytes[i++] = (byte)Filename.Length; + Buffer.BlockCopy(Filename, 0, bytes, i, Filename.Length); i += Filename.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += InventoryData.Length; + return length; + } + } + public InventoryDataBlock InventoryData; + + public ReplyTaskInventoryPacket() + { + HasVariableBlocks = false; + Type = PacketType.ReplyTaskInventory; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 290; + Header.Reliable = true; + Header.Zerocoded = true; + InventoryData = new InventoryDataBlock(); + } + + public ReplyTaskInventoryPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + InventoryData.FromBytes(bytes, ref i); + } + + public ReplyTaskInventoryPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class DeRezObjectPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class AgentBlockBlock : PacketBlock + { + public UUID GroupID; + public byte Destination; + public UUID DestinationID; + public UUID TransactionID; + public byte PacketCount; + public byte PacketNumber; + + public override int Length + { + get + { + return 51; + } + } + + public AgentBlockBlock() { } + public AgentBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + Destination = (byte)bytes[i++]; + DestinationID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + PacketCount = (byte)bytes[i++]; + PacketNumber = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = Destination; + DestinationID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = PacketCount; + bytes[i++] = PacketNumber; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += AgentBlock.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public AgentBlockBlock AgentBlock; + public ObjectDataBlock[] ObjectData; + + public DeRezObjectPacket() + { + HasVariableBlocks = true; + Type = PacketType.DeRezObject; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 291; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + AgentBlock = new AgentBlockBlock(); + ObjectData = null; + } + + public DeRezObjectPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + AgentBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public DeRezObjectPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + AgentBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += AgentBlock.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + AgentBlock.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += AgentBlock.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + AgentBlock.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DeRezAckPacket : Packet + { + /// + public sealed class TransactionDataBlock : PacketBlock + { + public UUID TransactionID; + public bool Success; + + public override int Length + { + get + { + return 17; + } + } + + public TransactionDataBlock() { } + public TransactionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + Success = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Success) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += TransactionData.Length; + return length; + } + } + public TransactionDataBlock TransactionData; + + public DeRezAckPacket() + { + HasVariableBlocks = false; + Type = PacketType.DeRezAck; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 292; + Header.Reliable = true; + TransactionData = new TransactionDataBlock(); + } + + public DeRezAckPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TransactionData.FromBytes(bytes, ref i); + } + + public DeRezAckPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TransactionData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TransactionData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TransactionData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RezObjectPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RezDataBlock : PacketBlock + { + public UUID FromTaskID; + public byte BypassRaycast; + public Vector3 RayStart; + public Vector3 RayEnd; + public UUID RayTargetID; + public bool RayEndIsIntersection; + public bool RezSelected; + public bool RemoveItem; + public uint ItemFlags; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + + public override int Length + { + get + { + return 76; + } + } + + public RezDataBlock() { } + public RezDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FromTaskID.FromBytes(bytes, i); i += 16; + BypassRaycast = (byte)bytes[i++]; + RayStart.FromBytes(bytes, i); i += 12; + RayEnd.FromBytes(bytes, i); i += 12; + RayTargetID.FromBytes(bytes, i); i += 16; + RayEndIsIntersection = (bytes[i++] != 0) ? (bool)true : (bool)false; + RezSelected = (bytes[i++] != 0) ? (bool)true : (bool)false; + RemoveItem = (bytes[i++] != 0) ? (bool)true : (bool)false; + ItemFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FromTaskID.ToBytes(bytes, i); i += 16; + bytes[i++] = BypassRaycast; + RayStart.ToBytes(bytes, i); i += 12; + RayEnd.ToBytes(bytes, i); i += 12; + RayTargetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((RayEndIsIntersection) ? 1 : 0); + bytes[i++] = (byte)((RezSelected) ? 1 : 0); + bytes[i++] = (byte)((RemoveItem) ? 1 : 0); + Utils.UIntToBytes(ItemFlags, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID TransactionID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 138; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + TransactionID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += RezData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public RezDataBlock RezData; + public InventoryDataBlock InventoryData; + + public RezObjectPacket() + { + HasVariableBlocks = false; + Type = PacketType.RezObject; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 293; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + RezData = new RezDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public RezObjectPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RezData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public RezObjectPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RezData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RezData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RezData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RezObjectFromNotecardPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RezDataBlock : PacketBlock + { + public UUID FromTaskID; + public byte BypassRaycast; + public Vector3 RayStart; + public Vector3 RayEnd; + public UUID RayTargetID; + public bool RayEndIsIntersection; + public bool RezSelected; + public bool RemoveItem; + public uint ItemFlags; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + + public override int Length + { + get + { + return 76; + } + } + + public RezDataBlock() { } + public RezDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FromTaskID.FromBytes(bytes, i); i += 16; + BypassRaycast = (byte)bytes[i++]; + RayStart.FromBytes(bytes, i); i += 12; + RayEnd.FromBytes(bytes, i); i += 12; + RayTargetID.FromBytes(bytes, i); i += 16; + RayEndIsIntersection = (bytes[i++] != 0) ? (bool)true : (bool)false; + RezSelected = (bytes[i++] != 0) ? (bool)true : (bool)false; + RemoveItem = (bytes[i++] != 0) ? (bool)true : (bool)false; + ItemFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FromTaskID.ToBytes(bytes, i); i += 16; + bytes[i++] = BypassRaycast; + RayStart.ToBytes(bytes, i); i += 12; + RayEnd.ToBytes(bytes, i); i += 12; + RayTargetID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((RayEndIsIntersection) ? 1 : 0); + bytes[i++] = (byte)((RezSelected) ? 1 : 0); + bytes[i++] = (byte)((RemoveItem) ? 1 : 0); + Utils.UIntToBytes(ItemFlags, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + } + + } + + /// + public sealed class NotecardDataBlock : PacketBlock + { + public UUID NotecardItemID; + public UUID ObjectID; + + public override int Length + { + get + { + return 32; + } + } + + public NotecardDataBlock() { } + public NotecardDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + NotecardItemID.FromBytes(bytes, i); i += 16; + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + NotecardItemID.ToBytes(bytes, i); i += 16; + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + + public override int Length + { + get + { + return 16; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += RezData.Length; + length += NotecardData.Length; + for (int j = 0; j < InventoryData.Length; j++) + length += InventoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RezDataBlock RezData; + public NotecardDataBlock NotecardData; + public InventoryDataBlock[] InventoryData; + + public RezObjectFromNotecardPacket() + { + HasVariableBlocks = true; + Type = PacketType.RezObjectFromNotecard; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 294; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + RezData = new RezDataBlock(); + NotecardData = new NotecardDataBlock(); + InventoryData = null; + } + + public RezObjectFromNotecardPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RezData.FromBytes(bytes, ref i); + NotecardData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != -1) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public RezObjectFromNotecardPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RezData.FromBytes(bytes, ref i); + NotecardData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InventoryData == null || InventoryData.Length != count) { + InventoryData = new InventoryDataBlock[count]; + for(int j = 0; j < count; j++) + { InventoryData[j] = new InventoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { InventoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RezData.Length; + length += NotecardData.Length; + length++; + for (int j = 0; j < InventoryData.Length; j++) { length += InventoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RezData.ToBytes(bytes, ref i); + NotecardData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InventoryData.Length; + for (int j = 0; j < InventoryData.Length; j++) { InventoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += RezData.Length; + fixedLength += NotecardData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + RezData.ToBytes(fixedBytes, ref i); + NotecardData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InventoryDataStart = 0; + do + { + int variableLength = 0; + int InventoryDataCount = 0; + + i = InventoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InventoryData.Length) { + int blockLength = InventoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InventoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InventoryDataCount; + for (i = InventoryDataStart; i < InventoryDataStart + InventoryDataCount; i++) { InventoryData[i].ToBytes(packet, ref length); } + InventoryDataStart += InventoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InventoryDataStart < InventoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AcceptFriendshipPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionBlockBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionBlockBlock() { } + public TransactionBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + + public override int Length + { + get + { + return 16; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += TransactionBlock.Length; + for (int j = 0; j < FolderData.Length; j++) + length += FolderData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionBlockBlock TransactionBlock; + public FolderDataBlock[] FolderData; + + public AcceptFriendshipPacket() + { + HasVariableBlocks = true; + Type = PacketType.AcceptFriendship; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 297; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + TransactionBlock = new TransactionBlockBlock(); + FolderData = null; + } + + public AcceptFriendshipPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != -1) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public AcceptFriendshipPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != count) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionBlock.Length; + length++; + for (int j = 0; j < FolderData.Length; j++) { length += FolderData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionBlock.ToBytes(bytes, ref i); + bytes[i++] = (byte)FolderData.Length; + for (int j = 0; j < FolderData.Length; j++) { FolderData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += TransactionBlock.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + TransactionBlock.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int FolderDataStart = 0; + do + { + int variableLength = 0; + int FolderDataCount = 0; + + i = FolderDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < FolderData.Length) { + int blockLength = FolderData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++FolderDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)FolderDataCount; + for (i = FolderDataStart; i < FolderDataStart + FolderDataCount; i++) { FolderData[i].ToBytes(packet, ref length); } + FolderDataStart += FolderDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + FolderDataStart < FolderData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DeclineFriendshipPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionBlockBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionBlockBlock() { } + public TransactionBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += TransactionBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionBlockBlock TransactionBlock; + + public DeclineFriendshipPacket() + { + HasVariableBlocks = false; + Type = PacketType.DeclineFriendship; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 298; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + TransactionBlock = new TransactionBlockBlock(); + } + + public DeclineFriendshipPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + } + + public DeclineFriendshipPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class TerminateFriendshipPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ExBlockBlock : PacketBlock + { + public UUID OtherID; + + public override int Length + { + get + { + return 16; + } + } + + public ExBlockBlock() { } + public ExBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OtherID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OtherID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ExBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ExBlockBlock ExBlock; + + public TerminateFriendshipPacket() + { + HasVariableBlocks = false; + Type = PacketType.TerminateFriendship; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 300; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ExBlock = new ExBlockBlock(); + } + + public TerminateFriendshipPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ExBlock.FromBytes(bytes, ref i); + } + + public TerminateFriendshipPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ExBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ExBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ExBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class OfferCallingCardPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class AgentBlockBlock : PacketBlock + { + public UUID DestID; + public UUID TransactionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentBlockBlock() { } + public AgentBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + DestID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + DestID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += AgentBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public AgentBlockBlock AgentBlock; + + public OfferCallingCardPacket() + { + HasVariableBlocks = false; + Type = PacketType.OfferCallingCard; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 301; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + AgentBlock = new AgentBlockBlock(); + } + + public OfferCallingCardPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + AgentBlock.FromBytes(bytes, ref i); + } + + public OfferCallingCardPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + AgentBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += AgentBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + AgentBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AcceptCallingCardPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionBlockBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionBlockBlock() { } + public TransactionBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FolderDataBlock : PacketBlock + { + public UUID FolderID; + + public override int Length + { + get + { + return 16; + } + } + + public FolderDataBlock() { } + public FolderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + FolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += TransactionBlock.Length; + for (int j = 0; j < FolderData.Length; j++) + length += FolderData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionBlockBlock TransactionBlock; + public FolderDataBlock[] FolderData; + + public AcceptCallingCardPacket() + { + HasVariableBlocks = true; + Type = PacketType.AcceptCallingCard; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 302; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + TransactionBlock = new TransactionBlockBlock(); + FolderData = null; + } + + public AcceptCallingCardPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != -1) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public AcceptCallingCardPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(FolderData == null || FolderData.Length != count) { + FolderData = new FolderDataBlock[count]; + for(int j = 0; j < count; j++) + { FolderData[j] = new FolderDataBlock(); } + } + for (int j = 0; j < count; j++) + { FolderData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionBlock.Length; + length++; + for (int j = 0; j < FolderData.Length; j++) { length += FolderData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionBlock.ToBytes(bytes, ref i); + bytes[i++] = (byte)FolderData.Length; + for (int j = 0; j < FolderData.Length; j++) { FolderData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += TransactionBlock.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + TransactionBlock.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int FolderDataStart = 0; + do + { + int variableLength = 0; + int FolderDataCount = 0; + + i = FolderDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < FolderData.Length) { + int blockLength = FolderData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++FolderDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)FolderDataCount; + for (i = FolderDataStart; i < FolderDataStart + FolderDataCount; i++) { FolderData[i].ToBytes(packet, ref length); } + FolderDataStart += FolderDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + FolderDataStart < FolderData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DeclineCallingCardPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionBlockBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionBlockBlock() { } + public TransactionBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += TransactionBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionBlockBlock TransactionBlock; + + public DeclineCallingCardPacket() + { + HasVariableBlocks = false; + Type = PacketType.DeclineCallingCard; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 303; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + TransactionBlock = new TransactionBlockBlock(); + } + + public DeclineCallingCardPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + } + + public DeclineCallingCardPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RezScriptPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class UpdateBlockBlock : PacketBlock + { + public uint ObjectLocalID; + public bool Enabled; + + public override int Length + { + get + { + return 5; + } + } + + public UpdateBlockBlock() { } + public UpdateBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Enabled = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = (byte)((Enabled) ? 1 : 0); + } + + } + + /// + public sealed class InventoryBlockBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID TransactionID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 138; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryBlockBlock() { } + public InventoryBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + TransactionID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += UpdateBlock.Length; + length += InventoryBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public UpdateBlockBlock UpdateBlock; + public InventoryBlockBlock InventoryBlock; + + public RezScriptPacket() + { + HasVariableBlocks = false; + Type = PacketType.RezScript; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 304; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + UpdateBlock = new UpdateBlockBlock(); + InventoryBlock = new InventoryBlockBlock(); + } + + public RezScriptPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + UpdateBlock.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public RezScriptPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + UpdateBlock.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += UpdateBlock.Length; + length += InventoryBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + UpdateBlock.ToBytes(bytes, ref i); + InventoryBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CreateInventoryItemPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryBlockBlock : PacketBlock + { + public uint CallbackID; + public UUID FolderID; + public UUID TransactionID; + public uint NextOwnerMask; + public sbyte Type; + public sbyte InvType; + public byte WearableType; + public byte[] Name; + public byte[] Description; + + public override int Length + { + get + { + int length = 45; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryBlockBlock() { } + public InventoryBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + CallbackID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + FolderID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + WearableType = (byte)bytes[i++]; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(CallbackID, bytes, i); i += 4; + FolderID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + bytes[i++] = WearableType; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryBlockBlock InventoryBlock; + + public CreateInventoryItemPacket() + { + HasVariableBlocks = false; + Type = PacketType.CreateInventoryItem; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 305; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryBlock = new InventoryBlockBlock(); + } + + public CreateInventoryItemPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public CreateInventoryItemPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CreateLandmarkForEventPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EventDataBlock : PacketBlock + { + public uint EventID; + + public override int Length + { + get + { + return 4; + } + } + + public EventDataBlock() { } + public EventDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + EventID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(EventID, bytes, i); i += 4; + } + + } + + /// + public sealed class InventoryBlockBlock : PacketBlock + { + public UUID FolderID; + public byte[] Name; + + public override int Length + { + get + { + int length = 17; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public InventoryBlockBlock() { } + public InventoryBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + FolderID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + FolderID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + length += InventoryBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public EventDataBlock EventData; + public InventoryBlockBlock InventoryBlock; + + public CreateLandmarkForEventPacket() + { + HasVariableBlocks = false; + Type = PacketType.CreateLandmarkForEvent; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 306; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + EventData = new EventDataBlock(); + InventoryBlock = new InventoryBlockBlock(); + } + + public CreateLandmarkForEventPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public CreateLandmarkForEventPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + EventData.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += EventData.Length; + length += InventoryBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + EventData.ToBytes(bytes, ref i); + InventoryBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RegionHandleRequestPacket : Packet + { + /// + public sealed class RequestBlockBlock : PacketBlock + { + public UUID RegionID; + + public override int Length + { + get + { + return 16; + } + } + + public RequestBlockBlock() { } + public RequestBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RegionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += RequestBlock.Length; + return length; + } + } + public RequestBlockBlock RequestBlock; + + public RegionHandleRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.RegionHandleRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 309; + Header.Reliable = true; + RequestBlock = new RequestBlockBlock(); + } + + public RegionHandleRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RequestBlock.FromBytes(bytes, ref i); + } + + public RegionHandleRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RequestBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += RequestBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RequestBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RegionIDAndHandleReplyPacket : Packet + { + /// + public sealed class ReplyBlockBlock : PacketBlock + { + public UUID RegionID; + public ulong RegionHandle; + + public override int Length + { + get + { + return 24; + } + } + + public ReplyBlockBlock() { } + public ReplyBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionID.FromBytes(bytes, i); i += 16; + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RegionID.ToBytes(bytes, i); i += 16; + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ReplyBlock.Length; + return length; + } + } + public ReplyBlockBlock ReplyBlock; + + public RegionIDAndHandleReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.RegionIDAndHandleReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 310; + Header.Reliable = true; + ReplyBlock = new ReplyBlockBlock(); + } + + public RegionIDAndHandleReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ReplyBlock.FromBytes(bytes, ref i); + } + + public RegionIDAndHandleReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ReplyBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ReplyBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ReplyBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MoneyTransferRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID SourceID; + public UUID DestID; + public byte Flags; + public int Amount; + public byte AggregatePermNextOwner; + public byte AggregatePermInventory; + public int TransactionType; + public byte[] Description; + + public override int Length + { + get + { + int length = 44; + if (Description != null) { length += Description.Length; } + return length; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + SourceID.FromBytes(bytes, i); i += 16; + DestID.FromBytes(bytes, i); i += 16; + Flags = (byte)bytes[i++]; + Amount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AggregatePermNextOwner = (byte)bytes[i++]; + AggregatePermInventory = (byte)bytes[i++]; + TransactionType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + SourceID.ToBytes(bytes, i); i += 16; + DestID.ToBytes(bytes, i); i += 16; + bytes[i++] = Flags; + Utils.IntToBytes(Amount, bytes, i); i += 4; + bytes[i++] = AggregatePermNextOwner; + bytes[i++] = AggregatePermInventory; + Utils.IntToBytes(TransactionType, bytes, i); i += 4; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + + public MoneyTransferRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.MoneyTransferRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 311; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + } + + public MoneyTransferRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public MoneyTransferRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MoneyBalanceRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + + public MoneyBalanceRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.MoneyBalanceRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 313; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + } + + public MoneyBalanceRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public MoneyBalanceRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MoneyBalanceReplyPacket : Packet + { + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID AgentID; + public UUID TransactionID; + public bool TransactionSuccess; + public int MoneyBalance; + public int SquareMetersCredit; + public int SquareMetersCommitted; + public byte[] Description; + + public override int Length + { + get + { + int length = 46; + if (Description != null) { length += Description.Length; } + return length; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + TransactionSuccess = (bytes[i++] != 0) ? (bool)true : (bool)false; + MoneyBalance = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SquareMetersCredit = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SquareMetersCommitted = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((TransactionSuccess) ? 1 : 0); + Utils.IntToBytes(MoneyBalance, bytes, i); i += 4; + Utils.IntToBytes(SquareMetersCredit, bytes, i); i += 4; + Utils.IntToBytes(SquareMetersCommitted, bytes, i); i += 4; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + /// + public sealed class TransactionInfoBlock : PacketBlock + { + public int TransactionType; + public UUID SourceID; + public bool IsSourceGroup; + public UUID DestID; + public bool IsDestGroup; + public int Amount; + public byte[] ItemDescription; + + public override int Length + { + get + { + int length = 43; + if (ItemDescription != null) { length += ItemDescription.Length; } + return length; + } + } + + public TransactionInfoBlock() { } + public TransactionInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TransactionType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SourceID.FromBytes(bytes, i); i += 16; + IsSourceGroup = (bytes[i++] != 0) ? (bool)true : (bool)false; + DestID.FromBytes(bytes, i); i += 16; + IsDestGroup = (bytes[i++] != 0) ? (bool)true : (bool)false; + Amount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + ItemDescription = new byte[length]; + Buffer.BlockCopy(bytes, i, ItemDescription, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(TransactionType, bytes, i); i += 4; + SourceID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsSourceGroup) ? 1 : 0); + DestID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsDestGroup) ? 1 : 0); + Utils.IntToBytes(Amount, bytes, i); i += 4; + bytes[i++] = (byte)ItemDescription.Length; + Buffer.BlockCopy(ItemDescription, 0, bytes, i, ItemDescription.Length); i += ItemDescription.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += MoneyData.Length; + length += TransactionInfo.Length; + return length; + } + } + public MoneyDataBlock MoneyData; + public TransactionInfoBlock TransactionInfo; + + public MoneyBalanceReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.MoneyBalanceReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 314; + Header.Reliable = true; + Header.Zerocoded = true; + MoneyData = new MoneyDataBlock(); + TransactionInfo = new TransactionInfoBlock(); + } + + public MoneyBalanceReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + MoneyData.FromBytes(bytes, ref i); + TransactionInfo.FromBytes(bytes, ref i); + } + + public MoneyBalanceReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + MoneyData.FromBytes(bytes, ref i); + TransactionInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += MoneyData.Length; + length += TransactionInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + TransactionInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RoutedMoneyBalanceReplyPacket : Packet + { + /// + public sealed class TargetBlockBlock : PacketBlock + { + public uint TargetIP; + public ushort TargetPort; + + public override int Length + { + get + { + return 6; + } + } + + public TargetBlockBlock() { } + public TargetBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TargetIP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TargetPort = (ushort)((bytes[i++] << 8) + bytes[i++]); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(TargetIP, bytes, i); i += 4; + bytes[i++] = (byte)((TargetPort >> 8) % 256); + bytes[i++] = (byte)(TargetPort % 256); + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID AgentID; + public UUID TransactionID; + public bool TransactionSuccess; + public int MoneyBalance; + public int SquareMetersCredit; + public int SquareMetersCommitted; + public byte[] Description; + + public override int Length + { + get + { + int length = 46; + if (Description != null) { length += Description.Length; } + return length; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + TransactionSuccess = (bytes[i++] != 0) ? (bool)true : (bool)false; + MoneyBalance = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SquareMetersCredit = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SquareMetersCommitted = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((TransactionSuccess) ? 1 : 0); + Utils.IntToBytes(MoneyBalance, bytes, i); i += 4; + Utils.IntToBytes(SquareMetersCredit, bytes, i); i += 4; + Utils.IntToBytes(SquareMetersCommitted, bytes, i); i += 4; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + /// + public sealed class TransactionInfoBlock : PacketBlock + { + public int TransactionType; + public UUID SourceID; + public bool IsSourceGroup; + public UUID DestID; + public bool IsDestGroup; + public int Amount; + public byte[] ItemDescription; + + public override int Length + { + get + { + int length = 43; + if (ItemDescription != null) { length += ItemDescription.Length; } + return length; + } + } + + public TransactionInfoBlock() { } + public TransactionInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TransactionType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SourceID.FromBytes(bytes, i); i += 16; + IsSourceGroup = (bytes[i++] != 0) ? (bool)true : (bool)false; + DestID.FromBytes(bytes, i); i += 16; + IsDestGroup = (bytes[i++] != 0) ? (bool)true : (bool)false; + Amount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + ItemDescription = new byte[length]; + Buffer.BlockCopy(bytes, i, ItemDescription, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(TransactionType, bytes, i); i += 4; + SourceID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsSourceGroup) ? 1 : 0); + DestID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsDestGroup) ? 1 : 0); + Utils.IntToBytes(Amount, bytes, i); i += 4; + bytes[i++] = (byte)ItemDescription.Length; + Buffer.BlockCopy(ItemDescription, 0, bytes, i, ItemDescription.Length); i += ItemDescription.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += TargetBlock.Length; + length += MoneyData.Length; + length += TransactionInfo.Length; + return length; + } + } + public TargetBlockBlock TargetBlock; + public MoneyDataBlock MoneyData; + public TransactionInfoBlock TransactionInfo; + + public RoutedMoneyBalanceReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.RoutedMoneyBalanceReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 315; + Header.Reliable = true; + Header.Zerocoded = true; + TargetBlock = new TargetBlockBlock(); + MoneyData = new MoneyDataBlock(); + TransactionInfo = new TransactionInfoBlock(); + } + + public RoutedMoneyBalanceReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TargetBlock.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + TransactionInfo.FromBytes(bytes, ref i); + } + + public RoutedMoneyBalanceReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TargetBlock.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + TransactionInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += TargetBlock.Length; + length += MoneyData.Length; + length += TransactionInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TargetBlock.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + TransactionInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ActivateGesturesPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint Flags; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ItemID; + public UUID AssetID; + public uint GestureFlags; + + public override int Length + { + get + { + return 36; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + AssetID.FromBytes(bytes, i); i += 16; + GestureFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + AssetID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(GestureFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock[] Data; + + public ActivateGesturesPacket() + { + HasVariableBlocks = true; + Type = PacketType.ActivateGestures; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 316; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = null; + } + + public ActivateGesturesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public ActivateGesturesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DeactivateGesturesPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint Flags; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID ItemID; + public uint GestureFlags; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + GestureFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(GestureFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock[] Data; + + public DeactivateGesturesPacket() + { + HasVariableBlocks = true; + Type = PacketType.DeactivateGestures; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 317; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = null; + } + + public DeactivateGesturesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public DeactivateGesturesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class MuteListUpdatePacket : Packet + { + /// + public sealed class MuteDataBlock : PacketBlock + { + public UUID AgentID; + public byte[] Filename; + + public override int Length + { + get + { + int length = 17; + if (Filename != null) { length += Filename.Length; } + return length; + } + } + + public MuteDataBlock() { } + public MuteDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Filename = new byte[length]; + Buffer.BlockCopy(bytes, i, Filename, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Filename.Length; + Buffer.BlockCopy(Filename, 0, bytes, i, Filename.Length); i += Filename.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += MuteData.Length; + return length; + } + } + public MuteDataBlock MuteData; + + public MuteListUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.MuteListUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 318; + Header.Reliable = true; + MuteData = new MuteDataBlock(); + } + + public MuteListUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + MuteData.FromBytes(bytes, ref i); + } + + public MuteListUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + MuteData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += MuteData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + MuteData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UseCachedMuteListPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public UseCachedMuteListPacket() + { + HasVariableBlocks = false; + Type = PacketType.UseCachedMuteList; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 319; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public UseCachedMuteListPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public UseCachedMuteListPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GrantUserRightsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RightsBlock : PacketBlock + { + public UUID AgentRelated; + public int RelatedRights; + + public override int Length + { + get + { + return 20; + } + } + + public RightsBlock() { } + public RightsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentRelated.FromBytes(bytes, i); i += 16; + RelatedRights = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentRelated.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(RelatedRights, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Rights.Length; j++) + length += Rights[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RightsBlock[] Rights; + + public GrantUserRightsPacket() + { + HasVariableBlocks = true; + Type = PacketType.GrantUserRights; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 320; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Rights = null; + } + + public GrantUserRightsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Rights == null || Rights.Length != -1) { + Rights = new RightsBlock[count]; + for(int j = 0; j < count; j++) + { Rights[j] = new RightsBlock(); } + } + for (int j = 0; j < count; j++) + { Rights[j].FromBytes(bytes, ref i); } + } + + public GrantUserRightsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Rights == null || Rights.Length != count) { + Rights = new RightsBlock[count]; + for(int j = 0; j < count; j++) + { Rights[j] = new RightsBlock(); } + } + for (int j = 0; j < count; j++) + { Rights[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Rights.Length; j++) { length += Rights[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Rights.Length; + for (int j = 0; j < Rights.Length; j++) { Rights[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RightsStart = 0; + do + { + int variableLength = 0; + int RightsCount = 0; + + i = RightsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Rights.Length) { + int blockLength = Rights[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RightsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RightsCount; + for (i = RightsStart; i < RightsStart + RightsCount; i++) { Rights[i].ToBytes(packet, ref length); } + RightsStart += RightsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RightsStart < Rights.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ChangeUserRightsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RightsBlock : PacketBlock + { + public UUID AgentRelated; + public int RelatedRights; + + public override int Length + { + get + { + return 20; + } + } + + public RightsBlock() { } + public RightsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentRelated.FromBytes(bytes, i); i += 16; + RelatedRights = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentRelated.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(RelatedRights, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < Rights.Length; j++) + length += Rights[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RightsBlock[] Rights; + + public ChangeUserRightsPacket() + { + HasVariableBlocks = true; + Type = PacketType.ChangeUserRights; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 321; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Rights = null; + } + + public ChangeUserRightsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Rights == null || Rights.Length != -1) { + Rights = new RightsBlock[count]; + for(int j = 0; j < count; j++) + { Rights[j] = new RightsBlock(); } + } + for (int j = 0; j < count; j++) + { Rights[j].FromBytes(bytes, ref i); } + } + + public ChangeUserRightsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Rights == null || Rights.Length != count) { + Rights = new RightsBlock[count]; + for(int j = 0; j < count; j++) + { Rights[j] = new RightsBlock(); } + } + for (int j = 0; j < count; j++) + { Rights[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Rights.Length; j++) { length += Rights[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Rights.Length; + for (int j = 0; j < Rights.Length; j++) { Rights[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RightsStart = 0; + do + { + int variableLength = 0; + int RightsCount = 0; + + i = RightsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Rights.Length) { + int blockLength = Rights[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RightsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RightsCount; + for (i = RightsStart; i < RightsStart + RightsCount; i++) { Rights[i].ToBytes(packet, ref length); } + RightsStart += RightsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RightsStart < Rights.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class OnlineNotificationPacket : Packet + { + /// + public sealed class AgentBlockBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentBlockBlock() { } + public AgentBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < AgentBlock.Length; j++) + length += AgentBlock[j].Length; + return length; + } + } + public AgentBlockBlock[] AgentBlock; + + public OnlineNotificationPacket() + { + HasVariableBlocks = true; + Type = PacketType.OnlineNotification; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 322; + Header.Reliable = true; + AgentBlock = null; + } + + public OnlineNotificationPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(AgentBlock == null || AgentBlock.Length != -1) { + AgentBlock = new AgentBlockBlock[count]; + for(int j = 0; j < count; j++) + { AgentBlock[j] = new AgentBlockBlock(); } + } + for (int j = 0; j < count; j++) + { AgentBlock[j].FromBytes(bytes, ref i); } + } + + public OnlineNotificationPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(AgentBlock == null || AgentBlock.Length != count) { + AgentBlock = new AgentBlockBlock[count]; + for(int j = 0; j < count; j++) + { AgentBlock[j] = new AgentBlockBlock(); } + } + for (int j = 0; j < count; j++) + { AgentBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < AgentBlock.Length; j++) { length += AgentBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)AgentBlock.Length; + for (int j = 0; j < AgentBlock.Length; j++) { AgentBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int AgentBlockStart = 0; + do + { + int variableLength = 0; + int AgentBlockCount = 0; + + i = AgentBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AgentBlock.Length) { + int blockLength = AgentBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AgentBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)AgentBlockCount; + for (i = AgentBlockStart; i < AgentBlockStart + AgentBlockCount; i++) { AgentBlock[i].ToBytes(packet, ref length); } + AgentBlockStart += AgentBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + AgentBlockStart < AgentBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class OfflineNotificationPacket : Packet + { + /// + public sealed class AgentBlockBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentBlockBlock() { } + public AgentBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < AgentBlock.Length; j++) + length += AgentBlock[j].Length; + return length; + } + } + public AgentBlockBlock[] AgentBlock; + + public OfflineNotificationPacket() + { + HasVariableBlocks = true; + Type = PacketType.OfflineNotification; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 323; + Header.Reliable = true; + AgentBlock = null; + } + + public OfflineNotificationPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(AgentBlock == null || AgentBlock.Length != -1) { + AgentBlock = new AgentBlockBlock[count]; + for(int j = 0; j < count; j++) + { AgentBlock[j] = new AgentBlockBlock(); } + } + for (int j = 0; j < count; j++) + { AgentBlock[j].FromBytes(bytes, ref i); } + } + + public OfflineNotificationPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(AgentBlock == null || AgentBlock.Length != count) { + AgentBlock = new AgentBlockBlock[count]; + for(int j = 0; j < count; j++) + { AgentBlock[j] = new AgentBlockBlock(); } + } + for (int j = 0; j < count; j++) + { AgentBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < AgentBlock.Length; j++) { length += AgentBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)AgentBlock.Length; + for (int j = 0; j < AgentBlock.Length; j++) { AgentBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int AgentBlockStart = 0; + do + { + int variableLength = 0; + int AgentBlockCount = 0; + + i = AgentBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AgentBlock.Length) { + int blockLength = AgentBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AgentBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)AgentBlockCount; + for (i = AgentBlockStart; i < AgentBlockStart + AgentBlockCount; i++) { AgentBlock[i].ToBytes(packet, ref length); } + AgentBlockStart += AgentBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + AgentBlockStart < AgentBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class SetStartLocationRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class StartLocationDataBlock : PacketBlock + { + public byte[] SimName; + public uint LocationID; + public Vector3 LocationPos; + public Vector3 LocationLookAt; + + public override int Length + { + get + { + int length = 29; + if (SimName != null) { length += SimName.Length; } + return length; + } + } + + public StartLocationDataBlock() { } + public StartLocationDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + SimName = new byte[length]; + Buffer.BlockCopy(bytes, i, SimName, 0, length); i += length; + LocationID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LocationPos.FromBytes(bytes, i); i += 12; + LocationLookAt.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)SimName.Length; + Buffer.BlockCopy(SimName, 0, bytes, i, SimName.Length); i += SimName.Length; + Utils.UIntToBytes(LocationID, bytes, i); i += 4; + LocationPos.ToBytes(bytes, i); i += 12; + LocationLookAt.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += StartLocationData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public StartLocationDataBlock StartLocationData; + + public SetStartLocationRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.SetStartLocationRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 324; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + StartLocationData = new StartLocationDataBlock(); + } + + public SetStartLocationRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + StartLocationData.FromBytes(bytes, ref i); + } + + public SetStartLocationRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + StartLocationData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += StartLocationData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + StartLocationData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AssetUploadRequestPacket : Packet + { + /// + public sealed class AssetBlockBlock : PacketBlock + { + public UUID TransactionID; + public sbyte Type; + public bool Tempfile; + public bool StoreLocal; + public byte[] AssetData; + + public override int Length + { + get + { + int length = 21; + if (AssetData != null) { length += AssetData.Length; } + return length; + } + } + + public AssetBlockBlock() { } + public AssetBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TransactionID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + Tempfile = (bytes[i++] != 0) ? (bool)true : (bool)false; + StoreLocal = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = (bytes[i++] + (bytes[i++] << 8)); + AssetData = new byte[length]; + Buffer.BlockCopy(bytes, i, AssetData, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)((Tempfile) ? 1 : 0); + bytes[i++] = (byte)((StoreLocal) ? 1 : 0); + bytes[i++] = (byte)(AssetData.Length % 256); + bytes[i++] = (byte)((AssetData.Length >> 8) % 256); + Buffer.BlockCopy(AssetData, 0, bytes, i, AssetData.Length); i += AssetData.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AssetBlock.Length; + return length; + } + } + public AssetBlockBlock AssetBlock; + + public AssetUploadRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.AssetUploadRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 333; + Header.Reliable = true; + AssetBlock = new AssetBlockBlock(); + } + + public AssetUploadRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AssetBlock.FromBytes(bytes, ref i); + } + + public AssetUploadRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AssetBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AssetBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AssetBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AssetUploadCompletePacket : Packet + { + /// + public sealed class AssetBlockBlock : PacketBlock + { + public UUID UUID; + public sbyte Type; + public bool Success; + + public override int Length + { + get + { + return 18; + } + } + + public AssetBlockBlock() { } + public AssetBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + UUID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + Success = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + UUID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)((Success) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AssetBlock.Length; + return length; + } + } + public AssetBlockBlock AssetBlock; + + public AssetUploadCompletePacket() + { + HasVariableBlocks = false; + Type = PacketType.AssetUploadComplete; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 334; + Header.Reliable = true; + AssetBlock = new AssetBlockBlock(); + } + + public AssetUploadCompletePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AssetBlock.FromBytes(bytes, ref i); + } + + public AssetUploadCompletePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AssetBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AssetBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AssetBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CreateGroupRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public byte[] Name; + public byte[] Charter; + public bool ShowInList; + public UUID InsigniaID; + public int MembershipFee; + public bool OpenEnrollment; + public bool AllowPublish; + public bool MaturePublish; + + public override int Length + { + get + { + int length = 27; + if (Name != null) { length += Name.Length; } + if (Charter != null) { length += Charter.Length; } + return length; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Charter = new byte[length]; + Buffer.BlockCopy(bytes, i, Charter, 0, length); i += length; + ShowInList = (bytes[i++] != 0) ? (bool)true : (bool)false; + InsigniaID.FromBytes(bytes, i); i += 16; + MembershipFee = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OpenEnrollment = (bytes[i++] != 0) ? (bool)true : (bool)false; + AllowPublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + MaturePublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)(Charter.Length % 256); + bytes[i++] = (byte)((Charter.Length >> 8) % 256); + Buffer.BlockCopy(Charter, 0, bytes, i, Charter.Length); i += Charter.Length; + bytes[i++] = (byte)((ShowInList) ? 1 : 0); + InsigniaID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(MembershipFee, bytes, i); i += 4; + bytes[i++] = (byte)((OpenEnrollment) ? 1 : 0); + bytes[i++] = (byte)((AllowPublish) ? 1 : 0); + bytes[i++] = (byte)((MaturePublish) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public CreateGroupRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.CreateGroupRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 339; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public CreateGroupRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public CreateGroupRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CreateGroupReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ReplyDataBlock : PacketBlock + { + public UUID GroupID; + public bool Success; + public byte[] Message; + + public override int Length + { + get + { + int length = 18; + if (Message != null) { length += Message.Length; } + return length; + } + } + + public ReplyDataBlock() { } + public ReplyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GroupID.FromBytes(bytes, i); i += 16; + Success = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Success) ? 1 : 0); + bytes[i++] = (byte)Message.Length; + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ReplyData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ReplyDataBlock ReplyData; + + public CreateGroupReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.CreateGroupReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 340; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ReplyData = new ReplyDataBlock(); + } + + public CreateGroupReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ReplyData.FromBytes(bytes, ref i); + } + + public CreateGroupReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ReplyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ReplyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ReplyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UpdateGroupInfoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public byte[] Charter; + public bool ShowInList; + public UUID InsigniaID; + public int MembershipFee; + public bool OpenEnrollment; + public bool AllowPublish; + public bool MaturePublish; + + public override int Length + { + get + { + int length = 42; + if (Charter != null) { length += Charter.Length; } + return length; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GroupID.FromBytes(bytes, i); i += 16; + length = (bytes[i++] + (bytes[i++] << 8)); + Charter = new byte[length]; + Buffer.BlockCopy(bytes, i, Charter, 0, length); i += length; + ShowInList = (bytes[i++] != 0) ? (bool)true : (bool)false; + InsigniaID.FromBytes(bytes, i); i += 16; + MembershipFee = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OpenEnrollment = (bytes[i++] != 0) ? (bool)true : (bool)false; + AllowPublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + MaturePublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(Charter.Length % 256); + bytes[i++] = (byte)((Charter.Length >> 8) % 256); + Buffer.BlockCopy(Charter, 0, bytes, i, Charter.Length); i += Charter.Length; + bytes[i++] = (byte)((ShowInList) ? 1 : 0); + InsigniaID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(MembershipFee, bytes, i); i += 4; + bytes[i++] = (byte)((OpenEnrollment) ? 1 : 0); + bytes[i++] = (byte)((AllowPublish) ? 1 : 0); + bytes[i++] = (byte)((MaturePublish) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public UpdateGroupInfoPacket() + { + HasVariableBlocks = false; + Type = PacketType.UpdateGroupInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 341; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public UpdateGroupInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public UpdateGroupInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupRoleChangesPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RoleChangeBlock : PacketBlock + { + public UUID RoleID; + public UUID MemberID; + public uint Change; + + public override int Length + { + get + { + return 36; + } + } + + public RoleChangeBlock() { } + public RoleChangeBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RoleID.FromBytes(bytes, i); i += 16; + MemberID.FromBytes(bytes, i); i += 16; + Change = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RoleID.ToBytes(bytes, i); i += 16; + MemberID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Change, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < RoleChange.Length; j++) + length += RoleChange[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RoleChangeBlock[] RoleChange; + + public GroupRoleChangesPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupRoleChanges; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 342; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RoleChange = null; + } + + public GroupRoleChangesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RoleChange == null || RoleChange.Length != -1) { + RoleChange = new RoleChangeBlock[count]; + for(int j = 0; j < count; j++) + { RoleChange[j] = new RoleChangeBlock(); } + } + for (int j = 0; j < count; j++) + { RoleChange[j].FromBytes(bytes, ref i); } + } + + public GroupRoleChangesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RoleChange == null || RoleChange.Length != count) { + RoleChange = new RoleChangeBlock[count]; + for(int j = 0; j < count; j++) + { RoleChange[j] = new RoleChangeBlock(); } + } + for (int j = 0; j < count; j++) + { RoleChange[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < RoleChange.Length; j++) { length += RoleChange[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)RoleChange.Length; + for (int j = 0; j < RoleChange.Length; j++) { RoleChange[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RoleChangeStart = 0; + do + { + int variableLength = 0; + int RoleChangeCount = 0; + + i = RoleChangeStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < RoleChange.Length) { + int blockLength = RoleChange[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RoleChangeCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RoleChangeCount; + for (i = RoleChangeStart; i < RoleChangeStart + RoleChangeCount; i++) { RoleChange[i].ToBytes(packet, ref length); } + RoleChangeStart += RoleChangeCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RoleChangeStart < RoleChange.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class JoinGroupRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public JoinGroupRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.JoinGroupRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 343; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public JoinGroupRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public JoinGroupRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class JoinGroupReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public bool Success; + + public override int Length + { + get + { + return 17; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + Success = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Success) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public JoinGroupReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.JoinGroupReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 344; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public JoinGroupReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public JoinGroupReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class EjectGroupMemberRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EjectDataBlock : PacketBlock + { + public UUID EjecteeID; + + public override int Length + { + get + { + return 16; + } + } + + public EjectDataBlock() { } + public EjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + EjecteeID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + EjecteeID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += GroupData.Length; + for (int j = 0; j < EjectData.Length; j++) + length += EjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + public EjectDataBlock[] EjectData; + + public EjectGroupMemberRequestPacket() + { + HasVariableBlocks = true; + Type = PacketType.EjectGroupMemberRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 345; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + EjectData = null; + } + + public EjectGroupMemberRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(EjectData == null || EjectData.Length != -1) { + EjectData = new EjectDataBlock[count]; + for(int j = 0; j < count; j++) + { EjectData[j] = new EjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { EjectData[j].FromBytes(bytes, ref i); } + } + + public EjectGroupMemberRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(EjectData == null || EjectData.Length != count) { + EjectData = new EjectDataBlock[count]; + for(int j = 0; j < count; j++) + { EjectData[j] = new EjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { EjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length++; + for (int j = 0; j < EjectData.Length; j++) { length += EjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + bytes[i++] = (byte)EjectData.Length; + for (int j = 0; j < EjectData.Length; j++) { EjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += GroupData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + GroupData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int EjectDataStart = 0; + do + { + int variableLength = 0; + int EjectDataCount = 0; + + i = EjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < EjectData.Length) { + int blockLength = EjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++EjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)EjectDataCount; + for (i = EjectDataStart; i < EjectDataStart + EjectDataCount; i++) { EjectData[i].ToBytes(packet, ref length); } + EjectDataStart += EjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + EjectDataStart < EjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class EjectGroupMemberReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EjectDataBlock : PacketBlock + { + public bool Success; + + public override int Length + { + get + { + return 1; + } + } + + public EjectDataBlock() { } + public EjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Success = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((Success) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length += EjectData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + public EjectDataBlock EjectData; + + public EjectGroupMemberReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.EjectGroupMemberReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 346; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + EjectData = new EjectDataBlock(); + } + + public EjectGroupMemberReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + EjectData.FromBytes(bytes, ref i); + } + + public EjectGroupMemberReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + EjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length += EjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + EjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LeaveGroupRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public LeaveGroupRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.LeaveGroupRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 347; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public LeaveGroupRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public LeaveGroupRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LeaveGroupReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public bool Success; + + public override int Length + { + get + { + return 17; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + Success = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Success) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public LeaveGroupReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.LeaveGroupReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 348; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public LeaveGroupReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public LeaveGroupReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class InviteGroupRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InviteDataBlock : PacketBlock + { + public UUID InviteeID; + public UUID RoleID; + + public override int Length + { + get + { + return 32; + } + } + + public InviteDataBlock() { } + public InviteDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + InviteeID.FromBytes(bytes, i); i += 16; + RoleID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + InviteeID.ToBytes(bytes, i); i += 16; + RoleID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += GroupData.Length; + for (int j = 0; j < InviteData.Length; j++) + length += InviteData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + public InviteDataBlock[] InviteData; + + public InviteGroupRequestPacket() + { + HasVariableBlocks = true; + Type = PacketType.InviteGroupRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 349; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + InviteData = null; + } + + public InviteGroupRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InviteData == null || InviteData.Length != -1) { + InviteData = new InviteDataBlock[count]; + for(int j = 0; j < count; j++) + { InviteData[j] = new InviteDataBlock(); } + } + for (int j = 0; j < count; j++) + { InviteData[j].FromBytes(bytes, ref i); } + } + + public InviteGroupRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(InviteData == null || InviteData.Length != count) { + InviteData = new InviteDataBlock[count]; + for(int j = 0; j < count; j++) + { InviteData[j] = new InviteDataBlock(); } + } + for (int j = 0; j < count; j++) + { InviteData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length++; + for (int j = 0; j < InviteData.Length; j++) { length += InviteData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + bytes[i++] = (byte)InviteData.Length; + for (int j = 0; j < InviteData.Length; j++) { InviteData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += GroupData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + GroupData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int InviteDataStart = 0; + do + { + int variableLength = 0; + int InviteDataCount = 0; + + i = InviteDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < InviteData.Length) { + int blockLength = InviteData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++InviteDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)InviteDataCount; + for (i = InviteDataStart; i < InviteDataStart + InviteDataCount; i++) { InviteData[i].ToBytes(packet, ref length); } + InviteDataStart += InviteDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + InviteDataStart < InviteData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupProfileRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public GroupProfileRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupProfileRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 351; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public GroupProfileRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public GroupProfileRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupProfileReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public byte[] Name; + public byte[] Charter; + public bool ShowInList; + public byte[] MemberTitle; + public ulong PowersMask; + public UUID InsigniaID; + public UUID FounderID; + public int MembershipFee; + public bool OpenEnrollment; + public int Money; + public int GroupMembershipCount; + public int GroupRolesCount; + public bool AllowPublish; + public bool MaturePublish; + public UUID OwnerRole; + + public override int Length + { + get + { + int length = 96; + if (Name != null) { length += Name.Length; } + if (Charter != null) { length += Charter.Length; } + if (MemberTitle != null) { length += MemberTitle.Length; } + return length; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GroupID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Charter = new byte[length]; + Buffer.BlockCopy(bytes, i, Charter, 0, length); i += length; + ShowInList = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + MemberTitle = new byte[length]; + Buffer.BlockCopy(bytes, i, MemberTitle, 0, length); i += length; + PowersMask = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + InsigniaID.FromBytes(bytes, i); i += 16; + FounderID.FromBytes(bytes, i); i += 16; + MembershipFee = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OpenEnrollment = (bytes[i++] != 0) ? (bool)true : (bool)false; + Money = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMembershipCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupRolesCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AllowPublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + MaturePublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + OwnerRole.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)(Charter.Length % 256); + bytes[i++] = (byte)((Charter.Length >> 8) % 256); + Buffer.BlockCopy(Charter, 0, bytes, i, Charter.Length); i += Charter.Length; + bytes[i++] = (byte)((ShowInList) ? 1 : 0); + bytes[i++] = (byte)MemberTitle.Length; + Buffer.BlockCopy(MemberTitle, 0, bytes, i, MemberTitle.Length); i += MemberTitle.Length; + Utils.UInt64ToBytes(PowersMask, bytes, i); i += 8; + InsigniaID.ToBytes(bytes, i); i += 16; + FounderID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(MembershipFee, bytes, i); i += 4; + bytes[i++] = (byte)((OpenEnrollment) ? 1 : 0); + Utils.IntToBytes(Money, bytes, i); i += 4; + Utils.IntToBytes(GroupMembershipCount, bytes, i); i += 4; + Utils.IntToBytes(GroupRolesCount, bytes, i); i += 4; + bytes[i++] = (byte)((AllowPublish) ? 1 : 0); + bytes[i++] = (byte)((MaturePublish) ? 1 : 0); + OwnerRole.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public GroupProfileReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupProfileReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 352; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public GroupProfileReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public GroupProfileReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupAccountSummaryRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID RequestID; + public int IntervalDays; + public int CurrentInterval; + + public override int Length + { + get + { + return 24; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RequestID.FromBytes(bytes, i); i += 16; + IntervalDays = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CurrentInterval = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(IntervalDays, bytes, i); i += 4; + Utils.IntToBytes(CurrentInterval, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + + public GroupAccountSummaryRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupAccountSummaryRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 353; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + } + + public GroupAccountSummaryRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public GroupAccountSummaryRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupAccountSummaryReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID RequestID; + public int IntervalDays; + public int CurrentInterval; + public byte[] StartDate; + public int Balance; + public int TotalCredits; + public int TotalDebits; + public int ObjectTaxCurrent; + public int LightTaxCurrent; + public int LandTaxCurrent; + public int GroupTaxCurrent; + public int ParcelDirFeeCurrent; + public int ObjectTaxEstimate; + public int LightTaxEstimate; + public int LandTaxEstimate; + public int GroupTaxEstimate; + public int ParcelDirFeeEstimate; + public int NonExemptMembers; + public byte[] LastTaxDate; + public byte[] TaxDate; + + public override int Length + { + get + { + int length = 83; + if (StartDate != null) { length += StartDate.Length; } + if (LastTaxDate != null) { length += LastTaxDate.Length; } + if (TaxDate != null) { length += TaxDate.Length; } + return length; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RequestID.FromBytes(bytes, i); i += 16; + IntervalDays = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CurrentInterval = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + StartDate = new byte[length]; + Buffer.BlockCopy(bytes, i, StartDate, 0, length); i += length; + Balance = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TotalCredits = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TotalDebits = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ObjectTaxCurrent = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LightTaxCurrent = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LandTaxCurrent = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupTaxCurrent = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParcelDirFeeCurrent = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ObjectTaxEstimate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LightTaxEstimate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LandTaxEstimate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupTaxEstimate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParcelDirFeeEstimate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NonExemptMembers = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + LastTaxDate = new byte[length]; + Buffer.BlockCopy(bytes, i, LastTaxDate, 0, length); i += length; + length = bytes[i++]; + TaxDate = new byte[length]; + Buffer.BlockCopy(bytes, i, TaxDate, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(IntervalDays, bytes, i); i += 4; + Utils.IntToBytes(CurrentInterval, bytes, i); i += 4; + bytes[i++] = (byte)StartDate.Length; + Buffer.BlockCopy(StartDate, 0, bytes, i, StartDate.Length); i += StartDate.Length; + Utils.IntToBytes(Balance, bytes, i); i += 4; + Utils.IntToBytes(TotalCredits, bytes, i); i += 4; + Utils.IntToBytes(TotalDebits, bytes, i); i += 4; + Utils.IntToBytes(ObjectTaxCurrent, bytes, i); i += 4; + Utils.IntToBytes(LightTaxCurrent, bytes, i); i += 4; + Utils.IntToBytes(LandTaxCurrent, bytes, i); i += 4; + Utils.IntToBytes(GroupTaxCurrent, bytes, i); i += 4; + Utils.IntToBytes(ParcelDirFeeCurrent, bytes, i); i += 4; + Utils.IntToBytes(ObjectTaxEstimate, bytes, i); i += 4; + Utils.IntToBytes(LightTaxEstimate, bytes, i); i += 4; + Utils.IntToBytes(LandTaxEstimate, bytes, i); i += 4; + Utils.IntToBytes(GroupTaxEstimate, bytes, i); i += 4; + Utils.IntToBytes(ParcelDirFeeEstimate, bytes, i); i += 4; + Utils.IntToBytes(NonExemptMembers, bytes, i); i += 4; + bytes[i++] = (byte)LastTaxDate.Length; + Buffer.BlockCopy(LastTaxDate, 0, bytes, i, LastTaxDate.Length); i += LastTaxDate.Length; + bytes[i++] = (byte)TaxDate.Length; + Buffer.BlockCopy(TaxDate, 0, bytes, i, TaxDate.Length); i += TaxDate.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + + public GroupAccountSummaryReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupAccountSummaryReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 354; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + } + + public GroupAccountSummaryReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public GroupAccountSummaryReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupAccountDetailsRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID RequestID; + public int IntervalDays; + public int CurrentInterval; + + public override int Length + { + get + { + return 24; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RequestID.FromBytes(bytes, i); i += 16; + IntervalDays = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CurrentInterval = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(IntervalDays, bytes, i); i += 4; + Utils.IntToBytes(CurrentInterval, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + + public GroupAccountDetailsRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupAccountDetailsRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 355; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + } + + public GroupAccountDetailsRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public GroupAccountDetailsRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupAccountDetailsReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID RequestID; + public int IntervalDays; + public int CurrentInterval; + public byte[] StartDate; + + public override int Length + { + get + { + int length = 25; + if (StartDate != null) { length += StartDate.Length; } + return length; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RequestID.FromBytes(bytes, i); i += 16; + IntervalDays = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CurrentInterval = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + StartDate = new byte[length]; + Buffer.BlockCopy(bytes, i, StartDate, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(IntervalDays, bytes, i); i += 4; + Utils.IntToBytes(CurrentInterval, bytes, i); i += 4; + bytes[i++] = (byte)StartDate.Length; + Buffer.BlockCopy(StartDate, 0, bytes, i, StartDate.Length); i += StartDate.Length; + } + + } + + /// + public sealed class HistoryDataBlock : PacketBlock + { + public byte[] Description; + public int Amount; + + public override int Length + { + get + { + int length = 5; + if (Description != null) { length += Description.Length; } + return length; + } + } + + public HistoryDataBlock() { } + public HistoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + Amount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(Amount, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += MoneyData.Length; + for (int j = 0; j < HistoryData.Length; j++) + length += HistoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + public HistoryDataBlock[] HistoryData; + + public GroupAccountDetailsReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupAccountDetailsReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 356; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + HistoryData = null; + } + + public GroupAccountDetailsReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(HistoryData == null || HistoryData.Length != -1) { + HistoryData = new HistoryDataBlock[count]; + for(int j = 0; j < count; j++) + { HistoryData[j] = new HistoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { HistoryData[j].FromBytes(bytes, ref i); } + } + + public GroupAccountDetailsReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(HistoryData == null || HistoryData.Length != count) { + HistoryData = new HistoryDataBlock[count]; + for(int j = 0; j < count; j++) + { HistoryData[j] = new HistoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { HistoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + length++; + for (int j = 0; j < HistoryData.Length; j++) { length += HistoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + bytes[i++] = (byte)HistoryData.Length; + for (int j = 0; j < HistoryData.Length; j++) { HistoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += MoneyData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + MoneyData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int HistoryDataStart = 0; + do + { + int variableLength = 0; + int HistoryDataCount = 0; + + i = HistoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < HistoryData.Length) { + int blockLength = HistoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++HistoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)HistoryDataCount; + for (i = HistoryDataStart; i < HistoryDataStart + HistoryDataCount; i++) { HistoryData[i].ToBytes(packet, ref length); } + HistoryDataStart += HistoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + HistoryDataStart < HistoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupAccountTransactionsRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID RequestID; + public int IntervalDays; + public int CurrentInterval; + + public override int Length + { + get + { + return 24; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RequestID.FromBytes(bytes, i); i += 16; + IntervalDays = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CurrentInterval = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(IntervalDays, bytes, i); i += 4; + Utils.IntToBytes(CurrentInterval, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + + public GroupAccountTransactionsRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupAccountTransactionsRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 357; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + } + + public GroupAccountTransactionsRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public GroupAccountTransactionsRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupAccountTransactionsReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class MoneyDataBlock : PacketBlock + { + public UUID RequestID; + public int IntervalDays; + public int CurrentInterval; + public byte[] StartDate; + + public override int Length + { + get + { + int length = 25; + if (StartDate != null) { length += StartDate.Length; } + return length; + } + } + + public MoneyDataBlock() { } + public MoneyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RequestID.FromBytes(bytes, i); i += 16; + IntervalDays = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CurrentInterval = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + StartDate = new byte[length]; + Buffer.BlockCopy(bytes, i, StartDate, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(IntervalDays, bytes, i); i += 4; + Utils.IntToBytes(CurrentInterval, bytes, i); i += 4; + bytes[i++] = (byte)StartDate.Length; + Buffer.BlockCopy(StartDate, 0, bytes, i, StartDate.Length); i += StartDate.Length; + } + + } + + /// + public sealed class HistoryDataBlock : PacketBlock + { + public byte[] Time; + public byte[] User; + public int Type; + public byte[] Item; + public int Amount; + + public override int Length + { + get + { + int length = 11; + if (Time != null) { length += Time.Length; } + if (User != null) { length += User.Length; } + if (Item != null) { length += Item.Length; } + return length; + } + } + + public HistoryDataBlock() { } + public HistoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Time = new byte[length]; + Buffer.BlockCopy(bytes, i, Time, 0, length); i += length; + length = bytes[i++]; + User = new byte[length]; + Buffer.BlockCopy(bytes, i, User, 0, length); i += length; + Type = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Item = new byte[length]; + Buffer.BlockCopy(bytes, i, Item, 0, length); i += length; + Amount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Time.Length; + Buffer.BlockCopy(Time, 0, bytes, i, Time.Length); i += Time.Length; + bytes[i++] = (byte)User.Length; + Buffer.BlockCopy(User, 0, bytes, i, User.Length); i += User.Length; + Utils.IntToBytes(Type, bytes, i); i += 4; + bytes[i++] = (byte)Item.Length; + Buffer.BlockCopy(Item, 0, bytes, i, Item.Length); i += Item.Length; + Utils.IntToBytes(Amount, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += MoneyData.Length; + for (int j = 0; j < HistoryData.Length; j++) + length += HistoryData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public MoneyDataBlock MoneyData; + public HistoryDataBlock[] HistoryData; + + public GroupAccountTransactionsReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupAccountTransactionsReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 358; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + MoneyData = new MoneyDataBlock(); + HistoryData = null; + } + + public GroupAccountTransactionsReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(HistoryData == null || HistoryData.Length != -1) { + HistoryData = new HistoryDataBlock[count]; + for(int j = 0; j < count; j++) + { HistoryData[j] = new HistoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { HistoryData[j].FromBytes(bytes, ref i); } + } + + public GroupAccountTransactionsReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + MoneyData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(HistoryData == null || HistoryData.Length != count) { + HistoryData = new HistoryDataBlock[count]; + for(int j = 0; j < count; j++) + { HistoryData[j] = new HistoryDataBlock(); } + } + for (int j = 0; j < count; j++) + { HistoryData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += MoneyData.Length; + length++; + for (int j = 0; j < HistoryData.Length; j++) { length += HistoryData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + MoneyData.ToBytes(bytes, ref i); + bytes[i++] = (byte)HistoryData.Length; + for (int j = 0; j < HistoryData.Length; j++) { HistoryData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += MoneyData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + MoneyData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int HistoryDataStart = 0; + do + { + int variableLength = 0; + int HistoryDataCount = 0; + + i = HistoryDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < HistoryData.Length) { + int blockLength = HistoryData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++HistoryDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)HistoryDataCount; + for (i = HistoryDataStart; i < HistoryDataStart + HistoryDataCount; i++) { HistoryData[i].ToBytes(packet, ref length); } + HistoryDataStart += HistoryDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + HistoryDataStart < HistoryData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupActiveProposalsRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionDataBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionDataBlock() { } + public TransactionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length += TransactionData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + public TransactionDataBlock TransactionData; + + public GroupActiveProposalsRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupActiveProposalsRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 359; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + TransactionData = new TransactionDataBlock(); + } + + public GroupActiveProposalsRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + } + + public GroupActiveProposalsRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length += TransactionData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + TransactionData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupActiveProposalItemReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionDataBlock : PacketBlock + { + public UUID TransactionID; + public uint TotalNumItems; + + public override int Length + { + get + { + return 20; + } + } + + public TransactionDataBlock() { } + public TransactionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + TotalNumItems = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(TotalNumItems, bytes, i); i += 4; + } + + } + + /// + public sealed class ProposalDataBlock : PacketBlock + { + public UUID VoteID; + public UUID VoteInitiator; + public byte[] TerseDateID; + public byte[] StartDateTime; + public byte[] EndDateTime; + public bool AlreadyVoted; + public byte[] VoteCast; + public float Majority; + public int Quorum; + public byte[] ProposalText; + + public override int Length + { + get + { + int length = 46; + if (TerseDateID != null) { length += TerseDateID.Length; } + if (StartDateTime != null) { length += StartDateTime.Length; } + if (EndDateTime != null) { length += EndDateTime.Length; } + if (VoteCast != null) { length += VoteCast.Length; } + if (ProposalText != null) { length += ProposalText.Length; } + return length; + } + } + + public ProposalDataBlock() { } + public ProposalDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + VoteID.FromBytes(bytes, i); i += 16; + VoteInitiator.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + TerseDateID = new byte[length]; + Buffer.BlockCopy(bytes, i, TerseDateID, 0, length); i += length; + length = bytes[i++]; + StartDateTime = new byte[length]; + Buffer.BlockCopy(bytes, i, StartDateTime, 0, length); i += length; + length = bytes[i++]; + EndDateTime = new byte[length]; + Buffer.BlockCopy(bytes, i, EndDateTime, 0, length); i += length; + AlreadyVoted = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + VoteCast = new byte[length]; + Buffer.BlockCopy(bytes, i, VoteCast, 0, length); i += length; + Majority = Utils.BytesToFloat(bytes, i); i += 4; + Quorum = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + ProposalText = new byte[length]; + Buffer.BlockCopy(bytes, i, ProposalText, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + VoteID.ToBytes(bytes, i); i += 16; + VoteInitiator.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)TerseDateID.Length; + Buffer.BlockCopy(TerseDateID, 0, bytes, i, TerseDateID.Length); i += TerseDateID.Length; + bytes[i++] = (byte)StartDateTime.Length; + Buffer.BlockCopy(StartDateTime, 0, bytes, i, StartDateTime.Length); i += StartDateTime.Length; + bytes[i++] = (byte)EndDateTime.Length; + Buffer.BlockCopy(EndDateTime, 0, bytes, i, EndDateTime.Length); i += EndDateTime.Length; + bytes[i++] = (byte)((AlreadyVoted) ? 1 : 0); + bytes[i++] = (byte)VoteCast.Length; + Buffer.BlockCopy(VoteCast, 0, bytes, i, VoteCast.Length); i += VoteCast.Length; + Utils.FloatToBytes(Majority, bytes, i); i += 4; + Utils.IntToBytes(Quorum, bytes, i); i += 4; + bytes[i++] = (byte)ProposalText.Length; + Buffer.BlockCopy(ProposalText, 0, bytes, i, ProposalText.Length); i += ProposalText.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += TransactionData.Length; + for (int j = 0; j < ProposalData.Length; j++) + length += ProposalData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionDataBlock TransactionData; + public ProposalDataBlock[] ProposalData; + + public GroupActiveProposalItemReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupActiveProposalItemReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 360; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + TransactionData = new TransactionDataBlock(); + ProposalData = null; + } + + public GroupActiveProposalItemReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ProposalData == null || ProposalData.Length != -1) { + ProposalData = new ProposalDataBlock[count]; + for(int j = 0; j < count; j++) + { ProposalData[j] = new ProposalDataBlock(); } + } + for (int j = 0; j < count; j++) + { ProposalData[j].FromBytes(bytes, ref i); } + } + + public GroupActiveProposalItemReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ProposalData == null || ProposalData.Length != count) { + ProposalData = new ProposalDataBlock[count]; + for(int j = 0; j < count; j++) + { ProposalData[j] = new ProposalDataBlock(); } + } + for (int j = 0; j < count; j++) + { ProposalData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionData.Length; + length++; + for (int j = 0; j < ProposalData.Length; j++) { length += ProposalData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ProposalData.Length; + for (int j = 0; j < ProposalData.Length; j++) { ProposalData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += TransactionData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + TransactionData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ProposalDataStart = 0; + do + { + int variableLength = 0; + int ProposalDataCount = 0; + + i = ProposalDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ProposalData.Length) { + int blockLength = ProposalData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ProposalDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ProposalDataCount; + for (i = ProposalDataStart; i < ProposalDataStart + ProposalDataCount; i++) { ProposalData[i].ToBytes(packet, ref length); } + ProposalDataStart += ProposalDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ProposalDataStart < ProposalData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupVoteHistoryRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + + public override int Length + { + get + { + return 16; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionDataBlock : PacketBlock + { + public UUID TransactionID; + + public override int Length + { + get + { + return 16; + } + } + + public TransactionDataBlock() { } + public TransactionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length += TransactionData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + public TransactionDataBlock TransactionData; + + public GroupVoteHistoryRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupVoteHistoryRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 361; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + TransactionData = new TransactionDataBlock(); + } + + public GroupVoteHistoryRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + } + + public GroupVoteHistoryRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length += TransactionData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + TransactionData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupVoteHistoryItemReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TransactionDataBlock : PacketBlock + { + public UUID TransactionID; + public uint TotalNumItems; + + public override int Length + { + get + { + return 20; + } + } + + public TransactionDataBlock() { } + public TransactionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TransactionID.FromBytes(bytes, i); i += 16; + TotalNumItems = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransactionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(TotalNumItems, bytes, i); i += 4; + } + + } + + /// + public sealed class HistoryItemDataBlock : PacketBlock + { + public UUID VoteID; + public byte[] TerseDateID; + public byte[] StartDateTime; + public byte[] EndDateTime; + public UUID VoteInitiator; + public byte[] VoteType; + public byte[] VoteResult; + public float Majority; + public int Quorum; + public byte[] ProposalText; + + public override int Length + { + get + { + int length = 47; + if (TerseDateID != null) { length += TerseDateID.Length; } + if (StartDateTime != null) { length += StartDateTime.Length; } + if (EndDateTime != null) { length += EndDateTime.Length; } + if (VoteType != null) { length += VoteType.Length; } + if (VoteResult != null) { length += VoteResult.Length; } + if (ProposalText != null) { length += ProposalText.Length; } + return length; + } + } + + public HistoryItemDataBlock() { } + public HistoryItemDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + VoteID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + TerseDateID = new byte[length]; + Buffer.BlockCopy(bytes, i, TerseDateID, 0, length); i += length; + length = bytes[i++]; + StartDateTime = new byte[length]; + Buffer.BlockCopy(bytes, i, StartDateTime, 0, length); i += length; + length = bytes[i++]; + EndDateTime = new byte[length]; + Buffer.BlockCopy(bytes, i, EndDateTime, 0, length); i += length; + VoteInitiator.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + VoteType = new byte[length]; + Buffer.BlockCopy(bytes, i, VoteType, 0, length); i += length; + length = bytes[i++]; + VoteResult = new byte[length]; + Buffer.BlockCopy(bytes, i, VoteResult, 0, length); i += length; + Majority = Utils.BytesToFloat(bytes, i); i += 4; + Quorum = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = (bytes[i++] + (bytes[i++] << 8)); + ProposalText = new byte[length]; + Buffer.BlockCopy(bytes, i, ProposalText, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + VoteID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)TerseDateID.Length; + Buffer.BlockCopy(TerseDateID, 0, bytes, i, TerseDateID.Length); i += TerseDateID.Length; + bytes[i++] = (byte)StartDateTime.Length; + Buffer.BlockCopy(StartDateTime, 0, bytes, i, StartDateTime.Length); i += StartDateTime.Length; + bytes[i++] = (byte)EndDateTime.Length; + Buffer.BlockCopy(EndDateTime, 0, bytes, i, EndDateTime.Length); i += EndDateTime.Length; + VoteInitiator.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)VoteType.Length; + Buffer.BlockCopy(VoteType, 0, bytes, i, VoteType.Length); i += VoteType.Length; + bytes[i++] = (byte)VoteResult.Length; + Buffer.BlockCopy(VoteResult, 0, bytes, i, VoteResult.Length); i += VoteResult.Length; + Utils.FloatToBytes(Majority, bytes, i); i += 4; + Utils.IntToBytes(Quorum, bytes, i); i += 4; + bytes[i++] = (byte)(ProposalText.Length % 256); + bytes[i++] = (byte)((ProposalText.Length >> 8) % 256); + Buffer.BlockCopy(ProposalText, 0, bytes, i, ProposalText.Length); i += ProposalText.Length; + } + + } + + /// + public sealed class VoteItemBlock : PacketBlock + { + public UUID CandidateID; + public byte[] VoteCast; + public int NumVotes; + + public override int Length + { + get + { + int length = 21; + if (VoteCast != null) { length += VoteCast.Length; } + return length; + } + } + + public VoteItemBlock() { } + public VoteItemBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + CandidateID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + VoteCast = new byte[length]; + Buffer.BlockCopy(bytes, i, VoteCast, 0, length); i += length; + NumVotes = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + CandidateID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)VoteCast.Length; + Buffer.BlockCopy(VoteCast, 0, bytes, i, VoteCast.Length); i += VoteCast.Length; + Utils.IntToBytes(NumVotes, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += TransactionData.Length; + length += HistoryItemData.Length; + for (int j = 0; j < VoteItem.Length; j++) + length += VoteItem[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public TransactionDataBlock TransactionData; + public HistoryItemDataBlock HistoryItemData; + public VoteItemBlock[] VoteItem; + + public GroupVoteHistoryItemReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupVoteHistoryItemReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 362; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + TransactionData = new TransactionDataBlock(); + HistoryItemData = new HistoryItemDataBlock(); + VoteItem = null; + } + + public GroupVoteHistoryItemReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + HistoryItemData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(VoteItem == null || VoteItem.Length != -1) { + VoteItem = new VoteItemBlock[count]; + for(int j = 0; j < count; j++) + { VoteItem[j] = new VoteItemBlock(); } + } + for (int j = 0; j < count; j++) + { VoteItem[j].FromBytes(bytes, ref i); } + } + + public GroupVoteHistoryItemReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TransactionData.FromBytes(bytes, ref i); + HistoryItemData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(VoteItem == null || VoteItem.Length != count) { + VoteItem = new VoteItemBlock[count]; + for(int j = 0; j < count; j++) + { VoteItem[j] = new VoteItemBlock(); } + } + for (int j = 0; j < count; j++) + { VoteItem[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += TransactionData.Length; + length += HistoryItemData.Length; + length++; + for (int j = 0; j < VoteItem.Length; j++) { length += VoteItem[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TransactionData.ToBytes(bytes, ref i); + HistoryItemData.ToBytes(bytes, ref i); + bytes[i++] = (byte)VoteItem.Length; + for (int j = 0; j < VoteItem.Length; j++) { VoteItem[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += TransactionData.Length; + fixedLength += HistoryItemData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + TransactionData.ToBytes(fixedBytes, ref i); + HistoryItemData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int VoteItemStart = 0; + do + { + int variableLength = 0; + int VoteItemCount = 0; + + i = VoteItemStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < VoteItem.Length) { + int blockLength = VoteItem[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++VoteItemCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)VoteItemCount; + for (i = VoteItemStart; i < VoteItemStart + VoteItemCount; i++) { VoteItem[i].ToBytes(packet, ref length); } + VoteItemStart += VoteItemCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + VoteItemStart < VoteItem.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class StartGroupProposalPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ProposalDataBlock : PacketBlock + { + public UUID GroupID; + public int Quorum; + public float Majority; + public int Duration; + public byte[] ProposalText; + + public override int Length + { + get + { + int length = 29; + if (ProposalText != null) { length += ProposalText.Length; } + return length; + } + } + + public ProposalDataBlock() { } + public ProposalDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GroupID.FromBytes(bytes, i); i += 16; + Quorum = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Majority = Utils.BytesToFloat(bytes, i); i += 4; + Duration = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + ProposalText = new byte[length]; + Buffer.BlockCopy(bytes, i, ProposalText, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Quorum, bytes, i); i += 4; + Utils.FloatToBytes(Majority, bytes, i); i += 4; + Utils.IntToBytes(Duration, bytes, i); i += 4; + bytes[i++] = (byte)ProposalText.Length; + Buffer.BlockCopy(ProposalText, 0, bytes, i, ProposalText.Length); i += ProposalText.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ProposalData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ProposalDataBlock ProposalData; + + public StartGroupProposalPacket() + { + HasVariableBlocks = false; + Type = PacketType.StartGroupProposal; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 363; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ProposalData = new ProposalDataBlock(); + } + + public StartGroupProposalPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ProposalData.FromBytes(bytes, ref i); + } + + public StartGroupProposalPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ProposalData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ProposalData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ProposalData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupProposalBallotPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ProposalDataBlock : PacketBlock + { + public UUID ProposalID; + public UUID GroupID; + public byte[] VoteCast; + + public override int Length + { + get + { + int length = 33; + if (VoteCast != null) { length += VoteCast.Length; } + return length; + } + } + + public ProposalDataBlock() { } + public ProposalDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ProposalID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + VoteCast = new byte[length]; + Buffer.BlockCopy(bytes, i, VoteCast, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ProposalID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)VoteCast.Length; + Buffer.BlockCopy(VoteCast, 0, bytes, i, VoteCast.Length); i += VoteCast.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ProposalData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ProposalDataBlock ProposalData; + + public GroupProposalBallotPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupProposalBallot; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 364; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ProposalData = new ProposalDataBlock(); + } + + public GroupProposalBallotPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ProposalData.FromBytes(bytes, ref i); + } + + public GroupProposalBallotPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ProposalData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ProposalData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ProposalData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupMembersRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public UUID RequestID; + + public override int Length + { + get + { + return 32; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public GroupMembersRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupMembersRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 366; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public GroupMembersRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public GroupMembersRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupMembersReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public UUID RequestID; + public int MemberCount; + + public override int Length + { + get + { + return 36; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + MemberCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(MemberCount, bytes, i); i += 4; + } + + } + + /// + public sealed class MemberDataBlock : PacketBlock + { + public UUID AgentID; + public int Contribution; + public byte[] OnlineStatus; + public ulong AgentPowers; + public byte[] Title; + public bool IsOwner; + + public override int Length + { + get + { + int length = 31; + if (OnlineStatus != null) { length += OnlineStatus.Length; } + if (Title != null) { length += Title.Length; } + return length; + } + } + + public MemberDataBlock() { } + public MemberDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + Contribution = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + OnlineStatus = new byte[length]; + Buffer.BlockCopy(bytes, i, OnlineStatus, 0, length); i += length; + AgentPowers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + length = bytes[i++]; + Title = new byte[length]; + Buffer.BlockCopy(bytes, i, Title, 0, length); i += length; + IsOwner = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Contribution, bytes, i); i += 4; + bytes[i++] = (byte)OnlineStatus.Length; + Buffer.BlockCopy(OnlineStatus, 0, bytes, i, OnlineStatus.Length); i += OnlineStatus.Length; + Utils.UInt64ToBytes(AgentPowers, bytes, i); i += 8; + bytes[i++] = (byte)Title.Length; + Buffer.BlockCopy(Title, 0, bytes, i, Title.Length); i += Title.Length; + bytes[i++] = (byte)((IsOwner) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += GroupData.Length; + for (int j = 0; j < MemberData.Length; j++) + length += MemberData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + public MemberDataBlock[] MemberData; + + public GroupMembersReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupMembersReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 367; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + MemberData = null; + } + + public GroupMembersReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(MemberData == null || MemberData.Length != -1) { + MemberData = new MemberDataBlock[count]; + for(int j = 0; j < count; j++) + { MemberData[j] = new MemberDataBlock(); } + } + for (int j = 0; j < count; j++) + { MemberData[j].FromBytes(bytes, ref i); } + } + + public GroupMembersReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(MemberData == null || MemberData.Length != count) { + MemberData = new MemberDataBlock[count]; + for(int j = 0; j < count; j++) + { MemberData[j] = new MemberDataBlock(); } + } + for (int j = 0; j < count; j++) + { MemberData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length++; + for (int j = 0; j < MemberData.Length; j++) { length += MemberData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + bytes[i++] = (byte)MemberData.Length; + for (int j = 0; j < MemberData.Length; j++) { MemberData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += GroupData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + GroupData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int MemberDataStart = 0; + do + { + int variableLength = 0; + int MemberDataCount = 0; + + i = MemberDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < MemberData.Length) { + int blockLength = MemberData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++MemberDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)MemberDataCount; + for (i = MemberDataStart; i < MemberDataStart + MemberDataCount; i++) { MemberData[i].ToBytes(packet, ref length); } + MemberDataStart += MemberDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + MemberDataStart < MemberData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ActivateGroupPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public ActivateGroupPacket() + { + HasVariableBlocks = false; + Type = PacketType.ActivateGroup; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 368; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + } + + public ActivateGroupPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public ActivateGroupPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SetGroupContributionPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID GroupID; + public int Contribution; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + Contribution = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Contribution, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public SetGroupContributionPacket() + { + HasVariableBlocks = false; + Type = PacketType.SetGroupContribution; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 369; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public SetGroupContributionPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public SetGroupContributionPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SetGroupAcceptNoticesPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public UUID GroupID; + public bool AcceptNotices; + + public override int Length + { + get + { + return 17; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + AcceptNotices = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((AcceptNotices) ? 1 : 0); + } + + } + + /// + public sealed class NewDataBlock : PacketBlock + { + public bool ListInProfile; + + public override int Length + { + get + { + return 1; + } + } + + public NewDataBlock() { } + public NewDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ListInProfile = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((ListInProfile) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length += NewData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + public NewDataBlock NewData; + + public SetGroupAcceptNoticesPacket() + { + HasVariableBlocks = false; + Type = PacketType.SetGroupAcceptNotices; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 370; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + NewData = new NewDataBlock(); + } + + public SetGroupAcceptNoticesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + NewData.FromBytes(bytes, ref i); + } + + public SetGroupAcceptNoticesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + NewData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + length += NewData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + NewData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupRoleDataRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public UUID RequestID; + + public override int Length + { + get + { + return 32; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public GroupRoleDataRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupRoleDataRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 371; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public GroupRoleDataRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public GroupRoleDataRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupRoleDataReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public UUID RequestID; + public int RoleCount; + + public override int Length + { + get + { + return 36; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + RoleCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(RoleCount, bytes, i); i += 4; + } + + } + + /// + public sealed class RoleDataBlock : PacketBlock + { + public UUID RoleID; + public byte[] Name; + public byte[] Title; + public byte[] Description; + public ulong Powers; + public uint Members; + + public override int Length + { + get + { + int length = 31; + if (Name != null) { length += Name.Length; } + if (Title != null) { length += Title.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public RoleDataBlock() { } + public RoleDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RoleID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Title = new byte[length]; + Buffer.BlockCopy(bytes, i, Title, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + Powers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + Members = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RoleID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Title.Length; + Buffer.BlockCopy(Title, 0, bytes, i, Title.Length); i += Title.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.UInt64ToBytes(Powers, bytes, i); i += 8; + Utils.UIntToBytes(Members, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += GroupData.Length; + for (int j = 0; j < RoleData.Length; j++) + length += RoleData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + public RoleDataBlock[] RoleData; + + public GroupRoleDataReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupRoleDataReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 372; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + RoleData = null; + } + + public GroupRoleDataReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RoleData == null || RoleData.Length != -1) { + RoleData = new RoleDataBlock[count]; + for(int j = 0; j < count; j++) + { RoleData[j] = new RoleDataBlock(); } + } + for (int j = 0; j < count; j++) + { RoleData[j].FromBytes(bytes, ref i); } + } + + public GroupRoleDataReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RoleData == null || RoleData.Length != count) { + RoleData = new RoleDataBlock[count]; + for(int j = 0; j < count; j++) + { RoleData[j] = new RoleDataBlock(); } + } + for (int j = 0; j < count; j++) + { RoleData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + length++; + for (int j = 0; j < RoleData.Length; j++) { length += RoleData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + bytes[i++] = (byte)RoleData.Length; + for (int j = 0; j < RoleData.Length; j++) { RoleData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += GroupData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + GroupData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RoleDataStart = 0; + do + { + int variableLength = 0; + int RoleDataCount = 0; + + i = RoleDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < RoleData.Length) { + int blockLength = RoleData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RoleDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RoleDataCount; + for (i = RoleDataStart; i < RoleDataStart + RoleDataCount; i++) { RoleData[i].ToBytes(packet, ref length); } + RoleDataStart += RoleDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RoleDataStart < RoleData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupRoleMembersRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public UUID RequestID; + + public override int Length + { + get + { + return 32; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock GroupData; + + public GroupRoleMembersRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupRoleMembersRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 373; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + GroupData = new GroupDataBlock(); + } + + public GroupRoleMembersRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public GroupRoleMembersRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + GroupData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += GroupData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + GroupData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupRoleMembersReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + public UUID RequestID; + public uint TotalPairs; + + public override int Length + { + get + { + return 52; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + TotalPairs = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(TotalPairs, bytes, i); i += 4; + } + + } + + /// + public sealed class MemberDataBlock : PacketBlock + { + public UUID RoleID; + public UUID MemberID; + + public override int Length + { + get + { + return 32; + } + } + + public MemberDataBlock() { } + public MemberDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RoleID.FromBytes(bytes, i); i += 16; + MemberID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RoleID.ToBytes(bytes, i); i += 16; + MemberID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < MemberData.Length; j++) + length += MemberData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public MemberDataBlock[] MemberData; + + public GroupRoleMembersReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupRoleMembersReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 374; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + MemberData = null; + } + + public GroupRoleMembersReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(MemberData == null || MemberData.Length != -1) { + MemberData = new MemberDataBlock[count]; + for(int j = 0; j < count; j++) + { MemberData[j] = new MemberDataBlock(); } + } + for (int j = 0; j < count; j++) + { MemberData[j].FromBytes(bytes, ref i); } + } + + public GroupRoleMembersReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(MemberData == null || MemberData.Length != count) { + MemberData = new MemberDataBlock[count]; + for(int j = 0; j < count; j++) + { MemberData[j] = new MemberDataBlock(); } + } + for (int j = 0; j < count; j++) + { MemberData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < MemberData.Length; j++) { length += MemberData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)MemberData.Length; + for (int j = 0; j < MemberData.Length; j++) { MemberData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int MemberDataStart = 0; + do + { + int variableLength = 0; + int MemberDataCount = 0; + + i = MemberDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < MemberData.Length) { + int blockLength = MemberData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++MemberDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)MemberDataCount; + for (i = MemberDataStart; i < MemberDataStart + MemberDataCount; i++) { MemberData[i].ToBytes(packet, ref length); } + MemberDataStart += MemberDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + MemberDataStart < MemberData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupTitlesRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + public UUID RequestID; + + public override int Length + { + get + { + return 64; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public GroupTitlesRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupTitlesRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 375; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public GroupTitlesRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public GroupTitlesRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupTitlesReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + public UUID RequestID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + RequestID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + RequestID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public byte[] Title; + public UUID RoleID; + public bool Selected; + + public override int Length + { + get + { + int length = 18; + if (Title != null) { length += Title.Length; } + return length; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Title = new byte[length]; + Buffer.BlockCopy(bytes, i, Title, 0, length); i += length; + RoleID.FromBytes(bytes, i); i += 16; + Selected = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Title.Length; + Buffer.BlockCopy(Title, 0, bytes, i, Title.Length); i += Title.Length; + RoleID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((Selected) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < GroupData.Length; j++) + length += GroupData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock[] GroupData; + + public GroupTitlesReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupTitlesReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 376; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = null; + } + + public GroupTitlesReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != -1) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + } + + public GroupTitlesReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != count) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < GroupData.Length; j++) { length += GroupData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)GroupData.Length; + for (int j = 0; j < GroupData.Length; j++) { GroupData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int GroupDataStart = 0; + do + { + int variableLength = 0; + int GroupDataCount = 0; + + i = GroupDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < GroupData.Length) { + int blockLength = GroupData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++GroupDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)GroupDataCount; + for (i = GroupDataStart; i < GroupDataStart + GroupDataCount; i++) { GroupData[i].ToBytes(packet, ref length); } + GroupDataStart += GroupDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + GroupDataStart < GroupData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class GroupTitleUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + public UUID TitleRoleID; + + public override int Length + { + get + { + return 64; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + TitleRoleID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + TitleRoleID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public GroupTitleUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.GroupTitleUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 377; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public GroupTitleUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public GroupTitleUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupRoleUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RoleDataBlock : PacketBlock + { + public UUID RoleID; + public byte[] Name; + public byte[] Description; + public byte[] Title; + public ulong Powers; + public byte UpdateType; + + public override int Length + { + get + { + int length = 28; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + if (Title != null) { length += Title.Length; } + return length; + } + } + + public RoleDataBlock() { } + public RoleDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RoleID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + length = bytes[i++]; + Title = new byte[length]; + Buffer.BlockCopy(bytes, i, Title, 0, length); i += length; + Powers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + UpdateType = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RoleID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + bytes[i++] = (byte)Title.Length; + Buffer.BlockCopy(Title, 0, bytes, i, Title.Length); i += Title.Length; + Utils.UInt64ToBytes(Powers, bytes, i); i += 8; + bytes[i++] = UpdateType; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < RoleData.Length; j++) + length += RoleData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RoleDataBlock[] RoleData; + + public GroupRoleUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupRoleUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 378; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RoleData = null; + } + + public GroupRoleUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RoleData == null || RoleData.Length != -1) { + RoleData = new RoleDataBlock[count]; + for(int j = 0; j < count; j++) + { RoleData[j] = new RoleDataBlock(); } + } + for (int j = 0; j < count; j++) + { RoleData[j].FromBytes(bytes, ref i); } + } + + public GroupRoleUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RoleData == null || RoleData.Length != count) { + RoleData = new RoleDataBlock[count]; + for(int j = 0; j < count; j++) + { RoleData[j] = new RoleDataBlock(); } + } + for (int j = 0; j < count; j++) + { RoleData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < RoleData.Length; j++) { length += RoleData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)RoleData.Length; + for (int j = 0; j < RoleData.Length; j++) { RoleData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RoleDataStart = 0; + do + { + int variableLength = 0; + int RoleDataCount = 0; + + i = RoleDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < RoleData.Length) { + int blockLength = RoleData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RoleDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RoleDataCount; + for (i = RoleDataStart; i < RoleDataStart + RoleDataCount; i++) { RoleData[i].ToBytes(packet, ref length); } + RoleDataStart += RoleDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RoleDataStart < RoleData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class LiveHelpGroupRequestPacket : Packet + { + /// + public sealed class RequestDataBlock : PacketBlock + { + public UUID RequestID; + public UUID AgentID; + + public override int Length + { + get + { + return 32; + } + } + + public RequestDataBlock() { } + public RequestDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RequestID.FromBytes(bytes, i); i += 16; + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += RequestData.Length; + return length; + } + } + public RequestDataBlock RequestData; + + public LiveHelpGroupRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.LiveHelpGroupRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 379; + Header.Reliable = true; + RequestData = new RequestDataBlock(); + } + + public LiveHelpGroupRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RequestData.FromBytes(bytes, ref i); + } + + public LiveHelpGroupRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RequestData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += RequestData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RequestData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LiveHelpGroupReplyPacket : Packet + { + /// + public sealed class ReplyDataBlock : PacketBlock + { + public UUID RequestID; + public UUID GroupID; + public byte[] Selection; + + public override int Length + { + get + { + int length = 33; + if (Selection != null) { length += Selection.Length; } + return length; + } + } + + public ReplyDataBlock() { } + public ReplyDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RequestID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Selection = new byte[length]; + Buffer.BlockCopy(bytes, i, Selection, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + RequestID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Selection.Length; + Buffer.BlockCopy(Selection, 0, bytes, i, Selection.Length); i += Selection.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ReplyData.Length; + return length; + } + } + public ReplyDataBlock ReplyData; + + public LiveHelpGroupReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.LiveHelpGroupReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 380; + Header.Reliable = true; + ReplyData = new ReplyDataBlock(); + } + + public LiveHelpGroupReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ReplyData.FromBytes(bytes, ref i); + } + + public LiveHelpGroupReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ReplyData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ReplyData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ReplyData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentWearablesRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentWearablesRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentWearablesRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 381; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public AgentWearablesRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentWearablesRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentWearablesUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint SerialNum; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + SerialNum = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(SerialNum, bytes, i); i += 4; + } + + } + + /// + public sealed class WearableDataBlock : PacketBlock + { + public UUID ItemID; + public UUID AssetID; + public byte WearableType; + + public override int Length + { + get + { + return 33; + } + } + + public WearableDataBlock() { } + public WearableDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + AssetID.FromBytes(bytes, i); i += 16; + WearableType = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + AssetID.ToBytes(bytes, i); i += 16; + bytes[i++] = WearableType; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < WearableData.Length; j++) + length += WearableData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public WearableDataBlock[] WearableData; + + public AgentWearablesUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.AgentWearablesUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 382; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + WearableData = null; + } + + public AgentWearablesUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != -1) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public AgentWearablesUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != count) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < WearableData.Length; j++) { length += WearableData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)WearableData.Length; + for (int j = 0; j < WearableData.Length; j++) { WearableData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int WearableDataStart = 0; + do + { + int variableLength = 0; + int WearableDataCount = 0; + + i = WearableDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < WearableData.Length) { + int blockLength = WearableData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++WearableDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)WearableDataCount; + for (i = WearableDataStart; i < WearableDataStart + WearableDataCount; i++) { WearableData[i].ToBytes(packet, ref length); } + WearableDataStart += WearableDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + WearableDataStart < WearableData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentIsNowWearingPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class WearableDataBlock : PacketBlock + { + public UUID ItemID; + public byte WearableType; + + public override int Length + { + get + { + return 17; + } + } + + public WearableDataBlock() { } + public WearableDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemID.FromBytes(bytes, i); i += 16; + WearableType = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + bytes[i++] = WearableType; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < WearableData.Length; j++) + length += WearableData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public WearableDataBlock[] WearableData; + + public AgentIsNowWearingPacket() + { + HasVariableBlocks = true; + Type = PacketType.AgentIsNowWearing; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 383; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + WearableData = null; + } + + public AgentIsNowWearingPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != -1) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public AgentIsNowWearingPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != count) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < WearableData.Length; j++) { length += WearableData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)WearableData.Length; + for (int j = 0; j < WearableData.Length; j++) { WearableData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int WearableDataStart = 0; + do + { + int variableLength = 0; + int WearableDataCount = 0; + + i = WearableDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < WearableData.Length) { + int blockLength = WearableData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++WearableDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)WearableDataCount; + for (i = WearableDataStart; i < WearableDataStart + WearableDataCount; i++) { WearableData[i].ToBytes(packet, ref length); } + WearableDataStart += WearableDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + WearableDataStart < WearableData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentCachedTexturePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public int SerialNum; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + SerialNum = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(SerialNum, bytes, i); i += 4; + } + + } + + /// + public sealed class WearableDataBlock : PacketBlock + { + public UUID ID; + public byte TextureIndex; + + public override int Length + { + get + { + return 17; + } + } + + public WearableDataBlock() { } + public WearableDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + TextureIndex = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + bytes[i++] = TextureIndex; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < WearableData.Length; j++) + length += WearableData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public WearableDataBlock[] WearableData; + + public AgentCachedTexturePacket() + { + HasVariableBlocks = true; + Type = PacketType.AgentCachedTexture; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 384; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + WearableData = null; + } + + public AgentCachedTexturePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != -1) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public AgentCachedTexturePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != count) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < WearableData.Length; j++) { length += WearableData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)WearableData.Length; + for (int j = 0; j < WearableData.Length; j++) { WearableData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int WearableDataStart = 0; + do + { + int variableLength = 0; + int WearableDataCount = 0; + + i = WearableDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < WearableData.Length) { + int blockLength = WearableData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++WearableDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)WearableDataCount; + for (i = WearableDataStart; i < WearableDataStart + WearableDataCount; i++) { WearableData[i].ToBytes(packet, ref length); } + WearableDataStart += WearableDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + WearableDataStart < WearableData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentCachedTextureResponsePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public int SerialNum; + + public override int Length + { + get + { + return 36; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + SerialNum = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(SerialNum, bytes, i); i += 4; + } + + } + + /// + public sealed class WearableDataBlock : PacketBlock + { + public UUID TextureID; + public byte TextureIndex; + public byte[] HostName; + + public override int Length + { + get + { + int length = 18; + if (HostName != null) { length += HostName.Length; } + return length; + } + } + + public WearableDataBlock() { } + public WearableDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TextureID.FromBytes(bytes, i); i += 16; + TextureIndex = (byte)bytes[i++]; + length = bytes[i++]; + HostName = new byte[length]; + Buffer.BlockCopy(bytes, i, HostName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TextureID.ToBytes(bytes, i); i += 16; + bytes[i++] = TextureIndex; + bytes[i++] = (byte)HostName.Length; + Buffer.BlockCopy(HostName, 0, bytes, i, HostName.Length); i += HostName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < WearableData.Length; j++) + length += WearableData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public WearableDataBlock[] WearableData; + + public AgentCachedTextureResponsePacket() + { + HasVariableBlocks = true; + Type = PacketType.AgentCachedTextureResponse; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 385; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + WearableData = null; + } + + public AgentCachedTextureResponsePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != -1) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public AgentCachedTextureResponsePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(WearableData == null || WearableData.Length != count) { + WearableData = new WearableDataBlock[count]; + for(int j = 0; j < count; j++) + { WearableData[j] = new WearableDataBlock(); } + } + for (int j = 0; j < count; j++) + { WearableData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < WearableData.Length; j++) { length += WearableData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)WearableData.Length; + for (int j = 0; j < WearableData.Length; j++) { WearableData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int WearableDataStart = 0; + do + { + int variableLength = 0; + int WearableDataCount = 0; + + i = WearableDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < WearableData.Length) { + int blockLength = WearableData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++WearableDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)WearableDataCount; + for (i = WearableDataStart; i < WearableDataStart + WearableDataCount; i++) { WearableData[i].ToBytes(packet, ref length); } + WearableDataStart += WearableDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + WearableDataStart < WearableData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentDataUpdateRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentDataUpdateRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentDataUpdateRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 386; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public AgentDataUpdateRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentDataUpdateRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentDataUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public byte[] FirstName; + public byte[] LastName; + public byte[] GroupTitle; + public UUID ActiveGroupID; + public ulong GroupPowers; + public byte[] GroupName; + + public override int Length + { + get + { + int length = 44; + if (FirstName != null) { length += FirstName.Length; } + if (LastName != null) { length += LastName.Length; } + if (GroupTitle != null) { length += GroupTitle.Length; } + if (GroupName != null) { length += GroupName.Length; } + return length; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + FirstName = new byte[length]; + Buffer.BlockCopy(bytes, i, FirstName, 0, length); i += length; + length = bytes[i++]; + LastName = new byte[length]; + Buffer.BlockCopy(bytes, i, LastName, 0, length); i += length; + length = bytes[i++]; + GroupTitle = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupTitle, 0, length); i += length; + ActiveGroupID.FromBytes(bytes, i); i += 16; + GroupPowers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + length = bytes[i++]; + GroupName = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)FirstName.Length; + Buffer.BlockCopy(FirstName, 0, bytes, i, FirstName.Length); i += FirstName.Length; + bytes[i++] = (byte)LastName.Length; + Buffer.BlockCopy(LastName, 0, bytes, i, LastName.Length); i += LastName.Length; + bytes[i++] = (byte)GroupTitle.Length; + Buffer.BlockCopy(GroupTitle, 0, bytes, i, GroupTitle.Length); i += GroupTitle.Length; + ActiveGroupID.ToBytes(bytes, i); i += 16; + Utils.UInt64ToBytes(GroupPowers, bytes, i); i += 8; + bytes[i++] = (byte)GroupName.Length; + Buffer.BlockCopy(GroupName, 0, bytes, i, GroupName.Length); i += GroupName.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentDataUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentDataUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 387; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + } + + public AgentDataUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentDataUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class GroupDataUpdatePacket : Packet + { + /// + public sealed class AgentGroupDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + public ulong AgentPowers; + public byte[] GroupTitle; + + public override int Length + { + get + { + int length = 41; + if (GroupTitle != null) { length += GroupTitle.Length; } + return length; + } + } + + public AgentGroupDataBlock() { } + public AgentGroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + AgentPowers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + length = bytes[i++]; + GroupTitle = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupTitle, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UInt64ToBytes(AgentPowers, bytes, i); i += 8; + bytes[i++] = (byte)GroupTitle.Length; + Buffer.BlockCopy(GroupTitle, 0, bytes, i, GroupTitle.Length); i += GroupTitle.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < AgentGroupData.Length; j++) + length += AgentGroupData[j].Length; + return length; + } + } + public AgentGroupDataBlock[] AgentGroupData; + + public GroupDataUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.GroupDataUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 388; + Header.Reliable = true; + Header.Zerocoded = true; + AgentGroupData = null; + } + + public GroupDataUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(AgentGroupData == null || AgentGroupData.Length != -1) { + AgentGroupData = new AgentGroupDataBlock[count]; + for(int j = 0; j < count; j++) + { AgentGroupData[j] = new AgentGroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { AgentGroupData[j].FromBytes(bytes, ref i); } + } + + public GroupDataUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(AgentGroupData == null || AgentGroupData.Length != count) { + AgentGroupData = new AgentGroupDataBlock[count]; + for(int j = 0; j < count; j++) + { AgentGroupData[j] = new AgentGroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { AgentGroupData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < AgentGroupData.Length; j++) { length += AgentGroupData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)AgentGroupData.Length; + for (int j = 0; j < AgentGroupData.Length; j++) { AgentGroupData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int AgentGroupDataStart = 0; + do + { + int variableLength = 0; + int AgentGroupDataCount = 0; + + i = AgentGroupDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AgentGroupData.Length) { + int blockLength = AgentGroupData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AgentGroupDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)AgentGroupDataCount; + for (i = AgentGroupDataStart; i < AgentGroupDataStart + AgentGroupDataCount; i++) { AgentGroupData[i].ToBytes(packet, ref length); } + AgentGroupDataStart += AgentGroupDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + AgentGroupDataStart < AgentGroupData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentGroupDataUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public ulong GroupPowers; + public bool AcceptNotices; + public UUID GroupInsigniaID; + public int Contribution; + public byte[] GroupName; + + public override int Length + { + get + { + int length = 46; + if (GroupName != null) { length += GroupName.Length; } + return length; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + GroupID.FromBytes(bytes, i); i += 16; + GroupPowers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + AcceptNotices = (bytes[i++] != 0) ? (bool)true : (bool)false; + GroupInsigniaID.FromBytes(bytes, i); i += 16; + Contribution = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + GroupName = new byte[length]; + Buffer.BlockCopy(bytes, i, GroupName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + Utils.UInt64ToBytes(GroupPowers, bytes, i); i += 8; + bytes[i++] = (byte)((AcceptNotices) ? 1 : 0); + GroupInsigniaID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Contribution, bytes, i); i += 4; + bytes[i++] = (byte)GroupName.Length; + Buffer.BlockCopy(GroupName, 0, bytes, i, GroupName.Length); i += GroupName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < GroupData.Length; j++) + length += GroupData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock[] GroupData; + + public AgentGroupDataUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.AgentGroupDataUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 389; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = null; + } + + public AgentGroupDataUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != -1) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + } + + public AgentGroupDataUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != count) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < GroupData.Length; j++) { length += GroupData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)GroupData.Length; + for (int j = 0; j < GroupData.Length; j++) { GroupData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int GroupDataStart = 0; + do + { + int variableLength = 0; + int GroupDataCount = 0; + + i = GroupDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < GroupData.Length) { + int blockLength = GroupData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++GroupDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)GroupDataCount; + for (i = GroupDataStart; i < GroupDataStart + GroupDataCount; i++) { GroupData[i].ToBytes(packet, ref length); } + GroupDataStart += GroupDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + GroupDataStart < GroupData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentDropGroupPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID GroupID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentDropGroupPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentDropGroup; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 390; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + } + + public AgentDropGroupPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentDropGroupPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RezSingleAttachmentFromInvPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ItemID; + public UUID OwnerID; + public byte AttachmentPt; + public uint ItemFlags; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public byte[] Name; + public byte[] Description; + + public override int Length + { + get + { + int length = 51; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + AttachmentPt = (byte)bytes[i++]; + ItemFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = AttachmentPt; + Utils.UIntToBytes(ItemFlags, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + + public RezSingleAttachmentFromInvPacket() + { + HasVariableBlocks = false; + Type = PacketType.RezSingleAttachmentFromInv; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 395; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + } + + public RezSingleAttachmentFromInvPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public RezSingleAttachmentFromInvPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RezMultipleAttachmentsFromInvPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class HeaderDataBlock : PacketBlock + { + public UUID CompoundMsgID; + public byte TotalObjects; + public bool FirstDetachAll; + + public override int Length + { + get + { + return 18; + } + } + + public HeaderDataBlock() { } + public HeaderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + CompoundMsgID.FromBytes(bytes, i); i += 16; + TotalObjects = (byte)bytes[i++]; + FirstDetachAll = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + CompoundMsgID.ToBytes(bytes, i); i += 16; + bytes[i++] = TotalObjects; + bytes[i++] = (byte)((FirstDetachAll) ? 1 : 0); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ItemID; + public UUID OwnerID; + public byte AttachmentPt; + public uint ItemFlags; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public byte[] Name; + public byte[] Description; + + public override int Length + { + get + { + int length = 51; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + AttachmentPt = (byte)bytes[i++]; + ItemFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = AttachmentPt; + Utils.UIntToBytes(ItemFlags, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += HeaderData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public HeaderDataBlock HeaderData; + public ObjectDataBlock[] ObjectData; + + public RezMultipleAttachmentsFromInvPacket() + { + HasVariableBlocks = true; + Type = PacketType.RezMultipleAttachmentsFromInv; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 396; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + HeaderData = new HeaderDataBlock(); + ObjectData = null; + } + + public RezMultipleAttachmentsFromInvPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public RezMultipleAttachmentsFromInvPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += HeaderData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + HeaderData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += HeaderData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + HeaderData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class DetachAttachmentIntoInvPacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID AgentID; + public UUID ItemID; + + public override int Length + { + get + { + return 32; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + ItemID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + ItemID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += ObjectData.Length; + return length; + } + } + public ObjectDataBlock ObjectData; + + public DetachAttachmentIntoInvPacket() + { + HasVariableBlocks = false; + Type = PacketType.DetachAttachmentIntoInv; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 397; + Header.Reliable = true; + ObjectData = new ObjectDataBlock(); + } + + public DetachAttachmentIntoInvPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ObjectData.FromBytes(bytes, ref i); + } + + public DetachAttachmentIntoInvPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CreateNewOutfitAttachmentsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class HeaderDataBlock : PacketBlock + { + public UUID NewFolderID; + + public override int Length + { + get + { + return 16; + } + } + + public HeaderDataBlock() { } + public HeaderDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + NewFolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + NewFolderID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID OldItemID; + public UUID OldFolderID; + + public override int Length + { + get + { + return 32; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + OldItemID.FromBytes(bytes, i); i += 16; + OldFolderID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + OldItemID.ToBytes(bytes, i); i += 16; + OldFolderID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += HeaderData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public HeaderDataBlock HeaderData; + public ObjectDataBlock[] ObjectData; + + public CreateNewOutfitAttachmentsPacket() + { + HasVariableBlocks = true; + Type = PacketType.CreateNewOutfitAttachments; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 398; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + HeaderData = new HeaderDataBlock(); + ObjectData = null; + } + + public CreateNewOutfitAttachmentsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public CreateNewOutfitAttachmentsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + HeaderData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += HeaderData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + HeaderData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += HeaderData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + HeaderData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class UserInfoRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public UserInfoRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.UserInfoRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 399; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public UserInfoRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public UserInfoRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UserInfoReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class UserDataBlock : PacketBlock + { + public bool IMViaEMail; + public byte[] DirectoryVisibility; + public byte[] EMail; + + public override int Length + { + get + { + int length = 4; + if (DirectoryVisibility != null) { length += DirectoryVisibility.Length; } + if (EMail != null) { length += EMail.Length; } + return length; + } + } + + public UserDataBlock() { } + public UserDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + IMViaEMail = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + DirectoryVisibility = new byte[length]; + Buffer.BlockCopy(bytes, i, DirectoryVisibility, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + EMail = new byte[length]; + Buffer.BlockCopy(bytes, i, EMail, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((IMViaEMail) ? 1 : 0); + bytes[i++] = (byte)DirectoryVisibility.Length; + Buffer.BlockCopy(DirectoryVisibility, 0, bytes, i, DirectoryVisibility.Length); i += DirectoryVisibility.Length; + bytes[i++] = (byte)(EMail.Length % 256); + bytes[i++] = (byte)((EMail.Length >> 8) % 256); + Buffer.BlockCopy(EMail, 0, bytes, i, EMail.Length); i += EMail.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += UserData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public UserDataBlock UserData; + + public UserInfoReplyPacket() + { + HasVariableBlocks = false; + Type = PacketType.UserInfoReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 400; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + UserData = new UserDataBlock(); + } + + public UserInfoReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + UserData.FromBytes(bytes, ref i); + } + + public UserInfoReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + UserData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += UserData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + UserData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class UpdateUserInfoPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class UserDataBlock : PacketBlock + { + public bool IMViaEMail; + public byte[] DirectoryVisibility; + + public override int Length + { + get + { + int length = 2; + if (DirectoryVisibility != null) { length += DirectoryVisibility.Length; } + return length; + } + } + + public UserDataBlock() { } + public UserDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + IMViaEMail = (bytes[i++] != 0) ? (bool)true : (bool)false; + length = bytes[i++]; + DirectoryVisibility = new byte[length]; + Buffer.BlockCopy(bytes, i, DirectoryVisibility, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((IMViaEMail) ? 1 : 0); + bytes[i++] = (byte)DirectoryVisibility.Length; + Buffer.BlockCopy(DirectoryVisibility, 0, bytes, i, DirectoryVisibility.Length); i += DirectoryVisibility.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += UserData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public UserDataBlock UserData; + + public UpdateUserInfoPacket() + { + HasVariableBlocks = false; + Type = PacketType.UpdateUserInfo; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 401; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + UserData = new UserDataBlock(); + } + + public UpdateUserInfoPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + UserData.FromBytes(bytes, ref i); + } + + public UpdateUserInfoPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + UserData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += UserData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + UserData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class InitiateDownloadPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class FileDataBlock : PacketBlock + { + public byte[] SimFilename; + public byte[] ViewerFilename; + + public override int Length + { + get + { + int length = 2; + if (SimFilename != null) { length += SimFilename.Length; } + if (ViewerFilename != null) { length += ViewerFilename.Length; } + return length; + } + } + + public FileDataBlock() { } + public FileDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + SimFilename = new byte[length]; + Buffer.BlockCopy(bytes, i, SimFilename, 0, length); i += length; + length = bytes[i++]; + ViewerFilename = new byte[length]; + Buffer.BlockCopy(bytes, i, ViewerFilename, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)SimFilename.Length; + Buffer.BlockCopy(SimFilename, 0, bytes, i, SimFilename.Length); i += SimFilename.Length; + bytes[i++] = (byte)ViewerFilename.Length; + Buffer.BlockCopy(ViewerFilename, 0, bytes, i, ViewerFilename.Length); i += ViewerFilename.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += FileData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public FileDataBlock FileData; + + public InitiateDownloadPacket() + { + HasVariableBlocks = false; + Type = PacketType.InitiateDownload; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 403; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + FileData = new FileDataBlock(); + } + + public InitiateDownloadPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + FileData.FromBytes(bytes, ref i); + } + + public InitiateDownloadPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + FileData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += FileData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + FileData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MapLayerRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint Flags; + public uint EstateID; + public bool Godlike; + + public override int Length + { + get + { + return 41; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Godlike = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.UIntToBytes(EstateID, bytes, i); i += 4; + bytes[i++] = (byte)((Godlike) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public MapLayerRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.MapLayerRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 405; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public MapLayerRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public MapLayerRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MapLayerReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public uint Flags; + + public override int Length + { + get + { + return 20; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + /// + public sealed class LayerDataBlock : PacketBlock + { + public uint Left; + public uint Right; + public uint Top; + public uint Bottom; + public UUID ImageID; + + public override int Length + { + get + { + return 32; + } + } + + public LayerDataBlock() { } + public LayerDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Left = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Right = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Top = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Bottom = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ImageID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Left, bytes, i); i += 4; + Utils.UIntToBytes(Right, bytes, i); i += 4; + Utils.UIntToBytes(Top, bytes, i); i += 4; + Utils.UIntToBytes(Bottom, bytes, i); i += 4; + ImageID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < LayerData.Length; j++) + length += LayerData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public LayerDataBlock[] LayerData; + + public MapLayerReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.MapLayerReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 406; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + LayerData = null; + } + + public MapLayerReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(LayerData == null || LayerData.Length != -1) { + LayerData = new LayerDataBlock[count]; + for(int j = 0; j < count; j++) + { LayerData[j] = new LayerDataBlock(); } + } + for (int j = 0; j < count; j++) + { LayerData[j].FromBytes(bytes, ref i); } + } + + public MapLayerReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(LayerData == null || LayerData.Length != count) { + LayerData = new LayerDataBlock[count]; + for(int j = 0; j < count; j++) + { LayerData[j] = new LayerDataBlock(); } + } + for (int j = 0; j < count; j++) + { LayerData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < LayerData.Length; j++) { length += LayerData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)LayerData.Length; + for (int j = 0; j < LayerData.Length; j++) { LayerData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int LayerDataStart = 0; + do + { + int variableLength = 0; + int LayerDataCount = 0; + + i = LayerDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < LayerData.Length) { + int blockLength = LayerData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++LayerDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)LayerDataCount; + for (i = LayerDataStart; i < LayerDataStart + LayerDataCount; i++) { LayerData[i].ToBytes(packet, ref length); } + LayerDataStart += LayerDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + LayerDataStart < LayerData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class MapBlockRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint Flags; + public uint EstateID; + public bool Godlike; + + public override int Length + { + get + { + return 41; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Godlike = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.UIntToBytes(EstateID, bytes, i); i += 4; + bytes[i++] = (byte)((Godlike) ? 1 : 0); + } + + } + + /// + public sealed class PositionDataBlock : PacketBlock + { + public ushort MinX; + public ushort MaxX; + public ushort MinY; + public ushort MaxY; + + public override int Length + { + get + { + return 8; + } + } + + public PositionDataBlock() { } + public PositionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + MinX = (ushort)(bytes[i++] + (bytes[i++] << 8)); + MaxX = (ushort)(bytes[i++] + (bytes[i++] << 8)); + MinY = (ushort)(bytes[i++] + (bytes[i++] << 8)); + MaxY = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(MinX % 256); + bytes[i++] = (byte)((MinX >> 8) % 256); + bytes[i++] = (byte)(MaxX % 256); + bytes[i++] = (byte)((MaxX >> 8) % 256); + bytes[i++] = (byte)(MinY % 256); + bytes[i++] = (byte)((MinY >> 8) % 256); + bytes[i++] = (byte)(MaxY % 256); + bytes[i++] = (byte)((MaxY >> 8) % 256); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += PositionData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public PositionDataBlock PositionData; + + public MapBlockRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.MapBlockRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 407; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + PositionData = new PositionDataBlock(); + } + + public MapBlockRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + PositionData.FromBytes(bytes, ref i); + } + + public MapBlockRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + PositionData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += PositionData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + PositionData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MapNameRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint Flags; + public uint EstateID; + public bool Godlike; + + public override int Length + { + get + { + return 41; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Godlike = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.UIntToBytes(EstateID, bytes, i); i += 4; + bytes[i++] = (byte)((Godlike) ? 1 : 0); + } + + } + + /// + public sealed class NameDataBlock : PacketBlock + { + public byte[] Name; + + public override int Length + { + get + { + int length = 1; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public NameDataBlock() { } + public NameDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += NameData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public NameDataBlock NameData; + + public MapNameRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.MapNameRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 408; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + NameData = new NameDataBlock(); + } + + public MapNameRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + NameData.FromBytes(bytes, ref i); + } + + public MapNameRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + NameData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += NameData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + NameData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MapBlockReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public uint Flags; + + public override int Length + { + get + { + return 20; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public ushort X; + public ushort Y; + public byte[] Name; + public byte Access; + public uint RegionFlags; + public byte WaterHeight; + public byte Agents; + public UUID MapImageID; + + public override int Length + { + get + { + int length = 28; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + X = (ushort)(bytes[i++] + (bytes[i++] << 8)); + Y = (ushort)(bytes[i++] + (bytes[i++] << 8)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + Access = (byte)bytes[i++]; + RegionFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + WaterHeight = (byte)bytes[i++]; + Agents = (byte)bytes[i++]; + MapImageID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(X % 256); + bytes[i++] = (byte)((X >> 8) % 256); + bytes[i++] = (byte)(Y % 256); + bytes[i++] = (byte)((Y >> 8) % 256); + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = Access; + Utils.UIntToBytes(RegionFlags, bytes, i); i += 4; + bytes[i++] = WaterHeight; + bytes[i++] = Agents; + MapImageID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class SizeBlock : PacketBlock + { + public ushort SizeX; + public ushort SizeY; + + public override int Length + { + get + { + return 4; + } + } + + public SizeBlock() { } + public SizeBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SizeX = (ushort)(bytes[i++] + (bytes[i++] << 8)); + SizeY = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(SizeX % 256); + bytes[i++] = (byte)((SizeX >> 8) % 256); + bytes[i++] = (byte)(SizeY % 256); + bytes[i++] = (byte)((SizeY >> 8) % 256); + } + + } + + public override int Length + { + get + { + int length = 12; + length += AgentData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + for (int j = 0; j < Size.Length; j++) + length += Size[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock[] Data; + public SizeBlock[] Size; + + public MapBlockReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.MapBlockReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 409; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + Data = null; + Size = null; + } + + public MapBlockReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(Size == null || Size.Length != -1) { + Size = new SizeBlock[count]; + for(int j = 0; j < count; j++) + { Size[j] = new SizeBlock(); } + } + for (int j = 0; j < count; j++) + { Size[j].FromBytes(bytes, ref i); } + } + + public MapBlockReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(Size == null || Size.Length != count) { + Size = new SizeBlock[count]; + for(int j = 0; j < count; j++) + { Size[j] = new SizeBlock(); } + } + for (int j = 0; j < count; j++) + { Size[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + length++; + for (int j = 0; j < Size.Length; j++) { length += Size[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)Size.Length; + for (int j = 0; j < Size.Length; j++) { Size[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int DataStart = 0; + int SizeStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + int SizeCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + i = SizeStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Size.Length) { + int blockLength = Size[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++SizeCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + packet[length++] = (byte)SizeCount; + for (i = SizeStart; i < SizeStart + SizeCount; i++) { Size[i].ToBytes(packet, ref length); } + SizeStart += SizeCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length || + SizeStart < Size.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class MapItemRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public uint Flags; + public uint EstateID; + public bool Godlike; + + public override int Length + { + get + { + return 41; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EstateID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Godlike = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.UIntToBytes(EstateID, bytes, i); i += 4; + bytes[i++] = (byte)((Godlike) ? 1 : 0); + } + + } + + /// + public sealed class RequestDataBlock : PacketBlock + { + public uint ItemType; + public ulong RegionHandle; + + public override int Length + { + get + { + return 12; + } + } + + public RequestDataBlock() { } + public RequestDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ItemType, bytes, i); i += 4; + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += RequestData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public RequestDataBlock RequestData; + + public MapItemRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.MapItemRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 410; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RequestData = new RequestDataBlock(); + } + + public MapItemRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RequestData.FromBytes(bytes, ref i); + } + + public MapItemRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RequestData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RequestData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RequestData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MapItemReplyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public uint Flags; + + public override int Length + { + get + { + return 20; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + /// + public sealed class RequestDataBlock : PacketBlock + { + public uint ItemType; + + public override int Length + { + get + { + return 4; + } + } + + public RequestDataBlock() { } + public RequestDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ItemType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ItemType, bytes, i); i += 4; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public uint X; + public uint Y; + public UUID ID; + public int Extra; + public int Extra2; + public byte[] Name; + + public override int Length + { + get + { + int length = 33; + if (Name != null) { length += Name.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + X = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Y = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ID.FromBytes(bytes, i); i += 16; + Extra = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Extra2 = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(X, bytes, i); i += 4; + Utils.UIntToBytes(Y, bytes, i); i += 4; + ID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(Extra, bytes, i); i += 4; + Utils.IntToBytes(Extra2, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + length += RequestData.Length; + for (int j = 0; j < Data.Length; j++) + length += Data[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RequestDataBlock RequestData; + public DataBlock[] Data; + + public MapItemReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.MapItemReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 411; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RequestData = new RequestDataBlock(); + Data = null; + } + + public MapItemReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RequestData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != -1) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public MapItemReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RequestData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Data == null || Data.Length != count) { + Data = new DataBlock[count]; + for(int j = 0; j < count; j++) + { Data[j] = new DataBlock(); } + } + for (int j = 0; j < count; j++) + { Data[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RequestData.Length; + length++; + for (int j = 0; j < Data.Length; j++) { length += Data[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RequestData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Data.Length; + for (int j = 0; j < Data.Length; j++) { Data[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + fixedLength += RequestData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + RequestData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataStart = 0; + do + { + int variableLength = 0; + int DataCount = 0; + + i = DataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Data.Length) { + int blockLength = Data[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataCount; + for (i = DataStart; i < DataStart + DataCount; i++) { Data[i].ToBytes(packet, ref length); } + DataStart += DataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataStart < Data.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class SendPostcardPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID AssetID; + public Vector3d PosGlobal; + public byte[] To; + public byte[] From; + public byte[] Name; + public byte[] Subject; + public byte[] Msg; + public bool AllowPublish; + public bool MaturePublish; + + public override int Length + { + get + { + int length = 80; + if (To != null) { length += To.Length; } + if (From != null) { length += From.Length; } + if (Name != null) { length += Name.Length; } + if (Subject != null) { length += Subject.Length; } + if (Msg != null) { length += Msg.Length; } + return length; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + AssetID.FromBytes(bytes, i); i += 16; + PosGlobal.FromBytes(bytes, i); i += 24; + length = bytes[i++]; + To = new byte[length]; + Buffer.BlockCopy(bytes, i, To, 0, length); i += length; + length = bytes[i++]; + From = new byte[length]; + Buffer.BlockCopy(bytes, i, From, 0, length); i += length; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Subject = new byte[length]; + Buffer.BlockCopy(bytes, i, Subject, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Msg = new byte[length]; + Buffer.BlockCopy(bytes, i, Msg, 0, length); i += length; + AllowPublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + MaturePublish = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + AssetID.ToBytes(bytes, i); i += 16; + PosGlobal.ToBytes(bytes, i); i += 24; + bytes[i++] = (byte)To.Length; + Buffer.BlockCopy(To, 0, bytes, i, To.Length); i += To.Length; + bytes[i++] = (byte)From.Length; + Buffer.BlockCopy(From, 0, bytes, i, From.Length); i += From.Length; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Subject.Length; + Buffer.BlockCopy(Subject, 0, bytes, i, Subject.Length); i += Subject.Length; + bytes[i++] = (byte)(Msg.Length % 256); + bytes[i++] = (byte)((Msg.Length >> 8) % 256); + Buffer.BlockCopy(Msg, 0, bytes, i, Msg.Length); i += Msg.Length; + bytes[i++] = (byte)((AllowPublish) ? 1 : 0); + bytes[i++] = (byte)((MaturePublish) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public SendPostcardPacket() + { + HasVariableBlocks = false; + Type = PacketType.SendPostcard; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 412; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public SendPostcardPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public SendPostcardPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelMediaCommandMessagePacket : Packet + { + /// + public sealed class CommandBlockBlock : PacketBlock + { + public uint Flags; + public uint Command; + public float Time; + + public override int Length + { + get + { + return 12; + } + } + + public CommandBlockBlock() { } + public CommandBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Command = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Time = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Flags, bytes, i); i += 4; + Utils.UIntToBytes(Command, bytes, i); i += 4; + Utils.FloatToBytes(Time, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += CommandBlock.Length; + return length; + } + } + public CommandBlockBlock CommandBlock; + + public ParcelMediaCommandMessagePacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelMediaCommandMessage; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 419; + Header.Reliable = true; + CommandBlock = new CommandBlockBlock(); + } + + public ParcelMediaCommandMessagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + CommandBlock.FromBytes(bytes, ref i); + } + + public ParcelMediaCommandMessagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + CommandBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += CommandBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + CommandBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelMediaUpdatePacket : Packet + { + /// + public sealed class DataBlockBlock : PacketBlock + { + public byte[] MediaURL; + public UUID MediaID; + public byte MediaAutoScale; + + public override int Length + { + get + { + int length = 18; + if (MediaURL != null) { length += MediaURL.Length; } + return length; + } + } + + public DataBlockBlock() { } + public DataBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + MediaURL = new byte[length]; + Buffer.BlockCopy(bytes, i, MediaURL, 0, length); i += length; + MediaID.FromBytes(bytes, i); i += 16; + MediaAutoScale = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)MediaURL.Length; + Buffer.BlockCopy(MediaURL, 0, bytes, i, MediaURL.Length); i += MediaURL.Length; + MediaID.ToBytes(bytes, i); i += 16; + bytes[i++] = MediaAutoScale; + } + + } + + /// + public sealed class DataBlockExtendedBlock : PacketBlock + { + public byte[] MediaType; + public byte[] MediaDesc; + public int MediaWidth; + public int MediaHeight; + public byte MediaLoop; + + public override int Length + { + get + { + int length = 11; + if (MediaType != null) { length += MediaType.Length; } + if (MediaDesc != null) { length += MediaDesc.Length; } + return length; + } + } + + public DataBlockExtendedBlock() { } + public DataBlockExtendedBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + MediaType = new byte[length]; + Buffer.BlockCopy(bytes, i, MediaType, 0, length); i += length; + length = bytes[i++]; + MediaDesc = new byte[length]; + Buffer.BlockCopy(bytes, i, MediaDesc, 0, length); i += length; + MediaWidth = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + MediaHeight = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + MediaLoop = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)MediaType.Length; + Buffer.BlockCopy(MediaType, 0, bytes, i, MediaType.Length); i += MediaType.Length; + bytes[i++] = (byte)MediaDesc.Length; + Buffer.BlockCopy(MediaDesc, 0, bytes, i, MediaDesc.Length); i += MediaDesc.Length; + Utils.IntToBytes(MediaWidth, bytes, i); i += 4; + Utils.IntToBytes(MediaHeight, bytes, i); i += 4; + bytes[i++] = MediaLoop; + } + + } + + public override int Length + { + get + { + int length = 10; + length += DataBlock.Length; + length += DataBlockExtended.Length; + return length; + } + } + public DataBlockBlock DataBlock; + public DataBlockExtendedBlock DataBlockExtended; + + public ParcelMediaUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelMediaUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 420; + Header.Reliable = true; + DataBlock = new DataBlockBlock(); + DataBlockExtended = new DataBlockExtendedBlock(); + } + + public ParcelMediaUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + DataBlock.FromBytes(bytes, ref i); + DataBlockExtended.FromBytes(bytes, ref i); + } + + public ParcelMediaUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + DataBlock.FromBytes(bytes, ref i); + DataBlockExtended.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += DataBlock.Length; + length += DataBlockExtended.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + DataBlock.ToBytes(bytes, ref i); + DataBlockExtended.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LandStatRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RequestDataBlock : PacketBlock + { + public uint ReportType; + public uint RequestFlags; + public byte[] Filter; + public int ParcelLocalID; + + public override int Length + { + get + { + int length = 13; + if (Filter != null) { length += Filter.Length; } + return length; + } + } + + public RequestDataBlock() { } + public RequestDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ReportType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RequestFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Filter = new byte[length]; + Buffer.BlockCopy(bytes, i, Filter, 0, length); i += length; + ParcelLocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ReportType, bytes, i); i += 4; + Utils.UIntToBytes(RequestFlags, bytes, i); i += 4; + bytes[i++] = (byte)Filter.Length; + Buffer.BlockCopy(Filter, 0, bytes, i, Filter.Length); i += Filter.Length; + Utils.IntToBytes(ParcelLocalID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += RequestData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public RequestDataBlock RequestData; + + public LandStatRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.LandStatRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 421; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RequestData = new RequestDataBlock(); + } + + public LandStatRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RequestData.FromBytes(bytes, ref i); + } + + public LandStatRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RequestData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += RequestData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RequestData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LandStatReplyPacket : Packet + { + /// + public sealed class RequestDataBlock : PacketBlock + { + public uint ReportType; + public uint RequestFlags; + public uint TotalObjectCount; + + public override int Length + { + get + { + return 12; + } + } + + public RequestDataBlock() { } + public RequestDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ReportType = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RequestFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TotalObjectCount = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ReportType, bytes, i); i += 4; + Utils.UIntToBytes(RequestFlags, bytes, i); i += 4; + Utils.UIntToBytes(TotalObjectCount, bytes, i); i += 4; + } + + } + + /// + public sealed class ReportDataBlock : PacketBlock + { + public uint TaskLocalID; + public UUID TaskID; + public float LocationX; + public float LocationY; + public float LocationZ; + public float Score; + public byte[] TaskName; + public byte[] OwnerName; + + public override int Length + { + get + { + int length = 38; + if (TaskName != null) { length += TaskName.Length; } + if (OwnerName != null) { length += OwnerName.Length; } + return length; + } + } + + public ReportDataBlock() { } + public ReportDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TaskLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TaskID.FromBytes(bytes, i); i += 16; + LocationX = Utils.BytesToFloat(bytes, i); i += 4; + LocationY = Utils.BytesToFloat(bytes, i); i += 4; + LocationZ = Utils.BytesToFloat(bytes, i); i += 4; + Score = Utils.BytesToFloat(bytes, i); i += 4; + length = bytes[i++]; + TaskName = new byte[length]; + Buffer.BlockCopy(bytes, i, TaskName, 0, length); i += length; + length = bytes[i++]; + OwnerName = new byte[length]; + Buffer.BlockCopy(bytes, i, OwnerName, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(TaskLocalID, bytes, i); i += 4; + TaskID.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(LocationX, bytes, i); i += 4; + Utils.FloatToBytes(LocationY, bytes, i); i += 4; + Utils.FloatToBytes(LocationZ, bytes, i); i += 4; + Utils.FloatToBytes(Score, bytes, i); i += 4; + bytes[i++] = (byte)TaskName.Length; + Buffer.BlockCopy(TaskName, 0, bytes, i, TaskName.Length); i += TaskName.Length; + bytes[i++] = (byte)OwnerName.Length; + Buffer.BlockCopy(OwnerName, 0, bytes, i, OwnerName.Length); i += OwnerName.Length; + } + + } + + public override int Length + { + get + { + int length = 11; + length += RequestData.Length; + for (int j = 0; j < ReportData.Length; j++) + length += ReportData[j].Length; + return length; + } + } + public RequestDataBlock RequestData; + public ReportDataBlock[] ReportData; + + public LandStatReplyPacket() + { + HasVariableBlocks = true; + Type = PacketType.LandStatReply; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 422; + Header.Reliable = true; + RequestData = new RequestDataBlock(); + ReportData = null; + } + + public LandStatReplyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RequestData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ReportData == null || ReportData.Length != -1) { + ReportData = new ReportDataBlock[count]; + for(int j = 0; j < count; j++) + { ReportData[j] = new ReportDataBlock(); } + } + for (int j = 0; j < count; j++) + { ReportData[j].FromBytes(bytes, ref i); } + } + + public LandStatReplyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RequestData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ReportData == null || ReportData.Length != count) { + ReportData = new ReportDataBlock[count]; + for(int j = 0; j < count; j++) + { ReportData[j] = new ReportDataBlock(); } + } + for (int j = 0; j < count; j++) + { ReportData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += RequestData.Length; + length++; + for (int j = 0; j < ReportData.Length; j++) { length += ReportData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RequestData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ReportData.Length; + for (int j = 0; j < ReportData.Length; j++) { ReportData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += RequestData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + RequestData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ReportDataStart = 0; + do + { + int variableLength = 0; + int ReportDataCount = 0; + + i = ReportDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ReportData.Length) { + int blockLength = ReportData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ReportDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ReportDataCount; + for (i = ReportDataStart; i < ReportDataStart + ReportDataCount; i++) { ReportData[i].ToBytes(packet, ref length); } + ReportDataStart += ReportDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ReportDataStart < ReportData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ErrorPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class DataBlock : PacketBlock + { + public int Code; + public byte[] Token; + public UUID ID; + public byte[] System; + public byte[] Message; + public byte[] Data; + + public override int Length + { + get + { + int length = 26; + if (Token != null) { length += Token.Length; } + if (System != null) { length += System.Length; } + if (Message != null) { length += Message.Length; } + if (Data != null) { length += Data.Length; } + return length; + } + } + + public DataBlock() { } + public DataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + Code = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Token = new byte[length]; + Buffer.BlockCopy(bytes, i, Token, 0, length); i += length; + ID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + System = new byte[length]; + Buffer.BlockCopy(bytes, i, System, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Message = new byte[length]; + Buffer.BlockCopy(bytes, i, Message, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(Code, bytes, i); i += 4; + bytes[i++] = (byte)Token.Length; + Buffer.BlockCopy(Token, 0, bytes, i, Token.Length); i += Token.Length; + ID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)System.Length; + Buffer.BlockCopy(System, 0, bytes, i, System.Length); i += System.Length; + bytes[i++] = (byte)(Message.Length % 256); + bytes[i++] = (byte)((Message.Length >> 8) % 256); + Buffer.BlockCopy(Message, 0, bytes, i, Message.Length); i += Message.Length; + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + return length; + } + } + public AgentDataBlock AgentData; + public DataBlock Data; + + public ErrorPacket() + { + HasVariableBlocks = false; + Type = PacketType.Error; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 423; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Data = new DataBlock(); + } + + public ErrorPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public ErrorPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + Data.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += Data.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + Data.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectIncludeInSearchPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public bool IncludeInSearch; + + public override int Length + { + get + { + return 5; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + IncludeInSearch = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = (byte)((IncludeInSearch) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 11; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectIncludeInSearchPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectIncludeInSearch; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 424; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectIncludeInSearchPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectIncludeInSearchPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RezRestoreToWorldPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryDataBlock : PacketBlock + { + public UUID ItemID; + public UUID FolderID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public bool GroupOwned; + public UUID TransactionID; + public sbyte Type; + public sbyte InvType; + public uint Flags; + public byte SaleType; + public int SalePrice; + public byte[] Name; + public byte[] Description; + public int CreationDate; + public uint CRC; + + public override int Length + { + get + { + int length = 138; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryDataBlock() { } + public InventoryDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + TransactionID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + CreationDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + bytes[i++] = (byte)((GroupOwned) ? 1 : 0); + TransactionID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + Utils.UIntToBytes(Flags, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + Utils.IntToBytes(CreationDate, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryDataBlock InventoryData; + + public RezRestoreToWorldPacket() + { + HasVariableBlocks = false; + Type = PacketType.RezRestoreToWorld; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 425; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + InventoryData = new InventoryDataBlock(); + } + + public RezRestoreToWorldPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public RezRestoreToWorldPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LinkInventoryItemPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class InventoryBlockBlock : PacketBlock + { + public uint CallbackID; + public UUID FolderID; + public UUID TransactionID; + public UUID OldItemID; + public sbyte Type; + public sbyte InvType; + public byte[] Name; + public byte[] Description; + + public override int Length + { + get + { + int length = 56; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public InventoryBlockBlock() { } + public InventoryBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + CallbackID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + FolderID.FromBytes(bytes, i); i += 16; + TransactionID.FromBytes(bytes, i); i += 16; + OldItemID.FromBytes(bytes, i); i += 16; + Type = (sbyte)bytes[i++]; + InvType = (sbyte)bytes[i++]; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(CallbackID, bytes, i); i += 4; + FolderID.ToBytes(bytes, i); i += 16; + TransactionID.ToBytes(bytes, i); i += 16; + OldItemID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Type; + bytes[i++] = (byte)InvType; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += AgentData.Length; + length += InventoryBlock.Length; + return length; + } + } + public AgentDataBlock AgentData; + public InventoryBlockBlock InventoryBlock; + + public LinkInventoryItemPacket() + { + HasVariableBlocks = false; + Type = PacketType.LinkInventoryItem; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 426; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + InventoryBlock = new InventoryBlockBlock(); + } + + public LinkInventoryItemPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public LinkInventoryItemPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + InventoryBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += AgentData.Length; + length += InventoryBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + InventoryBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PacketAckPacket : Packet + { + /// + public sealed class PacketsBlock : PacketBlock + { + public uint ID; + + public override int Length + { + get + { + return 4; + } + } + + public PacketsBlock() { } + public PacketsBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 11; + for (int j = 0; j < Packets.Length; j++) + length += Packets[j].Length; + return length; + } + } + public PacketsBlock[] Packets; + + public PacketAckPacket() + { + HasVariableBlocks = true; + Type = PacketType.PacketAck; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 65531; + Header.Reliable = true; + Packets = null; + } + + public PacketAckPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(Packets == null || Packets.Length != -1) { + Packets = new PacketsBlock[count]; + for(int j = 0; j < count; j++) + { Packets[j] = new PacketsBlock(); } + } + for (int j = 0; j < count; j++) + { Packets[j].FromBytes(bytes, ref i); } + } + + public PacketAckPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(Packets == null || Packets.Length != count) { + Packets = new PacketsBlock[count]; + for(int j = 0; j < count; j++) + { Packets[j] = new PacketsBlock(); } + } + for (int j = 0; j < count; j++) + { Packets[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 10; + length++; + for (int j = 0; j < Packets.Length; j++) { length += Packets[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)Packets.Length; + for (int j = 0; j < Packets.Length; j++) { Packets[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 10; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int PacketsStart = 0; + do + { + int variableLength = 0; + int PacketsCount = 0; + + i = PacketsStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Packets.Length) { + int blockLength = Packets[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++PacketsCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)PacketsCount; + for (i = PacketsStart; i < PacketsStart + PacketsCount; i++) { Packets[i].ToBytes(packet, ref length); } + PacketsStart += PacketsCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + PacketsStart < Packets.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class OpenCircuitPacket : Packet + { + /// + public sealed class CircuitInfoBlock : PacketBlock + { + public uint IP; + public ushort Port; + + public override int Length + { + get + { + return 6; + } + } + + public CircuitInfoBlock() { } + public CircuitInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + IP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Port = (ushort)((bytes[i++] << 8) + bytes[i++]); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(IP, bytes, i); i += 4; + bytes[i++] = (byte)((Port >> 8) % 256); + bytes[i++] = (byte)(Port % 256); + } + + } + + public override int Length + { + get + { + int length = 10; + length += CircuitInfo.Length; + return length; + } + } + public CircuitInfoBlock CircuitInfo; + + public OpenCircuitPacket() + { + HasVariableBlocks = false; + Type = PacketType.OpenCircuit; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 65532; + Header.Reliable = true; + CircuitInfo = new CircuitInfoBlock(); + } + + public OpenCircuitPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + CircuitInfo.FromBytes(bytes, ref i); + } + + public OpenCircuitPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + CircuitInfo.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 10; + length += CircuitInfo.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + CircuitInfo.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CloseCircuitPacket : Packet + { + public override int Length + { + get + { + int length = 10; + return length; + } + } + + public CloseCircuitPacket() + { + HasVariableBlocks = false; + Type = PacketType.CloseCircuit; + Header = new Header(); + Header.Frequency = PacketFrequency.Low; + Header.ID = 65533; + Header.Reliable = true; + } + + public CloseCircuitPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + } + + public CloseCircuitPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + } + + public override byte[] ToBytes() + { + int length = 10; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectAddPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public UUID GroupID; + + public override int Length + { + get + { + return 48; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public byte PCode; + public byte Material; + public uint AddFlags; + public byte PathCurve; + public byte ProfileCurve; + public ushort PathBegin; + public ushort PathEnd; + public byte PathScaleX; + public byte PathScaleY; + public byte PathShearX; + public byte PathShearY; + public sbyte PathTwist; + public sbyte PathTwistBegin; + public sbyte PathRadiusOffset; + public sbyte PathTaperX; + public sbyte PathTaperY; + public byte PathRevolutions; + public sbyte PathSkew; + public ushort ProfileBegin; + public ushort ProfileEnd; + public ushort ProfileHollow; + public byte BypassRaycast; + public Vector3 RayStart; + public Vector3 RayEnd; + public UUID RayTargetID; + public byte RayEndIsIntersection; + public Vector3 Scale; + public Quaternion Rotation; + public byte State; + + public override int Length + { + get + { + return 96; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PCode = (byte)bytes[i++]; + Material = (byte)bytes[i++]; + AddFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PathCurve = (byte)bytes[i++]; + ProfileCurve = (byte)bytes[i++]; + PathBegin = (ushort)(bytes[i++] + (bytes[i++] << 8)); + PathEnd = (ushort)(bytes[i++] + (bytes[i++] << 8)); + PathScaleX = (byte)bytes[i++]; + PathScaleY = (byte)bytes[i++]; + PathShearX = (byte)bytes[i++]; + PathShearY = (byte)bytes[i++]; + PathTwist = (sbyte)bytes[i++]; + PathTwistBegin = (sbyte)bytes[i++]; + PathRadiusOffset = (sbyte)bytes[i++]; + PathTaperX = (sbyte)bytes[i++]; + PathTaperY = (sbyte)bytes[i++]; + PathRevolutions = (byte)bytes[i++]; + PathSkew = (sbyte)bytes[i++]; + ProfileBegin = (ushort)(bytes[i++] + (bytes[i++] << 8)); + ProfileEnd = (ushort)(bytes[i++] + (bytes[i++] << 8)); + ProfileHollow = (ushort)(bytes[i++] + (bytes[i++] << 8)); + BypassRaycast = (byte)bytes[i++]; + RayStart.FromBytes(bytes, i); i += 12; + RayEnd.FromBytes(bytes, i); i += 12; + RayTargetID.FromBytes(bytes, i); i += 16; + RayEndIsIntersection = (byte)bytes[i++]; + Scale.FromBytes(bytes, i); i += 12; + Rotation.FromBytes(bytes, i, true); i += 12; + State = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = PCode; + bytes[i++] = Material; + Utils.UIntToBytes(AddFlags, bytes, i); i += 4; + bytes[i++] = PathCurve; + bytes[i++] = ProfileCurve; + bytes[i++] = (byte)(PathBegin % 256); + bytes[i++] = (byte)((PathBegin >> 8) % 256); + bytes[i++] = (byte)(PathEnd % 256); + bytes[i++] = (byte)((PathEnd >> 8) % 256); + bytes[i++] = PathScaleX; + bytes[i++] = PathScaleY; + bytes[i++] = PathShearX; + bytes[i++] = PathShearY; + bytes[i++] = (byte)PathTwist; + bytes[i++] = (byte)PathTwistBegin; + bytes[i++] = (byte)PathRadiusOffset; + bytes[i++] = (byte)PathTaperX; + bytes[i++] = (byte)PathTaperY; + bytes[i++] = PathRevolutions; + bytes[i++] = (byte)PathSkew; + bytes[i++] = (byte)(ProfileBegin % 256); + bytes[i++] = (byte)((ProfileBegin >> 8) % 256); + bytes[i++] = (byte)(ProfileEnd % 256); + bytes[i++] = (byte)((ProfileEnd >> 8) % 256); + bytes[i++] = (byte)(ProfileHollow % 256); + bytes[i++] = (byte)((ProfileHollow >> 8) % 256); + bytes[i++] = BypassRaycast; + RayStart.ToBytes(bytes, i); i += 12; + RayEnd.ToBytes(bytes, i); i += 12; + RayTargetID.ToBytes(bytes, i); i += 16; + bytes[i++] = RayEndIsIntersection; + Scale.ToBytes(bytes, i); i += 12; + Rotation.ToBytes(bytes, i); i += 12; + bytes[i++] = State; + } + + } + + public override int Length + { + get + { + int length = 8; + length += AgentData.Length; + length += ObjectData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + + public ObjectAddPacket() + { + HasVariableBlocks = false; + Type = PacketType.ObjectAdd; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 1; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + } + + public ObjectAddPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public ObjectAddPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class MultipleObjectUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public byte Type; + public byte[] Data; + + public override int Length + { + get + { + int length = 6; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Type = (byte)bytes[i++]; + length = bytes[i++]; + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + bytes[i++] = Type; + bytes[i++] = (byte)Data.Length; + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 9; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public MultipleObjectUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.MultipleObjectUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 2; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public MultipleObjectUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public MultipleObjectUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 8; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RequestMultipleObjectsPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public byte CacheMissType; + public uint ID; + + public override int Length + { + get + { + return 5; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + CacheMissType = (byte)bytes[i++]; + ID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = CacheMissType; + Utils.UIntToBytes(ID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 9; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public RequestMultipleObjectsPacket() + { + HasVariableBlocks = true; + Type = PacketType.RequestMultipleObjects; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 3; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public RequestMultipleObjectsPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public RequestMultipleObjectsPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 8; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectPositionPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ObjectLocalID; + public Vector3 Position; + + public override int Length + { + get + { + return 16; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectLocalID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Position.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ObjectLocalID, bytes, i); i += 4; + Position.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 9; + length += AgentData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock[] ObjectData; + + public ObjectPositionPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectPosition; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 4; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = null; + } + + public ObjectPositionPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectPositionPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 8; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class RequestObjectPropertiesFamilyPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint RequestFlags; + public UUID ObjectID; + + public override int Length + { + get + { + return 20; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RequestFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(RequestFlags, bytes, i); i += 4; + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 8; + length += AgentData.Length; + length += ObjectData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ObjectDataBlock ObjectData; + + public RequestObjectPropertiesFamilyPacket() + { + HasVariableBlocks = false; + Type = PacketType.RequestObjectPropertiesFamily; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 5; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ObjectData = new ObjectDataBlock(); + } + + public RequestObjectPropertiesFamilyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public RequestObjectPropertiesFamilyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CoarseLocationUpdatePacket : Packet + { + /// + public sealed class LocationBlock : PacketBlock + { + public byte X; + public byte Y; + public byte Z; + + public override int Length + { + get + { + return 3; + } + } + + public LocationBlock() { } + public LocationBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + X = (byte)bytes[i++]; + Y = (byte)bytes[i++]; + Z = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = X; + bytes[i++] = Y; + bytes[i++] = Z; + } + + } + + /// + public sealed class IndexBlock : PacketBlock + { + public short You; + public short Prey; + + public override int Length + { + get + { + return 4; + } + } + + public IndexBlock() { } + public IndexBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + You = (short)(bytes[i++] + (bytes[i++] << 8)); + Prey = (short)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(You % 256); + bytes[i++] = (byte)((You >> 8) % 256); + bytes[i++] = (byte)(Prey % 256); + bytes[i++] = (byte)((Prey >> 8) % 256); + } + + } + + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + + public override int Length + { + get + { + return 16; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 10; + for (int j = 0; j < Location.Length; j++) + length += Location[j].Length; + length += Index.Length; + for (int j = 0; j < AgentData.Length; j++) + length += AgentData[j].Length; + return length; + } + } + public LocationBlock[] Location; + public IndexBlock Index; + public AgentDataBlock[] AgentData; + + public CoarseLocationUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.CoarseLocationUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 6; + Header.Reliable = true; + Location = null; + Index = new IndexBlock(); + AgentData = null; + } + + public CoarseLocationUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(Location == null || Location.Length != -1) { + Location = new LocationBlock[count]; + for(int j = 0; j < count; j++) + { Location[j] = new LocationBlock(); } + } + for (int j = 0; j < count; j++) + { Location[j].FromBytes(bytes, ref i); } + Index.FromBytes(bytes, ref i); + count = (int)bytes[i++]; + if(AgentData == null || AgentData.Length != -1) { + AgentData = new AgentDataBlock[count]; + for(int j = 0; j < count; j++) + { AgentData[j] = new AgentDataBlock(); } + } + for (int j = 0; j < count; j++) + { AgentData[j].FromBytes(bytes, ref i); } + } + + public CoarseLocationUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(Location == null || Location.Length != count) { + Location = new LocationBlock[count]; + for(int j = 0; j < count; j++) + { Location[j] = new LocationBlock(); } + } + for (int j = 0; j < count; j++) + { Location[j].FromBytes(bytes, ref i); } + Index.FromBytes(bytes, ref i); + count = (int)bytes[i++]; + if(AgentData == null || AgentData.Length != count) { + AgentData = new AgentDataBlock[count]; + for(int j = 0; j < count; j++) + { AgentData[j] = new AgentDataBlock(); } + } + for (int j = 0; j < count; j++) + { AgentData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 8; + length += Index.Length; + length++; + for (int j = 0; j < Location.Length; j++) { length += Location[j].Length; } + length++; + for (int j = 0; j < AgentData.Length; j++) { length += AgentData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)Location.Length; + for (int j = 0; j < Location.Length; j++) { Location[j].ToBytes(bytes, ref i); } + Index.ToBytes(bytes, ref i); + bytes[i++] = (byte)AgentData.Length; + for (int j = 0; j < AgentData.Length; j++) { AgentData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CrossedRegionPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RegionDataBlock : PacketBlock + { + public uint SimIP; + public ushort SimPort; + public ulong RegionHandle; + public byte[] SeedCapability; + + public override int Length + { + get + { + int length = 16; + if (SeedCapability != null) { length += SeedCapability.Length; } + return length; + } + } + + public RegionDataBlock() { } + public RegionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + SimIP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SimPort = (ushort)((bytes[i++] << 8) + bytes[i++]); + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + length = (bytes[i++] + (bytes[i++] << 8)); + SeedCapability = new byte[length]; + Buffer.BlockCopy(bytes, i, SeedCapability, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(SimIP, bytes, i); i += 4; + bytes[i++] = (byte)((SimPort >> 8) % 256); + bytes[i++] = (byte)(SimPort % 256); + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + bytes[i++] = (byte)(SeedCapability.Length % 256); + bytes[i++] = (byte)((SeedCapability.Length >> 8) % 256); + Buffer.BlockCopy(SeedCapability, 0, bytes, i, SeedCapability.Length); i += SeedCapability.Length; + } + + } + + /// + public sealed class InfoBlock : PacketBlock + { + public Vector3 Position; + public Vector3 LookAt; + + public override int Length + { + get + { + return 24; + } + } + + public InfoBlock() { } + public InfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Position.FromBytes(bytes, i); i += 12; + LookAt.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Position.ToBytes(bytes, i); i += 12; + LookAt.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 8; + length += AgentData.Length; + length += RegionData.Length; + length += Info.Length; + return length; + } + } + public AgentDataBlock AgentData; + public RegionDataBlock RegionData; + public InfoBlock Info; + + public CrossedRegionPacket() + { + HasVariableBlocks = false; + Type = PacketType.CrossedRegion; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 7; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RegionData = new RegionDataBlock(); + Info = new InfoBlock(); + } + + public CrossedRegionPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + RegionData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public CrossedRegionPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + RegionData.FromBytes(bytes, ref i); + Info.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length += RegionData.Length; + length += Info.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + RegionData.ToBytes(bytes, ref i); + Info.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ConfirmEnableSimulatorPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 8; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public ConfirmEnableSimulatorPacket() + { + HasVariableBlocks = false; + Type = PacketType.ConfirmEnableSimulator; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 8; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public ConfirmEnableSimulatorPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public ConfirmEnableSimulatorPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectPropertiesPacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public UUID ObjectID; + public UUID CreatorID; + public UUID OwnerID; + public UUID GroupID; + public ulong CreationDate; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public int OwnershipCost; + public byte SaleType; + public int SalePrice; + public byte AggregatePerms; + public byte AggregatePermTextures; + public byte AggregatePermTexturesOwner; + public uint Category; + public short InventorySerial; + public UUID ItemID; + public UUID FolderID; + public UUID FromTaskID; + public UUID LastOwnerID; + public byte[] Name; + public byte[] Description; + public byte[] TouchName; + public byte[] SitName; + public byte[] TextureID; + + public override int Length + { + get + { + int length = 179; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + if (TouchName != null) { length += TouchName.Length; } + if (SitName != null) { length += SitName.Length; } + if (TextureID != null) { length += TextureID.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ObjectID.FromBytes(bytes, i); i += 16; + CreatorID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + CreationDate = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnershipCost = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AggregatePerms = (byte)bytes[i++]; + AggregatePermTextures = (byte)bytes[i++]; + AggregatePermTexturesOwner = (byte)bytes[i++]; + Category = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + InventorySerial = (short)(bytes[i++] + (bytes[i++] << 8)); + ItemID.FromBytes(bytes, i); i += 16; + FolderID.FromBytes(bytes, i); i += 16; + FromTaskID.FromBytes(bytes, i); i += 16; + LastOwnerID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + length = bytes[i++]; + TouchName = new byte[length]; + Buffer.BlockCopy(bytes, i, TouchName, 0, length); i += length; + length = bytes[i++]; + SitName = new byte[length]; + Buffer.BlockCopy(bytes, i, SitName, 0, length); i += length; + length = bytes[i++]; + TextureID = new byte[length]; + Buffer.BlockCopy(bytes, i, TextureID, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + CreatorID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UInt64ToBytes(CreationDate, bytes, i); i += 8; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + Utils.IntToBytes(OwnershipCost, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = AggregatePerms; + bytes[i++] = AggregatePermTextures; + bytes[i++] = AggregatePermTexturesOwner; + Utils.UIntToBytes(Category, bytes, i); i += 4; + bytes[i++] = (byte)(InventorySerial % 256); + bytes[i++] = (byte)((InventorySerial >> 8) % 256); + ItemID.ToBytes(bytes, i); i += 16; + FolderID.ToBytes(bytes, i); i += 16; + FromTaskID.ToBytes(bytes, i); i += 16; + LastOwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + bytes[i++] = (byte)TouchName.Length; + Buffer.BlockCopy(TouchName, 0, bytes, i, TouchName.Length); i += TouchName.Length; + bytes[i++] = (byte)SitName.Length; + Buffer.BlockCopy(SitName, 0, bytes, i, SitName.Length); i += SitName.Length; + bytes[i++] = (byte)TextureID.Length; + Buffer.BlockCopy(TextureID, 0, bytes, i, TextureID.Length); i += TextureID.Length; + } + + } + + public override int Length + { + get + { + int length = 9; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public ObjectDataBlock[] ObjectData; + + public ObjectPropertiesPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectProperties; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 9; + Header.Reliable = true; + Header.Zerocoded = true; + ObjectData = null; + } + + public ObjectPropertiesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectPropertiesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 8; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 8; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectPropertiesFamilyPacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint RequestFlags; + public UUID ObjectID; + public UUID OwnerID; + public UUID GroupID; + public uint BaseMask; + public uint OwnerMask; + public uint GroupMask; + public uint EveryoneMask; + public uint NextOwnerMask; + public int OwnershipCost; + public byte SaleType; + public int SalePrice; + public uint Category; + public UUID LastOwnerID; + public byte[] Name; + public byte[] Description; + + public override int Length + { + get + { + int length = 103; + if (Name != null) { length += Name.Length; } + if (Description != null) { length += Description.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RequestFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ObjectID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + GroupID.FromBytes(bytes, i); i += 16; + BaseMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EveryoneMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + NextOwnerMask = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnershipCost = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SaleType = (byte)bytes[i++]; + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Category = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LastOwnerID.FromBytes(bytes, i); i += 16; + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Description = new byte[length]; + Buffer.BlockCopy(bytes, i, Description, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(RequestFlags, bytes, i); i += 4; + ObjectID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + GroupID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(BaseMask, bytes, i); i += 4; + Utils.UIntToBytes(OwnerMask, bytes, i); i += 4; + Utils.UIntToBytes(GroupMask, bytes, i); i += 4; + Utils.UIntToBytes(EveryoneMask, bytes, i); i += 4; + Utils.UIntToBytes(NextOwnerMask, bytes, i); i += 4; + Utils.IntToBytes(OwnershipCost, bytes, i); i += 4; + bytes[i++] = SaleType; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + Utils.UIntToBytes(Category, bytes, i); i += 4; + LastOwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Description.Length; + Buffer.BlockCopy(Description, 0, bytes, i, Description.Length); i += Description.Length; + } + + } + + public override int Length + { + get + { + int length = 8; + length += ObjectData.Length; + return length; + } + } + public ObjectDataBlock ObjectData; + + public ObjectPropertiesFamilyPacket() + { + HasVariableBlocks = false; + Type = PacketType.ObjectPropertiesFamily; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 10; + Header.Reliable = true; + Header.Zerocoded = true; + ObjectData = new ObjectDataBlock(); + } + + public ObjectPropertiesFamilyPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ObjectData.FromBytes(bytes, ref i); + } + + public ObjectPropertiesFamilyPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ObjectData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += ObjectData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ObjectData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelPropertiesRequestPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int SequenceID; + public float West; + public float South; + public float East; + public float North; + public bool SnapSelection; + + public override int Length + { + get + { + return 21; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + West = Utils.BytesToFloat(bytes, i); i += 4; + South = Utils.BytesToFloat(bytes, i); i += 4; + East = Utils.BytesToFloat(bytes, i); i += 4; + North = Utils.BytesToFloat(bytes, i); i += 4; + SnapSelection = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(SequenceID, bytes, i); i += 4; + Utils.FloatToBytes(West, bytes, i); i += 4; + Utils.FloatToBytes(South, bytes, i); i += 4; + Utils.FloatToBytes(East, bytes, i); i += 4; + Utils.FloatToBytes(North, bytes, i); i += 4; + bytes[i++] = (byte)((SnapSelection) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 8; + length += AgentData.Length; + length += ParcelData.Length; + return length; + } + } + public AgentDataBlock AgentData; + public ParcelDataBlock ParcelData; + + public ParcelPropertiesRequestPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelPropertiesRequest; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 11; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + ParcelData = new ParcelDataBlock(); + } + + public ParcelPropertiesRequestPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public ParcelPropertiesRequestPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + ParcelData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length += ParcelData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AttachedSoundPacket : Packet + { + /// + public sealed class DataBlockBlock : PacketBlock + { + public UUID SoundID; + public UUID ObjectID; + public UUID OwnerID; + public float Gain; + public byte Flags; + + public override int Length + { + get + { + return 53; + } + } + + public DataBlockBlock() { } + public DataBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SoundID.FromBytes(bytes, i); i += 16; + ObjectID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + Gain = Utils.BytesToFloat(bytes, i); i += 4; + Flags = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + SoundID.ToBytes(bytes, i); i += 16; + ObjectID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(Gain, bytes, i); i += 4; + bytes[i++] = Flags; + } + + } + + public override int Length + { + get + { + int length = 8; + length += DataBlock.Length; + return length; + } + } + public DataBlockBlock DataBlock; + + public AttachedSoundPacket() + { + HasVariableBlocks = false; + Type = PacketType.AttachedSound; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 13; + Header.Reliable = true; + DataBlock = new DataBlockBlock(); + } + + public AttachedSoundPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + DataBlock.FromBytes(bytes, ref i); + } + + public AttachedSoundPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + DataBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += DataBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + DataBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AttachedSoundGainChangePacket : Packet + { + /// + public sealed class DataBlockBlock : PacketBlock + { + public UUID ObjectID; + public float Gain; + + public override int Length + { + get + { + return 20; + } + } + + public DataBlockBlock() { } + public DataBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + Gain = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(Gain, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 8; + length += DataBlock.Length; + return length; + } + } + public DataBlockBlock DataBlock; + + public AttachedSoundGainChangePacket() + { + HasVariableBlocks = false; + Type = PacketType.AttachedSoundGainChange; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 14; + Header.Reliable = true; + DataBlock = new DataBlockBlock(); + } + + public AttachedSoundGainChangePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + DataBlock.FromBytes(bytes, ref i); + } + + public AttachedSoundGainChangePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + DataBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 8; + length += DataBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + DataBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class PreloadSoundPacket : Packet + { + /// + public sealed class DataBlockBlock : PacketBlock + { + public UUID ObjectID; + public UUID OwnerID; + public UUID SoundID; + + public override int Length + { + get + { + return 48; + } + } + + public DataBlockBlock() { } + public DataBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + SoundID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + SoundID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 9; + for (int j = 0; j < DataBlock.Length; j++) + length += DataBlock[j].Length; + return length; + } + } + public DataBlockBlock[] DataBlock; + + public PreloadSoundPacket() + { + HasVariableBlocks = true; + Type = PacketType.PreloadSound; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 15; + Header.Reliable = true; + DataBlock = null; + } + + public PreloadSoundPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(DataBlock == null || DataBlock.Length != -1) { + DataBlock = new DataBlockBlock[count]; + for(int j = 0; j < count; j++) + { DataBlock[j] = new DataBlockBlock(); } + } + for (int j = 0; j < count; j++) + { DataBlock[j].FromBytes(bytes, ref i); } + } + + public PreloadSoundPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(DataBlock == null || DataBlock.Length != count) { + DataBlock = new DataBlockBlock[count]; + for(int j = 0; j < count; j++) + { DataBlock[j] = new DataBlockBlock(); } + } + for (int j = 0; j < count; j++) + { DataBlock[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 8; + length++; + for (int j = 0; j < DataBlock.Length; j++) { length += DataBlock[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)DataBlock.Length; + for (int j = 0; j < DataBlock.Length; j++) { DataBlock[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 8; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int DataBlockStart = 0; + do + { + int variableLength = 0; + int DataBlockCount = 0; + + i = DataBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < DataBlock.Length) { + int blockLength = DataBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++DataBlockCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)DataBlockCount; + for (i = DataBlockStart; i < DataBlockStart + DataBlockCount; i++) { DataBlock[i].ToBytes(packet, ref length); } + DataBlockStart += DataBlockCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + DataBlockStart < DataBlock.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ViewerEffectPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class EffectBlock : PacketBlock + { + public UUID ID; + public UUID AgentID; + public byte Type; + public float Duration; + public byte[] Color; + public byte[] TypeData; + + public override int Length + { + get + { + int length = 42; + if (TypeData != null) { length += TypeData.Length; } + return length; + } + } + + public EffectBlock() { } + public EffectBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ID.FromBytes(bytes, i); i += 16; + AgentID.FromBytes(bytes, i); i += 16; + Type = (byte)bytes[i++]; + Duration = Utils.BytesToFloat(bytes, i); i += 4; + Color = new byte[4]; + Buffer.BlockCopy(bytes, i, Color, 0, 4); i += 4; + length = bytes[i++]; + TypeData = new byte[length]; + Buffer.BlockCopy(bytes, i, TypeData, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + AgentID.ToBytes(bytes, i); i += 16; + bytes[i++] = Type; + Utils.FloatToBytes(Duration, bytes, i); i += 4; + Buffer.BlockCopy(Color, 0, bytes, i, 4);i += 4; + bytes[i++] = (byte)TypeData.Length; + Buffer.BlockCopy(TypeData, 0, bytes, i, TypeData.Length); i += TypeData.Length; + } + + } + + public override int Length + { + get + { + int length = 9; + length += AgentData.Length; + for (int j = 0; j < Effect.Length; j++) + length += Effect[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public EffectBlock[] Effect; + + public ViewerEffectPacket() + { + HasVariableBlocks = true; + Type = PacketType.ViewerEffect; + Header = new Header(); + Header.Frequency = PacketFrequency.Medium; + Header.ID = 17; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + Effect = null; + } + + public ViewerEffectPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Effect == null || Effect.Length != -1) { + Effect = new EffectBlock[count]; + for(int j = 0; j < count; j++) + { Effect[j] = new EffectBlock(); } + } + for (int j = 0; j < count; j++) + { Effect[j].FromBytes(bytes, ref i); } + } + + public ViewerEffectPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(Effect == null || Effect.Length != count) { + Effect = new EffectBlock[count]; + for(int j = 0; j < count; j++) + { Effect[j] = new EffectBlock(); } + } + for (int j = 0; j < count; j++) + { Effect[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 8; + length += AgentData.Length; + length++; + for (int j = 0; j < Effect.Length; j++) { length += Effect[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)Effect.Length; + for (int j = 0; j < Effect.Length; j++) { Effect[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 8; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int EffectStart = 0; + do + { + int variableLength = 0; + int EffectCount = 0; + + i = EffectStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < Effect.Length) { + int blockLength = Effect[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++EffectCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)EffectCount; + for (i = EffectStart; i < EffectStart + EffectCount; i++) { Effect[i].ToBytes(packet, ref length); } + EffectStart += EffectCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + EffectStart < Effect.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class StartPingCheckPacket : Packet + { + /// + public sealed class PingIDBlock : PacketBlock + { + public byte PingID; + public uint OldestUnacked; + + public override int Length + { + get + { + return 5; + } + } + + public PingIDBlock() { } + public PingIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PingID = (byte)bytes[i++]; + OldestUnacked = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = PingID; + Utils.UIntToBytes(OldestUnacked, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 7; + length += PingID.Length; + return length; + } + } + public PingIDBlock PingID; + + public StartPingCheckPacket() + { + HasVariableBlocks = false; + Type = PacketType.StartPingCheck; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 1; + Header.Reliable = true; + PingID = new PingIDBlock(); + } + + public StartPingCheckPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + PingID.FromBytes(bytes, ref i); + } + + public StartPingCheckPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + PingID.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += PingID.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + PingID.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CompletePingCheckPacket : Packet + { + /// + public sealed class PingIDBlock : PacketBlock + { + public byte PingID; + + public override int Length + { + get + { + return 1; + } + } + + public PingIDBlock() { } + public PingIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + PingID = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = PingID; + } + + } + + public override int Length + { + get + { + int length = 7; + length += PingID.Length; + return length; + } + } + public PingIDBlock PingID; + + public CompletePingCheckPacket() + { + HasVariableBlocks = false; + Type = PacketType.CompletePingCheck; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 2; + Header.Reliable = true; + PingID = new PingIDBlock(); + } + + public CompletePingCheckPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + PingID.FromBytes(bytes, ref i); + } + + public CompletePingCheckPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + PingID.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += PingID.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + PingID.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + public Quaternion BodyRotation; + public Quaternion HeadRotation; + public byte State; + public Vector3 CameraCenter; + public Vector3 CameraAtAxis; + public Vector3 CameraLeftAxis; + public Vector3 CameraUpAxis; + public float Far; + public uint ControlFlags; + public byte Flags; + + public override int Length + { + get + { + return 114; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + BodyRotation.FromBytes(bytes, i, true); i += 12; + HeadRotation.FromBytes(bytes, i, true); i += 12; + State = (byte)bytes[i++]; + CameraCenter.FromBytes(bytes, i); i += 12; + CameraAtAxis.FromBytes(bytes, i); i += 12; + CameraLeftAxis.FromBytes(bytes, i); i += 12; + CameraUpAxis.FromBytes(bytes, i); i += 12; + Far = Utils.BytesToFloat(bytes, i); i += 4; + ControlFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Flags = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + BodyRotation.ToBytes(bytes, i); i += 12; + HeadRotation.ToBytes(bytes, i); i += 12; + bytes[i++] = State; + CameraCenter.ToBytes(bytes, i); i += 12; + CameraAtAxis.ToBytes(bytes, i); i += 12; + CameraLeftAxis.ToBytes(bytes, i); i += 12; + CameraUpAxis.ToBytes(bytes, i); i += 12; + Utils.FloatToBytes(Far, bytes, i); i += 4; + Utils.UIntToBytes(ControlFlags, bytes, i); i += 4; + bytes[i++] = Flags; + } + + } + + public override int Length + { + get + { + int length = 7; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 4; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + } + + public AgentUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentAnimationPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class AnimationListBlock : PacketBlock + { + public UUID AnimID; + public bool StartAnim; + + public override int Length + { + get + { + return 17; + } + } + + public AnimationListBlock() { } + public AnimationListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AnimID.FromBytes(bytes, i); i += 16; + StartAnim = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AnimID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((StartAnim) ? 1 : 0); + } + + } + + /// + public sealed class PhysicalAvatarEventListBlock : PacketBlock + { + public byte[] TypeData; + + public override int Length + { + get + { + int length = 1; + if (TypeData != null) { length += TypeData.Length; } + return length; + } + } + + public PhysicalAvatarEventListBlock() { } + public PhysicalAvatarEventListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + TypeData = new byte[length]; + Buffer.BlockCopy(bytes, i, TypeData, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)TypeData.Length; + Buffer.BlockCopy(TypeData, 0, bytes, i, TypeData.Length); i += TypeData.Length; + } + + } + + public override int Length + { + get + { + int length = 9; + length += AgentData.Length; + for (int j = 0; j < AnimationList.Length; j++) + length += AnimationList[j].Length; + for (int j = 0; j < PhysicalAvatarEventList.Length; j++) + length += PhysicalAvatarEventList[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public AnimationListBlock[] AnimationList; + public PhysicalAvatarEventListBlock[] PhysicalAvatarEventList; + + public AgentAnimationPacket() + { + HasVariableBlocks = true; + Type = PacketType.AgentAnimation; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 5; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + AnimationList = null; + PhysicalAvatarEventList = null; + } + + public AgentAnimationPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AnimationList == null || AnimationList.Length != -1) { + AnimationList = new AnimationListBlock[count]; + for(int j = 0; j < count; j++) + { AnimationList[j] = new AnimationListBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationList[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(PhysicalAvatarEventList == null || PhysicalAvatarEventList.Length != -1) { + PhysicalAvatarEventList = new PhysicalAvatarEventListBlock[count]; + for(int j = 0; j < count; j++) + { PhysicalAvatarEventList[j] = new PhysicalAvatarEventListBlock(); } + } + for (int j = 0; j < count; j++) + { PhysicalAvatarEventList[j].FromBytes(bytes, ref i); } + } + + public AgentAnimationPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AnimationList == null || AnimationList.Length != count) { + AnimationList = new AnimationListBlock[count]; + for(int j = 0; j < count; j++) + { AnimationList[j] = new AnimationListBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationList[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(PhysicalAvatarEventList == null || PhysicalAvatarEventList.Length != count) { + PhysicalAvatarEventList = new PhysicalAvatarEventListBlock[count]; + for(int j = 0; j < count; j++) + { PhysicalAvatarEventList[j] = new PhysicalAvatarEventListBlock(); } + } + for (int j = 0; j < count; j++) + { PhysicalAvatarEventList[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + length++; + for (int j = 0; j < AnimationList.Length; j++) { length += AnimationList[j].Length; } + length++; + for (int j = 0; j < PhysicalAvatarEventList.Length; j++) { length += PhysicalAvatarEventList[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)AnimationList.Length; + for (int j = 0; j < AnimationList.Length; j++) { AnimationList[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)PhysicalAvatarEventList.Length; + for (int j = 0; j < PhysicalAvatarEventList.Length; j++) { PhysicalAvatarEventList[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 2; + + int AnimationListStart = 0; + int PhysicalAvatarEventListStart = 0; + do + { + int variableLength = 0; + int AnimationListCount = 0; + int PhysicalAvatarEventListCount = 0; + + i = AnimationListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AnimationList.Length) { + int blockLength = AnimationList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AnimationListCount; + } + else { break; } + ++i; + } + + i = PhysicalAvatarEventListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < PhysicalAvatarEventList.Length) { + int blockLength = PhysicalAvatarEventList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++PhysicalAvatarEventListCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)AnimationListCount; + for (i = AnimationListStart; i < AnimationListStart + AnimationListCount; i++) { AnimationList[i].ToBytes(packet, ref length); } + AnimationListStart += AnimationListCount; + + packet[length++] = (byte)PhysicalAvatarEventListCount; + for (i = PhysicalAvatarEventListStart; i < PhysicalAvatarEventListStart + PhysicalAvatarEventListCount; i++) { PhysicalAvatarEventList[i].ToBytes(packet, ref length); } + PhysicalAvatarEventListStart += PhysicalAvatarEventListCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + AnimationListStart < AnimationList.Length || + PhysicalAvatarEventListStart < PhysicalAvatarEventList.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AgentRequestSitPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class TargetObjectBlock : PacketBlock + { + public UUID TargetID; + public Vector3 Offset; + + public override int Length + { + get + { + return 28; + } + } + + public TargetObjectBlock() { } + public TargetObjectBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + TargetID.FromBytes(bytes, i); i += 16; + Offset.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TargetID.ToBytes(bytes, i); i += 16; + Offset.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 7; + length += AgentData.Length; + length += TargetObject.Length; + return length; + } + } + public AgentDataBlock AgentData; + public TargetObjectBlock TargetObject; + + public AgentRequestSitPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentRequestSit; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 6; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + TargetObject = new TargetObjectBlock(); + } + + public AgentRequestSitPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + TargetObject.FromBytes(bytes, ref i); + } + + public AgentRequestSitPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + TargetObject.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + length += TargetObject.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + TargetObject.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AgentSitPacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 7; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public AgentSitPacket() + { + HasVariableBlocks = false; + Type = PacketType.AgentSit; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 7; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public AgentSitPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public AgentSitPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class RequestImagePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 32; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class RequestImageBlock : PacketBlock + { + public UUID Image; + public sbyte DiscardLevel; + public float DownloadPriority; + public uint Packet; + public byte Type; + + public override int Length + { + get + { + return 26; + } + } + + public RequestImageBlock() { } + public RequestImageBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Image.FromBytes(bytes, i); i += 16; + DiscardLevel = (sbyte)bytes[i++]; + DownloadPriority = Utils.BytesToFloat(bytes, i); i += 4; + Packet = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Type = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Image.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)DiscardLevel; + Utils.FloatToBytes(DownloadPriority, bytes, i); i += 4; + Utils.UIntToBytes(Packet, bytes, i); i += 4; + bytes[i++] = Type; + } + + } + + public override int Length + { + get + { + int length = 8; + length += AgentData.Length; + for (int j = 0; j < RequestImage.Length; j++) + length += RequestImage[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public RequestImageBlock[] RequestImage; + + public RequestImagePacket() + { + HasVariableBlocks = true; + Type = PacketType.RequestImage; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 8; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + RequestImage = null; + } + + public RequestImagePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RequestImage == null || RequestImage.Length != -1) { + RequestImage = new RequestImageBlock[count]; + for(int j = 0; j < count; j++) + { RequestImage[j] = new RequestImageBlock(); } + } + for (int j = 0; j < count; j++) + { RequestImage[j].FromBytes(bytes, ref i); } + } + + public RequestImagePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(RequestImage == null || RequestImage.Length != count) { + RequestImage = new RequestImageBlock[count]; + for(int j = 0; j < count; j++) + { RequestImage[j] = new RequestImageBlock(); } + } + for (int j = 0; j < count; j++) + { RequestImage[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + length++; + for (int j = 0; j < RequestImage.Length; j++) { length += RequestImage[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)RequestImage.Length; + for (int j = 0; j < RequestImage.Length; j++) { RequestImage[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int RequestImageStart = 0; + do + { + int variableLength = 0; + int RequestImageCount = 0; + + i = RequestImageStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < RequestImage.Length) { + int blockLength = RequestImage[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++RequestImageCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)RequestImageCount; + for (i = RequestImageStart; i < RequestImageStart + RequestImageCount; i++) { RequestImage[i].ToBytes(packet, ref length); } + RequestImageStart += RequestImageCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + RequestImageStart < RequestImage.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ImageDataPacket : Packet + { + /// + public sealed class ImageIDBlock : PacketBlock + { + public UUID ID; + public byte Codec; + public uint Size; + public ushort Packets; + + public override int Length + { + get + { + return 23; + } + } + + public ImageIDBlock() { } + public ImageIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + Codec = (byte)bytes[i++]; + Size = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Packets = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + bytes[i++] = Codec; + Utils.UIntToBytes(Size, bytes, i); i += 4; + bytes[i++] = (byte)(Packets % 256); + bytes[i++] = (byte)((Packets >> 8) % 256); + } + + } + + /// + public sealed class ImageDataBlock : PacketBlock + { + public byte[] Data; + + public override int Length + { + get + { + int length = 2; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public ImageDataBlock() { } + public ImageDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 7; + length += ImageID.Length; + length += ImageData.Length; + return length; + } + } + public ImageIDBlock ImageID; + public ImageDataBlock ImageData; + + public ImageDataPacket() + { + HasVariableBlocks = false; + Type = PacketType.ImageData; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 9; + Header.Reliable = true; + ImageID = new ImageIDBlock(); + ImageData = new ImageDataBlock(); + } + + public ImageDataPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ImageID.FromBytes(bytes, ref i); + ImageData.FromBytes(bytes, ref i); + } + + public ImageDataPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ImageID.FromBytes(bytes, ref i); + ImageData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += ImageID.Length; + length += ImageData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ImageID.ToBytes(bytes, ref i); + ImageData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ImagePacketPacket : Packet + { + /// + public sealed class ImageIDBlock : PacketBlock + { + public UUID ID; + public ushort Packet; + + public override int Length + { + get + { + return 18; + } + } + + public ImageIDBlock() { } + public ImageIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + Packet = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)(Packet % 256); + bytes[i++] = (byte)((Packet >> 8) % 256); + } + + } + + /// + public sealed class ImageDataBlock : PacketBlock + { + public byte[] Data; + + public override int Length + { + get + { + int length = 2; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public ImageDataBlock() { } + public ImageDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 7; + length += ImageID.Length; + length += ImageData.Length; + return length; + } + } + public ImageIDBlock ImageID; + public ImageDataBlock ImageData; + + public ImagePacketPacket() + { + HasVariableBlocks = false; + Type = PacketType.ImagePacket; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 10; + Header.Reliable = true; + ImageID = new ImageIDBlock(); + ImageData = new ImageDataBlock(); + } + + public ImagePacketPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ImageID.FromBytes(bytes, ref i); + ImageData.FromBytes(bytes, ref i); + } + + public ImagePacketPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ImageID.FromBytes(bytes, ref i); + ImageData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += ImageID.Length; + length += ImageData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ImageID.ToBytes(bytes, ref i); + ImageData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class LayerDataPacket : Packet + { + /// + public sealed class LayerIDBlock : PacketBlock + { + public byte Type; + + public override int Length + { + get + { + return 1; + } + } + + public LayerIDBlock() { } + public LayerIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Type = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = Type; + } + + } + + /// + public sealed class LayerDataBlock : PacketBlock + { + public byte[] Data; + + public override int Length + { + get + { + int length = 2; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public LayerDataBlock() { } + public LayerDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 7; + length += LayerID.Length; + length += LayerData.Length; + return length; + } + } + public LayerIDBlock LayerID; + public LayerDataBlock LayerData; + + public LayerDataPacket() + { + HasVariableBlocks = false; + Type = PacketType.LayerData; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 11; + Header.Reliable = true; + LayerID = new LayerIDBlock(); + LayerData = new LayerDataBlock(); + } + + public LayerDataPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + LayerID.FromBytes(bytes, ref i); + LayerData.FromBytes(bytes, ref i); + } + + public LayerDataPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + LayerID.FromBytes(bytes, ref i); + LayerData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += LayerID.Length; + length += LayerData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + LayerID.ToBytes(bytes, ref i); + LayerData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ObjectUpdatePacket : Packet + { + /// + public sealed class RegionDataBlock : PacketBlock + { + public ulong RegionHandle; + public ushort TimeDilation; + + public override int Length + { + get + { + return 10; + } + } + + public RegionDataBlock() { } + public RegionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + TimeDilation = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + bytes[i++] = (byte)(TimeDilation % 256); + bytes[i++] = (byte)((TimeDilation >> 8) % 256); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ID; + public byte State; + public UUID FullID; + public uint CRC; + public byte PCode; + public byte Material; + public byte ClickAction; + public Vector3 Scale; + public byte[] ObjectData; + public uint ParentID; + public uint UpdateFlags; + public byte PathCurve; + public byte ProfileCurve; + public ushort PathBegin; + public ushort PathEnd; + public byte PathScaleX; + public byte PathScaleY; + public byte PathShearX; + public byte PathShearY; + public sbyte PathTwist; + public sbyte PathTwistBegin; + public sbyte PathRadiusOffset; + public sbyte PathTaperX; + public sbyte PathTaperY; + public byte PathRevolutions; + public sbyte PathSkew; + public ushort ProfileBegin; + public ushort ProfileEnd; + public ushort ProfileHollow; + public byte[] TextureEntry; + public byte[] TextureAnim; + public byte[] NameValue; + public byte[] Data; + public byte[] Text; + public byte[] TextColor; + public byte[] MediaURL; + public byte[] PSBlock; + public byte[] ExtraParams; + public UUID Sound; + public UUID OwnerID; + public float Gain; + public byte Flags; + public float Radius; + public byte JointType; + public Vector3 JointPivot; + public Vector3 JointAxisOrAnchor; + + public override int Length + { + get + { + int length = 153; + if (ObjectData != null) { length += ObjectData.Length; } + if (TextureEntry != null) { length += TextureEntry.Length; } + if (TextureAnim != null) { length += TextureAnim.Length; } + if (NameValue != null) { length += NameValue.Length; } + if (Data != null) { length += Data.Length; } + if (Text != null) { length += Text.Length; } + if (MediaURL != null) { length += MediaURL.Length; } + if (PSBlock != null) { length += PSBlock.Length; } + if (ExtraParams != null) { length += ExtraParams.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + ID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + State = (byte)bytes[i++]; + FullID.FromBytes(bytes, i); i += 16; + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PCode = (byte)bytes[i++]; + Material = (byte)bytes[i++]; + ClickAction = (byte)bytes[i++]; + Scale.FromBytes(bytes, i); i += 12; + length = bytes[i++]; + ObjectData = new byte[length]; + Buffer.BlockCopy(bytes, i, ObjectData, 0, length); i += length; + ParentID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + UpdateFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PathCurve = (byte)bytes[i++]; + ProfileCurve = (byte)bytes[i++]; + PathBegin = (ushort)(bytes[i++] + (bytes[i++] << 8)); + PathEnd = (ushort)(bytes[i++] + (bytes[i++] << 8)); + PathScaleX = (byte)bytes[i++]; + PathScaleY = (byte)bytes[i++]; + PathShearX = (byte)bytes[i++]; + PathShearY = (byte)bytes[i++]; + PathTwist = (sbyte)bytes[i++]; + PathTwistBegin = (sbyte)bytes[i++]; + PathRadiusOffset = (sbyte)bytes[i++]; + PathTaperX = (sbyte)bytes[i++]; + PathTaperY = (sbyte)bytes[i++]; + PathRevolutions = (byte)bytes[i++]; + PathSkew = (sbyte)bytes[i++]; + ProfileBegin = (ushort)(bytes[i++] + (bytes[i++] << 8)); + ProfileEnd = (ushort)(bytes[i++] + (bytes[i++] << 8)); + ProfileHollow = (ushort)(bytes[i++] + (bytes[i++] << 8)); + length = (bytes[i++] + (bytes[i++] << 8)); + TextureEntry = new byte[length]; + Buffer.BlockCopy(bytes, i, TextureEntry, 0, length); i += length; + length = bytes[i++]; + TextureAnim = new byte[length]; + Buffer.BlockCopy(bytes, i, TextureAnim, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + NameValue = new byte[length]; + Buffer.BlockCopy(bytes, i, NameValue, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + length = bytes[i++]; + Text = new byte[length]; + Buffer.BlockCopy(bytes, i, Text, 0, length); i += length; + TextColor = new byte[4]; + Buffer.BlockCopy(bytes, i, TextColor, 0, 4); i += 4; + length = bytes[i++]; + MediaURL = new byte[length]; + Buffer.BlockCopy(bytes, i, MediaURL, 0, length); i += length; + length = bytes[i++]; + PSBlock = new byte[length]; + Buffer.BlockCopy(bytes, i, PSBlock, 0, length); i += length; + length = bytes[i++]; + ExtraParams = new byte[length]; + Buffer.BlockCopy(bytes, i, ExtraParams, 0, length); i += length; + Sound.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + Gain = Utils.BytesToFloat(bytes, i); i += 4; + Flags = (byte)bytes[i++]; + Radius = Utils.BytesToFloat(bytes, i); i += 4; + JointType = (byte)bytes[i++]; + JointPivot.FromBytes(bytes, i); i += 12; + JointAxisOrAnchor.FromBytes(bytes, i); i += 12; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ID, bytes, i); i += 4; + bytes[i++] = State; + FullID.ToBytes(bytes, i); i += 16; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + bytes[i++] = PCode; + bytes[i++] = Material; + bytes[i++] = ClickAction; + Scale.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)ObjectData.Length; + Buffer.BlockCopy(ObjectData, 0, bytes, i, ObjectData.Length); i += ObjectData.Length; + Utils.UIntToBytes(ParentID, bytes, i); i += 4; + Utils.UIntToBytes(UpdateFlags, bytes, i); i += 4; + bytes[i++] = PathCurve; + bytes[i++] = ProfileCurve; + bytes[i++] = (byte)(PathBegin % 256); + bytes[i++] = (byte)((PathBegin >> 8) % 256); + bytes[i++] = (byte)(PathEnd % 256); + bytes[i++] = (byte)((PathEnd >> 8) % 256); + bytes[i++] = PathScaleX; + bytes[i++] = PathScaleY; + bytes[i++] = PathShearX; + bytes[i++] = PathShearY; + bytes[i++] = (byte)PathTwist; + bytes[i++] = (byte)PathTwistBegin; + bytes[i++] = (byte)PathRadiusOffset; + bytes[i++] = (byte)PathTaperX; + bytes[i++] = (byte)PathTaperY; + bytes[i++] = PathRevolutions; + bytes[i++] = (byte)PathSkew; + bytes[i++] = (byte)(ProfileBegin % 256); + bytes[i++] = (byte)((ProfileBegin >> 8) % 256); + bytes[i++] = (byte)(ProfileEnd % 256); + bytes[i++] = (byte)((ProfileEnd >> 8) % 256); + bytes[i++] = (byte)(ProfileHollow % 256); + bytes[i++] = (byte)((ProfileHollow >> 8) % 256); + bytes[i++] = (byte)(TextureEntry.Length % 256); + bytes[i++] = (byte)((TextureEntry.Length >> 8) % 256); + Buffer.BlockCopy(TextureEntry, 0, bytes, i, TextureEntry.Length); i += TextureEntry.Length; + bytes[i++] = (byte)TextureAnim.Length; + Buffer.BlockCopy(TextureAnim, 0, bytes, i, TextureAnim.Length); i += TextureAnim.Length; + bytes[i++] = (byte)(NameValue.Length % 256); + bytes[i++] = (byte)((NameValue.Length >> 8) % 256); + Buffer.BlockCopy(NameValue, 0, bytes, i, NameValue.Length); i += NameValue.Length; + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + bytes[i++] = (byte)Text.Length; + Buffer.BlockCopy(Text, 0, bytes, i, Text.Length); i += Text.Length; + Buffer.BlockCopy(TextColor, 0, bytes, i, 4);i += 4; + bytes[i++] = (byte)MediaURL.Length; + Buffer.BlockCopy(MediaURL, 0, bytes, i, MediaURL.Length); i += MediaURL.Length; + bytes[i++] = (byte)PSBlock.Length; + Buffer.BlockCopy(PSBlock, 0, bytes, i, PSBlock.Length); i += PSBlock.Length; + bytes[i++] = (byte)ExtraParams.Length; + Buffer.BlockCopy(ExtraParams, 0, bytes, i, ExtraParams.Length); i += ExtraParams.Length; + Sound.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + Utils.FloatToBytes(Gain, bytes, i); i += 4; + bytes[i++] = Flags; + Utils.FloatToBytes(Radius, bytes, i); i += 4; + bytes[i++] = JointType; + JointPivot.ToBytes(bytes, i); i += 12; + JointAxisOrAnchor.ToBytes(bytes, i); i += 12; + } + + } + + public override int Length + { + get + { + int length = 8; + length += RegionData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public RegionDataBlock RegionData; + public ObjectDataBlock[] ObjectData; + + public ObjectUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 12; + Header.Reliable = true; + Header.Zerocoded = true; + RegionData = new RegionDataBlock(); + ObjectData = null; + } + + public ObjectUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += RegionData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RegionData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += RegionData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + RegionData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectUpdateCompressedPacket : Packet + { + /// + public sealed class RegionDataBlock : PacketBlock + { + public ulong RegionHandle; + public ushort TimeDilation; + + public override int Length + { + get + { + return 10; + } + } + + public RegionDataBlock() { } + public RegionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + TimeDilation = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + bytes[i++] = (byte)(TimeDilation % 256); + bytes[i++] = (byte)((TimeDilation >> 8) % 256); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint UpdateFlags; + public byte[] Data; + + public override int Length + { + get + { + int length = 6; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + UpdateFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(UpdateFlags, bytes, i); i += 4; + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 8; + length += RegionData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public RegionDataBlock RegionData; + public ObjectDataBlock[] ObjectData; + + public ObjectUpdateCompressedPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectUpdateCompressed; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 13; + Header.Reliable = true; + RegionData = new RegionDataBlock(); + ObjectData = null; + } + + public ObjectUpdateCompressedPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectUpdateCompressedPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += RegionData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RegionData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += RegionData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + RegionData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ObjectUpdateCachedPacket : Packet + { + /// + public sealed class RegionDataBlock : PacketBlock + { + public ulong RegionHandle; + public ushort TimeDilation; + + public override int Length + { + get + { + return 10; + } + } + + public RegionDataBlock() { } + public RegionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + TimeDilation = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + bytes[i++] = (byte)(TimeDilation % 256); + bytes[i++] = (byte)((TimeDilation >> 8) % 256); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ID; + public uint CRC; + public uint UpdateFlags; + + public override int Length + { + get + { + return 12; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + CRC = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + UpdateFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ID, bytes, i); i += 4; + Utils.UIntToBytes(CRC, bytes, i); i += 4; + Utils.UIntToBytes(UpdateFlags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 8; + length += RegionData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public RegionDataBlock RegionData; + public ObjectDataBlock[] ObjectData; + + public ObjectUpdateCachedPacket() + { + HasVariableBlocks = true; + Type = PacketType.ObjectUpdateCached; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 14; + Header.Reliable = true; + RegionData = new RegionDataBlock(); + ObjectData = null; + } + + public ObjectUpdateCachedPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ObjectUpdateCachedPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += RegionData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RegionData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += RegionData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + RegionData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ImprovedTerseObjectUpdatePacket : Packet + { + /// + public sealed class RegionDataBlock : PacketBlock + { + public ulong RegionHandle; + public ushort TimeDilation; + + public override int Length + { + get + { + return 10; + } + } + + public RegionDataBlock() { } + public RegionDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + TimeDilation = (ushort)(bytes[i++] + (bytes[i++] << 8)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + bytes[i++] = (byte)(TimeDilation % 256); + bytes[i++] = (byte)((TimeDilation >> 8) % 256); + } + + } + + /// + public sealed class ObjectDataBlock : PacketBlock + { + public byte[] Data; + public byte[] TextureEntry; + + public override int Length + { + get + { + int length = 3; + if (Data != null) { length += Data.Length; } + if (TextureEntry != null) { length += TextureEntry.Length; } + return length; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + length = (bytes[i++] + (bytes[i++] << 8)); + TextureEntry = new byte[length]; + Buffer.BlockCopy(bytes, i, TextureEntry, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)Data.Length; + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + bytes[i++] = (byte)(TextureEntry.Length % 256); + bytes[i++] = (byte)((TextureEntry.Length >> 8) % 256); + Buffer.BlockCopy(TextureEntry, 0, bytes, i, TextureEntry.Length); i += TextureEntry.Length; + } + + } + + public override int Length + { + get + { + int length = 8; + length += RegionData.Length; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public RegionDataBlock RegionData; + public ObjectDataBlock[] ObjectData; + + public ImprovedTerseObjectUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.ImprovedTerseObjectUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 15; + Header.Reliable = true; + RegionData = new RegionDataBlock(); + ObjectData = null; + } + + public ImprovedTerseObjectUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public ImprovedTerseObjectUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + RegionData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += RegionData.Length; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + RegionData.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += RegionData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + RegionData.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class KillObjectPacket : Packet + { + /// + public sealed class ObjectDataBlock : PacketBlock + { + public uint ID; + + public override int Length + { + get + { + return 4; + } + } + + public ObjectDataBlock() { } + public ObjectDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(ID, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 8; + for (int j = 0; j < ObjectData.Length; j++) + length += ObjectData[j].Length; + return length; + } + } + public ObjectDataBlock[] ObjectData; + + public KillObjectPacket() + { + HasVariableBlocks = true; + Type = PacketType.KillObject; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 16; + Header.Reliable = true; + ObjectData = null; + } + + public KillObjectPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != -1) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public KillObjectPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + int count = (int)bytes[i++]; + if(ObjectData == null || ObjectData.Length != count) { + ObjectData = new ObjectDataBlock[count]; + for(int j = 0; j < count; j++) + { ObjectData[j] = new ObjectDataBlock(); } + } + for (int j = 0; j < count; j++) + { ObjectData[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length++; + for (int j = 0; j < ObjectData.Length; j++) { length += ObjectData[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + bytes[i++] = (byte)ObjectData.Length; + for (int j = 0; j < ObjectData.Length; j++) { ObjectData[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + fixedLength += 1; + + int ObjectDataStart = 0; + do + { + int variableLength = 0; + int ObjectDataCount = 0; + + i = ObjectDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < ObjectData.Length) { + int blockLength = ObjectData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++ObjectDataCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)ObjectDataCount; + for (i = ObjectDataStart; i < ObjectDataStart + ObjectDataCount; i++) { ObjectData[i].ToBytes(packet, ref length); } + ObjectDataStart += ObjectDataCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + ObjectDataStart < ObjectData.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class TransferPacketPacket : Packet + { + /// + public sealed class TransferDataBlock : PacketBlock + { + public UUID TransferID; + public int ChannelType; + public int Packet; + public int Status; + public byte[] Data; + + public override int Length + { + get + { + int length = 30; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public TransferDataBlock() { } + public TransferDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + TransferID.FromBytes(bytes, i); i += 16; + ChannelType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Packet = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Status = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + TransferID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(ChannelType, bytes, i); i += 4; + Utils.IntToBytes(Packet, bytes, i); i += 4; + Utils.IntToBytes(Status, bytes, i); i += 4; + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 7; + length += TransferData.Length; + return length; + } + } + public TransferDataBlock TransferData; + + public TransferPacketPacket() + { + HasVariableBlocks = false; + Type = PacketType.TransferPacket; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 17; + Header.Reliable = true; + TransferData = new TransferDataBlock(); + } + + public TransferPacketPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + TransferData.FromBytes(bytes, ref i); + } + + public TransferPacketPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + TransferData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += TransferData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + TransferData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SendXferPacketPacket : Packet + { + /// + public sealed class XferIDBlock : PacketBlock + { + public ulong ID; + public uint Packet; + + public override int Length + { + get + { + return 12; + } + } + + public XferIDBlock() { } + public XferIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + Packet = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(ID, bytes, i); i += 8; + Utils.UIntToBytes(Packet, bytes, i); i += 4; + } + + } + + /// + public sealed class DataPacketBlock : PacketBlock + { + public byte[] Data; + + public override int Length + { + get + { + int length = 2; + if (Data != null) { length += Data.Length; } + return length; + } + } + + public DataPacketBlock() { } + public DataPacketBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + Data = new byte[length]; + Buffer.BlockCopy(bytes, i, Data, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(Data.Length % 256); + bytes[i++] = (byte)((Data.Length >> 8) % 256); + Buffer.BlockCopy(Data, 0, bytes, i, Data.Length); i += Data.Length; + } + + } + + public override int Length + { + get + { + int length = 7; + length += XferID.Length; + length += DataPacket.Length; + return length; + } + } + public XferIDBlock XferID; + public DataPacketBlock DataPacket; + + public SendXferPacketPacket() + { + HasVariableBlocks = false; + Type = PacketType.SendXferPacket; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 18; + Header.Reliable = true; + XferID = new XferIDBlock(); + DataPacket = new DataPacketBlock(); + } + + public SendXferPacketPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + XferID.FromBytes(bytes, ref i); + DataPacket.FromBytes(bytes, ref i); + } + + public SendXferPacketPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + XferID.FromBytes(bytes, ref i); + DataPacket.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += XferID.Length; + length += DataPacket.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + XferID.ToBytes(bytes, ref i); + DataPacket.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ConfirmXferPacketPacket : Packet + { + /// + public sealed class XferIDBlock : PacketBlock + { + public ulong ID; + public uint Packet; + + public override int Length + { + get + { + return 12; + } + } + + public XferIDBlock() { } + public XferIDBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + Packet = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(ID, bytes, i); i += 8; + Utils.UIntToBytes(Packet, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 7; + length += XferID.Length; + return length; + } + } + public XferIDBlock XferID; + + public ConfirmXferPacketPacket() + { + HasVariableBlocks = false; + Type = PacketType.ConfirmXferPacket; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 19; + Header.Reliable = true; + XferID = new XferIDBlock(); + } + + public ConfirmXferPacketPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + XferID.FromBytes(bytes, ref i); + } + + public ConfirmXferPacketPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + XferID.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += XferID.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + XferID.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class AvatarAnimationPacket : Packet + { + /// + public sealed class SenderBlock : PacketBlock + { + public UUID ID; + + public override int Length + { + get + { + return 16; + } + } + + public SenderBlock() { } + public SenderBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class AnimationListBlock : PacketBlock + { + public UUID AnimID; + public int AnimSequenceID; + + public override int Length + { + get + { + return 20; + } + } + + public AnimationListBlock() { } + public AnimationListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AnimID.FromBytes(bytes, i); i += 16; + AnimSequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + AnimID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(AnimSequenceID, bytes, i); i += 4; + } + + } + + /// + public sealed class AnimationSourceListBlock : PacketBlock + { + public UUID ObjectID; + + public override int Length + { + get + { + return 16; + } + } + + public AnimationSourceListBlock() { } + public AnimationSourceListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class PhysicalAvatarEventListBlock : PacketBlock + { + public byte[] TypeData; + + public override int Length + { + get + { + int length = 1; + if (TypeData != null) { length += TypeData.Length; } + return length; + } + } + + public PhysicalAvatarEventListBlock() { } + public PhysicalAvatarEventListBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = bytes[i++]; + TypeData = new byte[length]; + Buffer.BlockCopy(bytes, i, TypeData, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)TypeData.Length; + Buffer.BlockCopy(TypeData, 0, bytes, i, TypeData.Length); i += TypeData.Length; + } + + } + + public override int Length + { + get + { + int length = 10; + length += Sender.Length; + for (int j = 0; j < AnimationList.Length; j++) + length += AnimationList[j].Length; + for (int j = 0; j < AnimationSourceList.Length; j++) + length += AnimationSourceList[j].Length; + for (int j = 0; j < PhysicalAvatarEventList.Length; j++) + length += PhysicalAvatarEventList[j].Length; + return length; + } + } + public SenderBlock Sender; + public AnimationListBlock[] AnimationList; + public AnimationSourceListBlock[] AnimationSourceList; + public PhysicalAvatarEventListBlock[] PhysicalAvatarEventList; + + public AvatarAnimationPacket() + { + HasVariableBlocks = true; + Type = PacketType.AvatarAnimation; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 20; + Header.Reliable = true; + Sender = new SenderBlock(); + AnimationList = null; + AnimationSourceList = null; + PhysicalAvatarEventList = null; + } + + public AvatarAnimationPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + Sender.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AnimationList == null || AnimationList.Length != -1) { + AnimationList = new AnimationListBlock[count]; + for(int j = 0; j < count; j++) + { AnimationList[j] = new AnimationListBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationList[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AnimationSourceList == null || AnimationSourceList.Length != -1) { + AnimationSourceList = new AnimationSourceListBlock[count]; + for(int j = 0; j < count; j++) + { AnimationSourceList[j] = new AnimationSourceListBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationSourceList[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(PhysicalAvatarEventList == null || PhysicalAvatarEventList.Length != -1) { + PhysicalAvatarEventList = new PhysicalAvatarEventListBlock[count]; + for(int j = 0; j < count; j++) + { PhysicalAvatarEventList[j] = new PhysicalAvatarEventListBlock(); } + } + for (int j = 0; j < count; j++) + { PhysicalAvatarEventList[j].FromBytes(bytes, ref i); } + } + + public AvatarAnimationPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + Sender.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(AnimationList == null || AnimationList.Length != count) { + AnimationList = new AnimationListBlock[count]; + for(int j = 0; j < count; j++) + { AnimationList[j] = new AnimationListBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationList[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AnimationSourceList == null || AnimationSourceList.Length != count) { + AnimationSourceList = new AnimationSourceListBlock[count]; + for(int j = 0; j < count; j++) + { AnimationSourceList[j] = new AnimationSourceListBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationSourceList[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(PhysicalAvatarEventList == null || PhysicalAvatarEventList.Length != count) { + PhysicalAvatarEventList = new PhysicalAvatarEventListBlock[count]; + for(int j = 0; j < count; j++) + { PhysicalAvatarEventList[j] = new PhysicalAvatarEventListBlock(); } + } + for (int j = 0; j < count; j++) + { PhysicalAvatarEventList[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += Sender.Length; + length++; + for (int j = 0; j < AnimationList.Length; j++) { length += AnimationList[j].Length; } + length++; + for (int j = 0; j < AnimationSourceList.Length; j++) { length += AnimationSourceList[j].Length; } + length++; + for (int j = 0; j < PhysicalAvatarEventList.Length; j++) { length += PhysicalAvatarEventList[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + Sender.ToBytes(bytes, ref i); + bytes[i++] = (byte)AnimationList.Length; + for (int j = 0; j < AnimationList.Length; j++) { AnimationList[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)AnimationSourceList.Length; + for (int j = 0; j < AnimationSourceList.Length; j++) { AnimationSourceList[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)PhysicalAvatarEventList.Length; + for (int j = 0; j < PhysicalAvatarEventList.Length; j++) { PhysicalAvatarEventList[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += Sender.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + Sender.ToBytes(fixedBytes, ref i); + fixedLength += 3; + + int AnimationListStart = 0; + int AnimationSourceListStart = 0; + int PhysicalAvatarEventListStart = 0; + do + { + int variableLength = 0; + int AnimationListCount = 0; + int AnimationSourceListCount = 0; + int PhysicalAvatarEventListCount = 0; + + i = AnimationListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AnimationList.Length) { + int blockLength = AnimationList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AnimationListCount; + } + else { break; } + ++i; + } + + i = AnimationSourceListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AnimationSourceList.Length) { + int blockLength = AnimationSourceList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AnimationSourceListCount; + } + else { break; } + ++i; + } + + i = PhysicalAvatarEventListStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < PhysicalAvatarEventList.Length) { + int blockLength = PhysicalAvatarEventList[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++PhysicalAvatarEventListCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)AnimationListCount; + for (i = AnimationListStart; i < AnimationListStart + AnimationListCount; i++) { AnimationList[i].ToBytes(packet, ref length); } + AnimationListStart += AnimationListCount; + + packet[length++] = (byte)AnimationSourceListCount; + for (i = AnimationSourceListStart; i < AnimationSourceListStart + AnimationSourceListCount; i++) { AnimationSourceList[i].ToBytes(packet, ref length); } + AnimationSourceListStart += AnimationSourceListCount; + + packet[length++] = (byte)PhysicalAvatarEventListCount; + for (i = PhysicalAvatarEventListStart; i < PhysicalAvatarEventListStart + PhysicalAvatarEventListCount; i++) { PhysicalAvatarEventList[i].ToBytes(packet, ref length); } + PhysicalAvatarEventListStart += PhysicalAvatarEventListCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + AnimationListStart < AnimationList.Length || + AnimationSourceListStart < AnimationSourceList.Length || + PhysicalAvatarEventListStart < PhysicalAvatarEventList.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class AvatarSitResponsePacket : Packet + { + /// + public sealed class SitObjectBlock : PacketBlock + { + public UUID ID; + + public override int Length + { + get + { + return 16; + } + } + + public SitObjectBlock() { } + public SitObjectBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + ID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class SitTransformBlock : PacketBlock + { + public bool AutoPilot; + public Vector3 SitPosition; + public Quaternion SitRotation; + public Vector3 CameraEyeOffset; + public Vector3 CameraAtOffset; + public bool ForceMouselook; + + public override int Length + { + get + { + return 50; + } + } + + public SitTransformBlock() { } + public SitTransformBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AutoPilot = (bytes[i++] != 0) ? (bool)true : (bool)false; + SitPosition.FromBytes(bytes, i); i += 12; + SitRotation.FromBytes(bytes, i, true); i += 12; + CameraEyeOffset.FromBytes(bytes, i); i += 12; + CameraAtOffset.FromBytes(bytes, i); i += 12; + ForceMouselook = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((AutoPilot) ? 1 : 0); + SitPosition.ToBytes(bytes, i); i += 12; + SitRotation.ToBytes(bytes, i); i += 12; + CameraEyeOffset.ToBytes(bytes, i); i += 12; + CameraAtOffset.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)((ForceMouselook) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 7; + length += SitObject.Length; + length += SitTransform.Length; + return length; + } + } + public SitObjectBlock SitObject; + public SitTransformBlock SitTransform; + + public AvatarSitResponsePacket() + { + HasVariableBlocks = false; + Type = PacketType.AvatarSitResponse; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 21; + Header.Reliable = true; + Header.Zerocoded = true; + SitObject = new SitObjectBlock(); + SitTransform = new SitTransformBlock(); + } + + public AvatarSitResponsePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + SitObject.FromBytes(bytes, ref i); + SitTransform.FromBytes(bytes, ref i); + } + + public AvatarSitResponsePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + SitObject.FromBytes(bytes, ref i); + SitTransform.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += SitObject.Length; + length += SitTransform.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + SitObject.ToBytes(bytes, ref i); + SitTransform.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class CameraConstraintPacket : Packet + { + /// + public sealed class CameraCollidePlaneBlock : PacketBlock + { + public Vector4 Plane; + + public override int Length + { + get + { + return 16; + } + } + + public CameraCollidePlaneBlock() { } + public CameraCollidePlaneBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Plane.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Plane.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 7; + length += CameraCollidePlane.Length; + return length; + } + } + public CameraCollidePlaneBlock CameraCollidePlane; + + public CameraConstraintPacket() + { + HasVariableBlocks = false; + Type = PacketType.CameraConstraint; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 22; + Header.Reliable = true; + Header.Zerocoded = true; + CameraCollidePlane = new CameraCollidePlaneBlock(); + } + + public CameraConstraintPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + CameraCollidePlane.FromBytes(bytes, ref i); + } + + public CameraConstraintPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + CameraCollidePlane.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += CameraCollidePlane.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + CameraCollidePlane.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ParcelPropertiesPacket : Packet + { + /// + public sealed class ParcelDataBlock : PacketBlock + { + public int RequestResult; + public int SequenceID; + public bool SnapSelection; + public int SelfCount; + public int OtherCount; + public int PublicCount; + public int LocalID; + public UUID OwnerID; + public bool IsGroupOwned; + public uint AuctionID; + public int ClaimDate; + public int ClaimPrice; + public int RentPrice; + public Vector3 AABBMin; + public Vector3 AABBMax; + public byte[] Bitmap; + public int Area; + public byte Status; + public int SimWideMaxPrims; + public int SimWideTotalPrims; + public int MaxPrims; + public int TotalPrims; + public int OwnerPrims; + public int GroupPrims; + public int OtherPrims; + public int SelectedPrims; + public float ParcelPrimBonus; + public int OtherCleanTime; + public uint ParcelFlags; + public int SalePrice; + public byte[] Name; + public byte[] Desc; + public byte[] MusicURL; + public byte[] MediaURL; + public UUID MediaID; + public byte MediaAutoScale; + public UUID GroupID; + public int PassPrice; + public float PassHours; + public byte Category; + public UUID AuthBuyerID; + public UUID SnapshotID; + public Vector3 UserLocation; + public Vector3 UserLookAt; + public byte LandingType; + public bool RegionPushOverride; + public bool RegionDenyAnonymous; + public bool RegionDenyIdentified; + public bool RegionDenyTransacted; + + public override int Length + { + get + { + int length = 244; + if (Bitmap != null) { length += Bitmap.Length; } + if (Name != null) { length += Name.Length; } + if (Desc != null) { length += Desc.Length; } + if (MusicURL != null) { length += MusicURL.Length; } + if (MediaURL != null) { length += MediaURL.Length; } + return length; + } + } + + public ParcelDataBlock() { } + public ParcelDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RequestResult = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SequenceID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SnapSelection = (bytes[i++] != 0) ? (bool)true : (bool)false; + SelfCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OtherCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PublicCount = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + LocalID = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerID.FromBytes(bytes, i); i += 16; + IsGroupOwned = (bytes[i++] != 0) ? (bool)true : (bool)false; + AuctionID = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ClaimDate = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ClaimPrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + RentPrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AABBMin.FromBytes(bytes, i); i += 12; + AABBMax.FromBytes(bytes, i); i += 12; + length = (bytes[i++] + (bytes[i++] << 8)); + Bitmap = new byte[length]; + Buffer.BlockCopy(bytes, i, Bitmap, 0, length); i += length; + Area = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + Status = (byte)bytes[i++]; + SimWideMaxPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SimWideTotalPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + MaxPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + TotalPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OwnerPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + GroupPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + OtherPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SelectedPrims = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParcelPrimBonus = Utils.BytesToFloat(bytes, i); i += 4; + OtherCleanTime = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + ParcelFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + SalePrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + length = bytes[i++]; + Name = new byte[length]; + Buffer.BlockCopy(bytes, i, Name, 0, length); i += length; + length = bytes[i++]; + Desc = new byte[length]; + Buffer.BlockCopy(bytes, i, Desc, 0, length); i += length; + length = bytes[i++]; + MusicURL = new byte[length]; + Buffer.BlockCopy(bytes, i, MusicURL, 0, length); i += length; + length = bytes[i++]; + MediaURL = new byte[length]; + Buffer.BlockCopy(bytes, i, MediaURL, 0, length); i += length; + MediaID.FromBytes(bytes, i); i += 16; + MediaAutoScale = (byte)bytes[i++]; + GroupID.FromBytes(bytes, i); i += 16; + PassPrice = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + PassHours = Utils.BytesToFloat(bytes, i); i += 4; + Category = (byte)bytes[i++]; + AuthBuyerID.FromBytes(bytes, i); i += 16; + SnapshotID.FromBytes(bytes, i); i += 16; + UserLocation.FromBytes(bytes, i); i += 12; + UserLookAt.FromBytes(bytes, i); i += 12; + LandingType = (byte)bytes[i++]; + RegionPushOverride = (bytes[i++] != 0) ? (bool)true : (bool)false; + RegionDenyAnonymous = (bytes[i++] != 0) ? (bool)true : (bool)false; + RegionDenyIdentified = (bytes[i++] != 0) ? (bool)true : (bool)false; + RegionDenyTransacted = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.IntToBytes(RequestResult, bytes, i); i += 4; + Utils.IntToBytes(SequenceID, bytes, i); i += 4; + bytes[i++] = (byte)((SnapSelection) ? 1 : 0); + Utils.IntToBytes(SelfCount, bytes, i); i += 4; + Utils.IntToBytes(OtherCount, bytes, i); i += 4; + Utils.IntToBytes(PublicCount, bytes, i); i += 4; + Utils.IntToBytes(LocalID, bytes, i); i += 4; + OwnerID.ToBytes(bytes, i); i += 16; + bytes[i++] = (byte)((IsGroupOwned) ? 1 : 0); + Utils.UIntToBytes(AuctionID, bytes, i); i += 4; + Utils.IntToBytes(ClaimDate, bytes, i); i += 4; + Utils.IntToBytes(ClaimPrice, bytes, i); i += 4; + Utils.IntToBytes(RentPrice, bytes, i); i += 4; + AABBMin.ToBytes(bytes, i); i += 12; + AABBMax.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)(Bitmap.Length % 256); + bytes[i++] = (byte)((Bitmap.Length >> 8) % 256); + Buffer.BlockCopy(Bitmap, 0, bytes, i, Bitmap.Length); i += Bitmap.Length; + Utils.IntToBytes(Area, bytes, i); i += 4; + bytes[i++] = Status; + Utils.IntToBytes(SimWideMaxPrims, bytes, i); i += 4; + Utils.IntToBytes(SimWideTotalPrims, bytes, i); i += 4; + Utils.IntToBytes(MaxPrims, bytes, i); i += 4; + Utils.IntToBytes(TotalPrims, bytes, i); i += 4; + Utils.IntToBytes(OwnerPrims, bytes, i); i += 4; + Utils.IntToBytes(GroupPrims, bytes, i); i += 4; + Utils.IntToBytes(OtherPrims, bytes, i); i += 4; + Utils.IntToBytes(SelectedPrims, bytes, i); i += 4; + Utils.FloatToBytes(ParcelPrimBonus, bytes, i); i += 4; + Utils.IntToBytes(OtherCleanTime, bytes, i); i += 4; + Utils.UIntToBytes(ParcelFlags, bytes, i); i += 4; + Utils.IntToBytes(SalePrice, bytes, i); i += 4; + bytes[i++] = (byte)Name.Length; + Buffer.BlockCopy(Name, 0, bytes, i, Name.Length); i += Name.Length; + bytes[i++] = (byte)Desc.Length; + Buffer.BlockCopy(Desc, 0, bytes, i, Desc.Length); i += Desc.Length; + bytes[i++] = (byte)MusicURL.Length; + Buffer.BlockCopy(MusicURL, 0, bytes, i, MusicURL.Length); i += MusicURL.Length; + bytes[i++] = (byte)MediaURL.Length; + Buffer.BlockCopy(MediaURL, 0, bytes, i, MediaURL.Length); i += MediaURL.Length; + MediaID.ToBytes(bytes, i); i += 16; + bytes[i++] = MediaAutoScale; + GroupID.ToBytes(bytes, i); i += 16; + Utils.IntToBytes(PassPrice, bytes, i); i += 4; + Utils.FloatToBytes(PassHours, bytes, i); i += 4; + bytes[i++] = Category; + AuthBuyerID.ToBytes(bytes, i); i += 16; + SnapshotID.ToBytes(bytes, i); i += 16; + UserLocation.ToBytes(bytes, i); i += 12; + UserLookAt.ToBytes(bytes, i); i += 12; + bytes[i++] = LandingType; + bytes[i++] = (byte)((RegionPushOverride) ? 1 : 0); + bytes[i++] = (byte)((RegionDenyAnonymous) ? 1 : 0); + bytes[i++] = (byte)((RegionDenyIdentified) ? 1 : 0); + bytes[i++] = (byte)((RegionDenyTransacted) ? 1 : 0); + } + + } + + /// + public sealed class AgeVerificationBlockBlock : PacketBlock + { + public bool RegionDenyAgeUnverified; + + public override int Length + { + get + { + return 1; + } + } + + public AgeVerificationBlockBlock() { } + public AgeVerificationBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionDenyAgeUnverified = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)((RegionDenyAgeUnverified) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 7; + length += ParcelData.Length; + length += AgeVerificationBlock.Length; + return length; + } + } + public ParcelDataBlock ParcelData; + public AgeVerificationBlockBlock AgeVerificationBlock; + + public ParcelPropertiesPacket() + { + HasVariableBlocks = false; + Type = PacketType.ParcelProperties; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 23; + Header.Reliable = true; + Header.Zerocoded = true; + ParcelData = new ParcelDataBlock(); + AgeVerificationBlock = new AgeVerificationBlockBlock(); + } + + public ParcelPropertiesPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + ParcelData.FromBytes(bytes, ref i); + AgeVerificationBlock.FromBytes(bytes, ref i); + } + + public ParcelPropertiesPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + ParcelData.FromBytes(bytes, ref i); + AgeVerificationBlock.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += ParcelData.Length; + length += AgeVerificationBlock.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + ParcelData.ToBytes(bytes, ref i); + AgeVerificationBlock.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ChildAgentUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public ulong RegionHandle; + public uint ViewerCircuitCode; + public UUID AgentID; + public UUID SessionID; + public Vector3 AgentPos; + public Vector3 AgentVel; + public Vector3 Center; + public Vector3 Size; + public Vector3 AtAxis; + public Vector3 LeftAxis; + public Vector3 UpAxis; + public bool ChangedGrid; + public float Far; + public float Aspect; + public byte[] Throttles; + public uint LocomotionState; + public Quaternion HeadRotation; + public Quaternion BodyRotation; + public uint ControlFlags; + public float EnergyLevel; + public byte GodLevel; + public bool AlwaysRun; + public UUID PreyAgent; + public byte AgentAccess; + public byte[] AgentTextures; + public UUID ActiveGroupID; + + public override int Length + { + get + { + int length = 211; + if (Throttles != null) { length += Throttles.Length; } + if (AgentTextures != null) { length += AgentTextures.Length; } + return length; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + ViewerCircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + AgentPos.FromBytes(bytes, i); i += 12; + AgentVel.FromBytes(bytes, i); i += 12; + Center.FromBytes(bytes, i); i += 12; + Size.FromBytes(bytes, i); i += 12; + AtAxis.FromBytes(bytes, i); i += 12; + LeftAxis.FromBytes(bytes, i); i += 12; + UpAxis.FromBytes(bytes, i); i += 12; + ChangedGrid = (bytes[i++] != 0) ? (bool)true : (bool)false; + Far = Utils.BytesToFloat(bytes, i); i += 4; + Aspect = Utils.BytesToFloat(bytes, i); i += 4; + length = bytes[i++]; + Throttles = new byte[length]; + Buffer.BlockCopy(bytes, i, Throttles, 0, length); i += length; + LocomotionState = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + HeadRotation.FromBytes(bytes, i, true); i += 12; + BodyRotation.FromBytes(bytes, i, true); i += 12; + ControlFlags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + EnergyLevel = Utils.BytesToFloat(bytes, i); i += 4; + GodLevel = (byte)bytes[i++]; + AlwaysRun = (bytes[i++] != 0) ? (bool)true : (bool)false; + PreyAgent.FromBytes(bytes, i); i += 16; + AgentAccess = (byte)bytes[i++]; + length = (bytes[i++] + (bytes[i++] << 8)); + AgentTextures = new byte[length]; + Buffer.BlockCopy(bytes, i, AgentTextures, 0, length); i += length; + ActiveGroupID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + Utils.UIntToBytes(ViewerCircuitCode, bytes, i); i += 4; + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + AgentPos.ToBytes(bytes, i); i += 12; + AgentVel.ToBytes(bytes, i); i += 12; + Center.ToBytes(bytes, i); i += 12; + Size.ToBytes(bytes, i); i += 12; + AtAxis.ToBytes(bytes, i); i += 12; + LeftAxis.ToBytes(bytes, i); i += 12; + UpAxis.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)((ChangedGrid) ? 1 : 0); + Utils.FloatToBytes(Far, bytes, i); i += 4; + Utils.FloatToBytes(Aspect, bytes, i); i += 4; + bytes[i++] = (byte)Throttles.Length; + Buffer.BlockCopy(Throttles, 0, bytes, i, Throttles.Length); i += Throttles.Length; + Utils.UIntToBytes(LocomotionState, bytes, i); i += 4; + HeadRotation.ToBytes(bytes, i); i += 12; + BodyRotation.ToBytes(bytes, i); i += 12; + Utils.UIntToBytes(ControlFlags, bytes, i); i += 4; + Utils.FloatToBytes(EnergyLevel, bytes, i); i += 4; + bytes[i++] = GodLevel; + bytes[i++] = (byte)((AlwaysRun) ? 1 : 0); + PreyAgent.ToBytes(bytes, i); i += 16; + bytes[i++] = AgentAccess; + bytes[i++] = (byte)(AgentTextures.Length % 256); + bytes[i++] = (byte)((AgentTextures.Length >> 8) % 256); + Buffer.BlockCopy(AgentTextures, 0, bytes, i, AgentTextures.Length); i += AgentTextures.Length; + ActiveGroupID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GroupDataBlock : PacketBlock + { + public UUID GroupID; + public ulong GroupPowers; + public bool AcceptNotices; + + public override int Length + { + get + { + return 25; + } + } + + public GroupDataBlock() { } + public GroupDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GroupID.FromBytes(bytes, i); i += 16; + GroupPowers = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + AcceptNotices = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GroupID.ToBytes(bytes, i); i += 16; + Utils.UInt64ToBytes(GroupPowers, bytes, i); i += 8; + bytes[i++] = (byte)((AcceptNotices) ? 1 : 0); + } + + } + + /// + public sealed class AnimationDataBlock : PacketBlock + { + public UUID Animation; + public UUID ObjectID; + + public override int Length + { + get + { + return 32; + } + } + + public AnimationDataBlock() { } + public AnimationDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Animation.FromBytes(bytes, i); i += 16; + ObjectID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Animation.ToBytes(bytes, i); i += 16; + ObjectID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class GranterBlockBlock : PacketBlock + { + public UUID GranterID; + + public override int Length + { + get + { + return 16; + } + } + + public GranterBlockBlock() { } + public GranterBlockBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + GranterID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + GranterID.ToBytes(bytes, i); i += 16; + } + + } + + /// + public sealed class NVPairDataBlock : PacketBlock + { + public byte[] NVPairs; + + public override int Length + { + get + { + int length = 2; + if (NVPairs != null) { length += NVPairs.Length; } + return length; + } + } + + public NVPairDataBlock() { } + public NVPairDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + int length; + try + { + length = (bytes[i++] + (bytes[i++] << 8)); + NVPairs = new byte[length]; + Buffer.BlockCopy(bytes, i, NVPairs, 0, length); i += length; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = (byte)(NVPairs.Length % 256); + bytes[i++] = (byte)((NVPairs.Length >> 8) % 256); + Buffer.BlockCopy(NVPairs, 0, bytes, i, NVPairs.Length); i += NVPairs.Length; + } + + } + + /// + public sealed class VisualParamBlock : PacketBlock + { + public byte ParamValue; + + public override int Length + { + get + { + return 1; + } + } + + public VisualParamBlock() { } + public VisualParamBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + ParamValue = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = ParamValue; + } + + } + + /// + public sealed class AgentAccessBlock : PacketBlock + { + public byte AgentLegacyAccess; + public byte AgentMaxAccess; + + public override int Length + { + get + { + return 2; + } + } + + public AgentAccessBlock() { } + public AgentAccessBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + AgentLegacyAccess = (byte)bytes[i++]; + AgentMaxAccess = (byte)bytes[i++]; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + bytes[i++] = AgentLegacyAccess; + bytes[i++] = AgentMaxAccess; + } + + } + + /// + public sealed class AgentInfoBlock : PacketBlock + { + public uint Flags; + + public override int Length + { + get + { + return 4; + } + } + + public AgentInfoBlock() { } + public AgentInfoBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + Flags = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UIntToBytes(Flags, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 14; + length += AgentData.Length; + for (int j = 0; j < GroupData.Length; j++) + length += GroupData[j].Length; + for (int j = 0; j < AnimationData.Length; j++) + length += AnimationData[j].Length; + for (int j = 0; j < GranterBlock.Length; j++) + length += GranterBlock[j].Length; + for (int j = 0; j < NVPairData.Length; j++) + length += NVPairData[j].Length; + for (int j = 0; j < VisualParam.Length; j++) + length += VisualParam[j].Length; + for (int j = 0; j < AgentAccess.Length; j++) + length += AgentAccess[j].Length; + for (int j = 0; j < AgentInfo.Length; j++) + length += AgentInfo[j].Length; + return length; + } + } + public AgentDataBlock AgentData; + public GroupDataBlock[] GroupData; + public AnimationDataBlock[] AnimationData; + public GranterBlockBlock[] GranterBlock; + public NVPairDataBlock[] NVPairData; + public VisualParamBlock[] VisualParam; + public AgentAccessBlock[] AgentAccess; + public AgentInfoBlock[] AgentInfo; + + public ChildAgentUpdatePacket() + { + HasVariableBlocks = true; + Type = PacketType.ChildAgentUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 25; + Header.Reliable = true; + Header.Zerocoded = true; + AgentData = new AgentDataBlock(); + GroupData = null; + AnimationData = null; + GranterBlock = null; + NVPairData = null; + VisualParam = null; + AgentAccess = null; + AgentInfo = null; + } + + public ChildAgentUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != -1) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AnimationData == null || AnimationData.Length != -1) { + AnimationData = new AnimationDataBlock[count]; + for(int j = 0; j < count; j++) + { AnimationData[j] = new AnimationDataBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(GranterBlock == null || GranterBlock.Length != -1) { + GranterBlock = new GranterBlockBlock[count]; + for(int j = 0; j < count; j++) + { GranterBlock[j] = new GranterBlockBlock(); } + } + for (int j = 0; j < count; j++) + { GranterBlock[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(NVPairData == null || NVPairData.Length != -1) { + NVPairData = new NVPairDataBlock[count]; + for(int j = 0; j < count; j++) + { NVPairData[j] = new NVPairDataBlock(); } + } + for (int j = 0; j < count; j++) + { NVPairData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(VisualParam == null || VisualParam.Length != -1) { + VisualParam = new VisualParamBlock[count]; + for(int j = 0; j < count; j++) + { VisualParam[j] = new VisualParamBlock(); } + } + for (int j = 0; j < count; j++) + { VisualParam[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AgentAccess == null || AgentAccess.Length != -1) { + AgentAccess = new AgentAccessBlock[count]; + for(int j = 0; j < count; j++) + { AgentAccess[j] = new AgentAccessBlock(); } + } + for (int j = 0; j < count; j++) + { AgentAccess[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AgentInfo == null || AgentInfo.Length != -1) { + AgentInfo = new AgentInfoBlock[count]; + for(int j = 0; j < count; j++) + { AgentInfo[j] = new AgentInfoBlock(); } + } + for (int j = 0; j < count; j++) + { AgentInfo[j].FromBytes(bytes, ref i); } + } + + public ChildAgentUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + int count = (int)bytes[i++]; + if(GroupData == null || GroupData.Length != count) { + GroupData = new GroupDataBlock[count]; + for(int j = 0; j < count; j++) + { GroupData[j] = new GroupDataBlock(); } + } + for (int j = 0; j < count; j++) + { GroupData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AnimationData == null || AnimationData.Length != count) { + AnimationData = new AnimationDataBlock[count]; + for(int j = 0; j < count; j++) + { AnimationData[j] = new AnimationDataBlock(); } + } + for (int j = 0; j < count; j++) + { AnimationData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(GranterBlock == null || GranterBlock.Length != count) { + GranterBlock = new GranterBlockBlock[count]; + for(int j = 0; j < count; j++) + { GranterBlock[j] = new GranterBlockBlock(); } + } + for (int j = 0; j < count; j++) + { GranterBlock[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(NVPairData == null || NVPairData.Length != count) { + NVPairData = new NVPairDataBlock[count]; + for(int j = 0; j < count; j++) + { NVPairData[j] = new NVPairDataBlock(); } + } + for (int j = 0; j < count; j++) + { NVPairData[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(VisualParam == null || VisualParam.Length != count) { + VisualParam = new VisualParamBlock[count]; + for(int j = 0; j < count; j++) + { VisualParam[j] = new VisualParamBlock(); } + } + for (int j = 0; j < count; j++) + { VisualParam[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AgentAccess == null || AgentAccess.Length != count) { + AgentAccess = new AgentAccessBlock[count]; + for(int j = 0; j < count; j++) + { AgentAccess[j] = new AgentAccessBlock(); } + } + for (int j = 0; j < count; j++) + { AgentAccess[j].FromBytes(bytes, ref i); } + count = (int)bytes[i++]; + if(AgentInfo == null || AgentInfo.Length != count) { + AgentInfo = new AgentInfoBlock[count]; + for(int j = 0; j < count; j++) + { AgentInfo[j] = new AgentInfoBlock(); } + } + for (int j = 0; j < count; j++) + { AgentInfo[j].FromBytes(bytes, ref i); } + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + length++; + for (int j = 0; j < GroupData.Length; j++) { length += GroupData[j].Length; } + length++; + for (int j = 0; j < AnimationData.Length; j++) { length += AnimationData[j].Length; } + length++; + for (int j = 0; j < GranterBlock.Length; j++) { length += GranterBlock[j].Length; } + length++; + for (int j = 0; j < NVPairData.Length; j++) { length += NVPairData[j].Length; } + length++; + for (int j = 0; j < VisualParam.Length; j++) { length += VisualParam[j].Length; } + length++; + for (int j = 0; j < AgentAccess.Length; j++) { length += AgentAccess[j].Length; } + length++; + for (int j = 0; j < AgentInfo.Length; j++) { length += AgentInfo[j].Length; } + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + bytes[i++] = (byte)GroupData.Length; + for (int j = 0; j < GroupData.Length; j++) { GroupData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)AnimationData.Length; + for (int j = 0; j < AnimationData.Length; j++) { AnimationData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)GranterBlock.Length; + for (int j = 0; j < GranterBlock.Length; j++) { GranterBlock[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)NVPairData.Length; + for (int j = 0; j < NVPairData.Length; j++) { NVPairData[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)VisualParam.Length; + for (int j = 0; j < VisualParam.Length; j++) { VisualParam[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)AgentAccess.Length; + for (int j = 0; j < AgentAccess.Length; j++) { AgentAccess[j].ToBytes(bytes, ref i); } + bytes[i++] = (byte)AgentInfo.Length; + for (int j = 0; j < AgentInfo.Length; j++) { AgentInfo[j].ToBytes(bytes, ref i); } + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + System.Collections.Generic.List packets = new System.Collections.Generic.List(); + int i = 0; + int fixedLength = 7; + + byte[] ackBytes = null; + int acksLength = 0; + if (Header.AckList != null && Header.AckList.Length > 0) { + Header.AppendedAcks = true; + ackBytes = new byte[Header.AckList.Length * 4 + 1]; + Header.AcksToBytes(ackBytes, ref acksLength); + } + + fixedLength += AgentData.Length; + byte[] fixedBytes = new byte[fixedLength]; + Header.ToBytes(fixedBytes, ref i); + AgentData.ToBytes(fixedBytes, ref i); + fixedLength += 7; + + int GroupDataStart = 0; + int AnimationDataStart = 0; + int GranterBlockStart = 0; + int NVPairDataStart = 0; + int VisualParamStart = 0; + int AgentAccessStart = 0; + int AgentInfoStart = 0; + do + { + int variableLength = 0; + int GroupDataCount = 0; + int AnimationDataCount = 0; + int GranterBlockCount = 0; + int NVPairDataCount = 0; + int VisualParamCount = 0; + int AgentAccessCount = 0; + int AgentInfoCount = 0; + + i = GroupDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < GroupData.Length) { + int blockLength = GroupData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++GroupDataCount; + } + else { break; } + ++i; + } + + i = AnimationDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AnimationData.Length) { + int blockLength = AnimationData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AnimationDataCount; + } + else { break; } + ++i; + } + + i = GranterBlockStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < GranterBlock.Length) { + int blockLength = GranterBlock[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++GranterBlockCount; + } + else { break; } + ++i; + } + + i = NVPairDataStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < NVPairData.Length) { + int blockLength = NVPairData[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++NVPairDataCount; + } + else { break; } + ++i; + } + + i = VisualParamStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < VisualParam.Length) { + int blockLength = VisualParam[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++VisualParamCount; + } + else { break; } + ++i; + } + + i = AgentAccessStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AgentAccess.Length) { + int blockLength = AgentAccess[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AgentAccessCount; + } + else { break; } + ++i; + } + + i = AgentInfoStart; + while (fixedLength + variableLength + acksLength < Packet.MTU && i < AgentInfo.Length) { + int blockLength = AgentInfo[i].Length; + if (fixedLength + variableLength + blockLength + acksLength <= MTU) { + variableLength += blockLength; + ++AgentInfoCount; + } + else { break; } + ++i; + } + + byte[] packet = new byte[fixedLength + variableLength + acksLength]; + int length = fixedBytes.Length; + Buffer.BlockCopy(fixedBytes, 0, packet, 0, length); + if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); } + + packet[length++] = (byte)GroupDataCount; + for (i = GroupDataStart; i < GroupDataStart + GroupDataCount; i++) { GroupData[i].ToBytes(packet, ref length); } + GroupDataStart += GroupDataCount; + + packet[length++] = (byte)AnimationDataCount; + for (i = AnimationDataStart; i < AnimationDataStart + AnimationDataCount; i++) { AnimationData[i].ToBytes(packet, ref length); } + AnimationDataStart += AnimationDataCount; + + packet[length++] = (byte)GranterBlockCount; + for (i = GranterBlockStart; i < GranterBlockStart + GranterBlockCount; i++) { GranterBlock[i].ToBytes(packet, ref length); } + GranterBlockStart += GranterBlockCount; + + packet[length++] = (byte)NVPairDataCount; + for (i = NVPairDataStart; i < NVPairDataStart + NVPairDataCount; i++) { NVPairData[i].ToBytes(packet, ref length); } + NVPairDataStart += NVPairDataCount; + + packet[length++] = (byte)VisualParamCount; + for (i = VisualParamStart; i < VisualParamStart + VisualParamCount; i++) { VisualParam[i].ToBytes(packet, ref length); } + VisualParamStart += VisualParamCount; + + packet[length++] = (byte)AgentAccessCount; + for (i = AgentAccessStart; i < AgentAccessStart + AgentAccessCount; i++) { AgentAccess[i].ToBytes(packet, ref length); } + AgentAccessStart += AgentAccessCount; + + packet[length++] = (byte)AgentInfoCount; + for (i = AgentInfoStart; i < AgentInfoStart + AgentInfoCount; i++) { AgentInfo[i].ToBytes(packet, ref length); } + AgentInfoStart += AgentInfoCount; + + if (acksLength > 0) { + Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength); + acksLength = 0; + } + + packets.Add(packet); + } while ( + GroupDataStart < GroupData.Length || + AnimationDataStart < AnimationData.Length || + GranterBlockStart < GranterBlock.Length || + NVPairDataStart < NVPairData.Length || + VisualParamStart < VisualParam.Length || + AgentAccessStart < AgentAccess.Length || + AgentInfoStart < AgentInfo.Length); + + return packets.ToArray(); + } + } + + /// + public sealed class ChildAgentAlivePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public ulong RegionHandle; + public uint ViewerCircuitCode; + public UUID AgentID; + public UUID SessionID; + + public override int Length + { + get + { + return 44; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + ViewerCircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + Utils.UIntToBytes(ViewerCircuitCode, bytes, i); i += 4; + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + } + + } + + public override int Length + { + get + { + int length = 7; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public ChildAgentAlivePacket() + { + HasVariableBlocks = false; + Type = PacketType.ChildAgentAlive; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 26; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public ChildAgentAlivePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public ChildAgentAlivePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class ChildAgentPositionUpdatePacket : Packet + { + /// + public sealed class AgentDataBlock : PacketBlock + { + public ulong RegionHandle; + public uint ViewerCircuitCode; + public UUID AgentID; + public UUID SessionID; + public Vector3 AgentPos; + public Vector3 AgentVel; + public Vector3 Center; + public Vector3 Size; + public Vector3 AtAxis; + public Vector3 LeftAxis; + public Vector3 UpAxis; + public bool ChangedGrid; + + public override int Length + { + get + { + return 129; + } + } + + public AgentDataBlock() { } + public AgentDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + RegionHandle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + ViewerCircuitCode = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + AgentID.FromBytes(bytes, i); i += 16; + SessionID.FromBytes(bytes, i); i += 16; + AgentPos.FromBytes(bytes, i); i += 12; + AgentVel.FromBytes(bytes, i); i += 12; + Center.FromBytes(bytes, i); i += 12; + Size.FromBytes(bytes, i); i += 12; + AtAxis.FromBytes(bytes, i); i += 12; + LeftAxis.FromBytes(bytes, i); i += 12; + UpAxis.FromBytes(bytes, i); i += 12; + ChangedGrid = (bytes[i++] != 0) ? (bool)true : (bool)false; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + Utils.UInt64ToBytes(RegionHandle, bytes, i); i += 8; + Utils.UIntToBytes(ViewerCircuitCode, bytes, i); i += 4; + AgentID.ToBytes(bytes, i); i += 16; + SessionID.ToBytes(bytes, i); i += 16; + AgentPos.ToBytes(bytes, i); i += 12; + AgentVel.ToBytes(bytes, i); i += 12; + Center.ToBytes(bytes, i); i += 12; + Size.ToBytes(bytes, i); i += 12; + AtAxis.ToBytes(bytes, i); i += 12; + LeftAxis.ToBytes(bytes, i); i += 12; + UpAxis.ToBytes(bytes, i); i += 12; + bytes[i++] = (byte)((ChangedGrid) ? 1 : 0); + } + + } + + public override int Length + { + get + { + int length = 7; + length += AgentData.Length; + return length; + } + } + public AgentDataBlock AgentData; + + public ChildAgentPositionUpdatePacket() + { + HasVariableBlocks = false; + Type = PacketType.ChildAgentPositionUpdate; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 27; + Header.Reliable = true; + AgentData = new AgentDataBlock(); + } + + public ChildAgentPositionUpdatePacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + AgentData.FromBytes(bytes, ref i); + } + + public ChildAgentPositionUpdatePacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + AgentData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += AgentData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + AgentData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + + /// + public sealed class SoundTriggerPacket : Packet + { + /// + public sealed class SoundDataBlock : PacketBlock + { + public UUID SoundID; + public UUID OwnerID; + public UUID ObjectID; + public UUID ParentID; + public ulong Handle; + public Vector3 Position; + public float Gain; + + public override int Length + { + get + { + return 88; + } + } + + public SoundDataBlock() { } + public SoundDataBlock(byte[] bytes, ref int i) + { + FromBytes(bytes, ref i); + } + + public override void FromBytes(byte[] bytes, ref int i) + { + try + { + SoundID.FromBytes(bytes, i); i += 16; + OwnerID.FromBytes(bytes, i); i += 16; + ObjectID.FromBytes(bytes, i); i += 16; + ParentID.FromBytes(bytes, i); i += 16; + Handle = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + ((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + ((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + ((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56)); + Position.FromBytes(bytes, i); i += 12; + Gain = Utils.BytesToFloat(bytes, i); i += 4; + } + catch (Exception) + { + throw new MalformedDataException(); + } + } + + public override void ToBytes(byte[] bytes, ref int i) + { + SoundID.ToBytes(bytes, i); i += 16; + OwnerID.ToBytes(bytes, i); i += 16; + ObjectID.ToBytes(bytes, i); i += 16; + ParentID.ToBytes(bytes, i); i += 16; + Utils.UInt64ToBytes(Handle, bytes, i); i += 8; + Position.ToBytes(bytes, i); i += 12; + Utils.FloatToBytes(Gain, bytes, i); i += 4; + } + + } + + public override int Length + { + get + { + int length = 7; + length += SoundData.Length; + return length; + } + } + public SoundDataBlock SoundData; + + public SoundTriggerPacket() + { + HasVariableBlocks = false; + Type = PacketType.SoundTrigger; + Header = new Header(); + Header.Frequency = PacketFrequency.High; + Header.ID = 29; + Header.Reliable = true; + SoundData = new SoundDataBlock(); + } + + public SoundTriggerPacket(byte[] bytes, ref int i) : this() + { + int packetEnd = bytes.Length - 1; + FromBytes(bytes, ref i, ref packetEnd, null); + } + + override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + Header.FromBytes(bytes, ref i, ref packetEnd); + if (Header.Zerocoded && zeroBuffer != null) + { + packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1; + bytes = zeroBuffer; + } + SoundData.FromBytes(bytes, ref i); + } + + public SoundTriggerPacket(Header head, byte[] bytes, ref int i): this() + { + int packetEnd = bytes.Length - 1; + FromBytes(head, bytes, ref i, ref packetEnd); + } + + override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd) + { + Header = header; + SoundData.FromBytes(bytes, ref i); + } + + public override byte[] ToBytes() + { + int length = 7; + length += SoundData.Length; + if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; } + byte[] bytes = new byte[length]; + int i = 0; + Header.ToBytes(bytes, ref i); + SoundData.ToBytes(bytes, ref i); + if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); } + return bytes; + } + + public override byte[][] ToBytesMultiple() + { + return new byte[][] { ToBytes() }; + } + } + +} diff --git a/OpenMetaverse/_VisualParam_.cs b/OpenMetaverse/_VisualParam_.cs new file mode 100644 index 0000000..4114541 --- /dev/null +++ b/OpenMetaverse/_VisualParam_.cs @@ -0,0 +1,625 @@ +using System; +using System.Collections.Generic; + +namespace OpenMetaverse +{ + /// + /// Operation to apply when applying color to texture + /// + public enum VisualColorOperation + { + Add, + Blend, + Multiply + } + + /// + /// Information needed to translate visual param value to RGBA color + /// + public struct VisualColorParam + { + public VisualColorOperation Operation; + public Color4[] Colors; + + /// + /// Construct VisualColorParam + /// + /// Operation to apply when applying color to texture + /// Colors + public VisualColorParam(VisualColorOperation operation, Color4[] colors) + { + Operation = operation; + Colors = colors; + } + } + + /// + /// Represents alpha blending and bump infor for a visual parameter + /// such as sleive length + /// + public struct VisualAlphaParam + { + /// Stregth of the alpha to apply + public float Domain; + + /// File containing the alpha channel + public string TGAFile; + + /// Skip blending if parameter value is 0 + public bool SkipIfZero; + + /// Use miltiply insted of alpha blending + public bool MultiplyBlend; + + /// + /// Create new alhpa information for a visual param + /// + /// Stregth of the alpha to apply + /// File containing the alpha channel + /// Skip blending if parameter value is 0 + /// Use miltiply insted of alpha blending + public VisualAlphaParam(float domain, string tgaFile, bool skipIfZero, bool multiplyBlend) + { + Domain = domain; + TGAFile = tgaFile; + SkipIfZero = skipIfZero; + MultiplyBlend = multiplyBlend; + } + } + /// + /// A single visual characteristic of an avatar mesh, such as eyebrow height + /// + public struct VisualParam + { + /// Index of this visual param + public int ParamID; + /// Internal name + public string Name; + /// Group ID this parameter belongs to + public int Group; + /// Name of the wearable this parameter belongs to + public string Wearable; + /// Displayable label of this characteristic + public string Label; + /// Displayable label for the minimum value of this characteristic + public string LabelMin; + /// Displayable label for the maximum value of this characteristic + public string LabelMax; + /// Default value + public float DefaultValue; + /// Minimum value + public float MinValue; + /// Maximum value + public float MaxValue; + /// Is this param used for creation of bump layer? + public bool IsBumpAttribute; + /// Alpha blending/bump info + public VisualAlphaParam? AlphaParams; + /// Color information + public VisualColorParam? ColorParams; + /// Array of param IDs that are drivers for this parameter + public int[] Drivers; + /// + /// Set all the values through the constructor + /// + /// Index of this visual param + /// Internal name + /// + /// + /// Displayable label of this characteristic + /// Displayable label for the minimum value of this characteristic + /// Displayable label for the maximum value of this characteristic + /// Default value + /// Minimum value + /// Maximum value + /// Is this param used for creation of bump layer? + /// Array of param IDs that are drivers for this parameter + /// Alpha blending/bump info + /// Color information + public VisualParam(int paramID, string name, int group, string wearable, string label, string labelMin, string labelMax, float def, float min, float max, bool isBumpAttribute, int[] drivers, VisualAlphaParam? alpha, VisualColorParam? colorParams) + { + ParamID = paramID; + Name = name; + Group = group; + Wearable = wearable; + Label = label; + LabelMin = labelMin; + LabelMax = labelMax; + DefaultValue = def; + MaxValue = max; + MinValue = min; + IsBumpAttribute = isBumpAttribute; + Drivers = drivers; + AlphaParams = alpha; + ColorParams = colorParams; + } + } + + /// + /// Holds the Params array of all the avatar appearance parameters + /// + public static class VisualParams + { + public static SortedList Params = new SortedList(); + + public static VisualParam Find(string name, string wearable) + { + foreach (KeyValuePair param in Params) + if (param.Value.Name == name && param.Value.Wearable == wearable) + return param.Value; + + return new VisualParam(); + } + + static VisualParams() + { + Params[1] = new VisualParam(1, "Big_Brow", 0, "shape", "Brow Size", "Small", "Large", -0.3f, -0.3f, 2f, false, null, null, null); + Params[2] = new VisualParam(2, "Nose_Big_Out", 0, "shape", "Nose Size", "Small", "Large", -0.8f, -0.8f, 2.5f, false, null, null, null); + Params[4] = new VisualParam(4, "Broad_Nostrils", 0, "shape", "Nostril Width", "Narrow", "Broad", -0.5f, -0.5f, 1f, false, null, null, null); + Params[5] = new VisualParam(5, "Cleft_Chin", 0, "shape", "Chin Cleft", "Round", "Cleft", -0.1f, -0.1f, 1f, false, null, null, null); + Params[6] = new VisualParam(6, "Bulbous_Nose_Tip", 0, "shape", "Nose Tip Shape", "Pointy", "Bulbous", -0.3f, -0.3f, 1f, false, null, null, null); + Params[7] = new VisualParam(7, "Weak_Chin", 0, "shape", "Chin Angle", "Chin Out", "Chin In", -0.5f, -0.5f, 0.5f, false, null, null, null); + Params[8] = new VisualParam(8, "Double_Chin", 0, "shape", "Chin-Neck", "Tight Chin", "Double Chin", -0.5f, -0.5f, 1.5f, false, null, null, null); + Params[10] = new VisualParam(10, "Sunken_Cheeks", 0, "shape", "Lower Cheeks", "Well-Fed", "Sunken", -1.5f, -1.5f, 3f, false, null, null, null); + Params[11] = new VisualParam(11, "Noble_Nose_Bridge", 0, "shape", "Upper Bridge", "Low", "High", -0.5f, -0.5f, 1.5f, false, null, null, null); + Params[12] = new VisualParam(12, "Jowls", 0, "shape", String.Empty, "Less", "More", -0.5f, -0.5f, 2.5f, false, null, null, null); + Params[13] = new VisualParam(13, "Cleft_Chin_Upper", 0, "shape", "Upper Chin Cleft", "Round", "Cleft", 0f, 0f, 1.5f, false, null, null, null); + Params[14] = new VisualParam(14, "High_Cheek_Bones", 0, "shape", "Cheek Bones", "Low", "High", -0.5f, -0.5f, 1f, false, null, null, null); + Params[15] = new VisualParam(15, "Ears_Out", 0, "shape", "Ear Angle", "In", "Out", -0.5f, -0.5f, 1.5f, false, null, null, null); + Params[16] = new VisualParam(16, "Pointy_Eyebrows", 0, "hair", "Eyebrow Points", "Smooth", "Pointy", -0.5f, -0.5f, 3f, false, new int[] { 870 }, null, null); + Params[17] = new VisualParam(17, "Square_Jaw", 0, "shape", "Jaw Shape", "Pointy", "Square", -0.5f, -0.5f, 1f, false, null, null, null); + Params[18] = new VisualParam(18, "Puffy_Upper_Cheeks", 0, "shape", "Upper Cheeks", "Thin", "Puffy", -1.5f, -1.5f, 2.5f, false, null, null, null); + Params[19] = new VisualParam(19, "Upturned_Nose_Tip", 0, "shape", "Nose Tip Angle", "Downturned", "Upturned", -1.5f, -1.5f, 1f, false, null, null, null); + Params[20] = new VisualParam(20, "Bulbous_Nose", 0, "shape", "Nose Thickness", "Thin Nose", "Bulbous Nose", -0.5f, -0.5f, 1.5f, false, null, null, null); + Params[21] = new VisualParam(21, "Upper_Eyelid_Fold", 0, "shape", "Upper Eyelid Fold", "Uncreased", "Creased", -0.2f, -0.2f, 1.3f, false, null, null, null); + Params[22] = new VisualParam(22, "Attached_Earlobes", 0, "shape", "Attached Earlobes", "Unattached", "Attached", 0f, 0f, 1f, false, null, null, null); + Params[23] = new VisualParam(23, "Baggy_Eyes", 0, "shape", "Eye Bags", "Smooth", "Baggy", -0.5f, -0.5f, 1.5f, false, null, null, null); + Params[24] = new VisualParam(24, "Wide_Eyes", 0, "shape", "Eye Opening", "Narrow", "Wide", -1.5f, -1.5f, 2f, false, null, null, null); + Params[25] = new VisualParam(25, "Wide_Lip_Cleft", 0, "shape", "Lip Cleft", "Narrow", "Wide", -0.8f, -0.8f, 1.5f, false, null, null, null); + Params[26] = new VisualParam(26, "Lips_Thin", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, 0f, 0.7f, false, null, null, null); + Params[27] = new VisualParam(27, "Wide_Nose_Bridge", 0, "shape", "Bridge Width", "Narrow", "Wide", -1.3f, -1.3f, 1.2f, false, null, null, null); + Params[28] = new VisualParam(28, "Lips_Fat", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, 0f, 2f, false, null, null, null); + Params[29] = new VisualParam(29, "Wide_Upper_Lip", 1, "shape", String.Empty, String.Empty, String.Empty, -0.7f, -0.7f, 1.3f, false, null, null, null); + Params[30] = new VisualParam(30, "Wide_Lower_Lip", 1, "shape", String.Empty, String.Empty, String.Empty, -0.7f, -0.7f, 1.3f, false, null, null, null); + Params[31] = new VisualParam(31, "Arced_Eyebrows", 0, "hair", "Eyebrow Arc", "Flat", "Arced", 0.5f, 0f, 2f, false, new int[] { 872 }, null, null); + Params[33] = new VisualParam(33, "Height", 0, "shape", "Height", "Short", "Tall", -2.3f, -2.3f, 2f, false, null, null, null); + Params[34] = new VisualParam(34, "Thickness", 0, "shape", "Body Thickness", "Body Thin", "Body Thick", -0.7f, -0.7f, 1.5f, false, null, null, null); + Params[35] = new VisualParam(35, "Big_Ears", 0, "shape", "Ear Size", "Small", "Large", -1f, -1f, 2f, false, null, null, null); + Params[36] = new VisualParam(36, "Shoulders", 0, "shape", "Shoulders", "Narrow", "Broad", -0.5f, -1.8f, 1.4f, false, null, null, null); + Params[37] = new VisualParam(37, "Hip Width", 0, "shape", "Hip Width", "Narrow", "Wide", -3.2f, -3.2f, 2.8f, false, null, null, null); + Params[38] = new VisualParam(38, "Torso Length", 0, "shape", String.Empty, "Short Torso", "Long Torso", -1f, -1f, 1f, false, null, null, null); + Params[40] = new VisualParam(40, "Male_Head", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[80] = new VisualParam(80, "male", 0, "shape", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, new int[] { 32, 153, 40, 100, 857 }, null, null); + Params[93] = new VisualParam(93, "Glove Length", 0, "gloves", String.Empty, "Short", "Long", 0.8f, 0.01f, 1f, false, new int[] { 1058, 1059 }, null, null); + Params[98] = new VisualParam(98, "Eye Lightness", 0, "eyes", String.Empty, "Darker", "Lighter", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 0), new Color4(255, 255, 255, 255) })); + Params[99] = new VisualParam(99, "Eye Color", 0, "eyes", String.Empty, "Natural", "Unnatural", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(50, 25, 5, 255), new Color4(109, 55, 15, 255), new Color4(150, 93, 49, 255), new Color4(152, 118, 25, 255), new Color4(95, 179, 107, 255), new Color4(87, 192, 191, 255), new Color4(95, 172, 179, 255), new Color4(128, 128, 128, 255), new Color4(0, 0, 0, 255), new Color4(255, 255, 0, 255), new Color4(0, 255, 0, 255), new Color4(0, 255, 255, 255), new Color4(0, 0, 255, 255), new Color4(255, 0, 255, 255), new Color4(255, 0, 0, 255) })); + Params[100] = new VisualParam(100, "Male_Torso", 1, "shape", String.Empty, "Male_Torso", String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[104] = new VisualParam(104, "Big_Belly_Torso", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[105] = new VisualParam(105, "Breast Size", 0, "shape", String.Empty, "Small", "Large", 0.5f, 0f, 1f, false, new int[] { 843, 627, 626 }, null, null); + Params[106] = new VisualParam(106, "Muscular_Torso", 1, "shape", "Torso Muscles", "Regular", "Muscular", 0f, 0f, 1.4f, false, null, null, null); + Params[108] = new VisualParam(108, "Rainbow Color", 0, "skin", String.Empty, "None", "Wild", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 255, 255), new Color4(255, 0, 0, 255), new Color4(255, 255, 0, 255), new Color4(0, 255, 0, 255), new Color4(0, 255, 255, 255), new Color4(0, 0, 255, 255), new Color4(255, 0, 255, 255) })); + Params[110] = new VisualParam(110, "Red Skin", 0, "skin", "Ruddiness", "Pale", "Ruddy", 0f, 0f, 0.1f, false, null, null, new VisualColorParam(VisualColorOperation.Blend, new Color4[] { new Color4(218, 41, 37, 255) })); + Params[111] = new VisualParam(111, "Pigment", 0, "skin", String.Empty, "Light", "Dark", 0.5f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(252, 215, 200, 255), new Color4(240, 177, 112, 255), new Color4(90, 40, 16, 255), new Color4(29, 9, 6, 255) })); + Params[112] = new VisualParam(112, "Rainbow Color", 0, "hair", String.Empty, "None", "Wild", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 255, 255), new Color4(255, 0, 0, 255), new Color4(255, 255, 0, 255), new Color4(0, 255, 0, 255), new Color4(0, 255, 255, 255), new Color4(0, 0, 255, 255), new Color4(255, 0, 255, 255) })); + Params[113] = new VisualParam(113, "Red Hair", 0, "hair", String.Empty, "No Red", "Very Red", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(118, 47, 19, 255) })); + Params[114] = new VisualParam(114, "Blonde Hair", 0, "hair", String.Empty, "Black", "Blonde", 0.5f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(22, 6, 6, 255), new Color4(29, 9, 6, 255), new Color4(45, 21, 11, 255), new Color4(78, 39, 11, 255), new Color4(90, 53, 16, 255), new Color4(136, 92, 21, 255), new Color4(150, 106, 33, 255), new Color4(198, 156, 74, 255), new Color4(233, 192, 103, 255), new Color4(238, 205, 136, 255) })); + Params[115] = new VisualParam(115, "White Hair", 0, "hair", String.Empty, "No White", "All White", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 255, 255, 255) })); + Params[116] = new VisualParam(116, "Rosy Complexion", 0, "skin", String.Empty, "Less Rosy", "More Rosy", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(198, 71, 71, 0), new Color4(198, 71, 71, 255) })); + Params[117] = new VisualParam(117, "Lip Pinkness", 0, "skin", String.Empty, "Darker", "Pinker", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(220, 115, 115, 0), new Color4(220, 115, 115, 128) })); + Params[119] = new VisualParam(119, "Eyebrow Size", 0, "hair", String.Empty, "Thin Eyebrows", "Bushy Eyebrows", 0.5f, 0f, 1f, false, new int[] { 1000, 1001 }, null, null); + Params[130] = new VisualParam(130, "Front Fringe", 0, "hair", String.Empty, "Short", "Long", 0.45f, 0f, 1f, false, new int[] { 144, 145 }, null, null); + Params[131] = new VisualParam(131, "Side Fringe", 0, "hair", String.Empty, "Short", "Long", 0.5f, 0f, 1f, false, new int[] { 146, 147 }, null, null); + Params[132] = new VisualParam(132, "Back Fringe", 0, "hair", String.Empty, "Short", "Long", 0.39f, 0f, 1f, false, new int[] { 148, 149 }, null, null); + Params[133] = new VisualParam(133, "Hair Front", 0, "hair", String.Empty, "Short", "Long", 0.25f, 0f, 1f, false, new int[] { 172, 171 }, null, null); + Params[134] = new VisualParam(134, "Hair Sides", 0, "hair", String.Empty, "Short", "Long", 0.5f, 0f, 1f, false, new int[] { 174, 173 }, null, null); + Params[135] = new VisualParam(135, "Hair Back", 0, "hair", String.Empty, "Short", "Long", 0.55f, 0f, 1f, false, new int[] { 176, 175 }, null, null); + Params[136] = new VisualParam(136, "Hair Sweep", 0, "hair", String.Empty, "Sweep Forward", "Sweep Back", 0.5f, 0f, 1f, false, new int[] { 179, 178 }, null, null); + Params[137] = new VisualParam(137, "Hair Tilt", 0, "hair", String.Empty, "Left", "Right", 0.5f, 0f, 1f, false, new int[] { 190, 191 }, null, null); + Params[140] = new VisualParam(140, "Hair_Part_Middle", 0, "hair", "Middle Part", "No Part", "Part", 0f, 0f, 2f, false, null, null, null); + Params[141] = new VisualParam(141, "Hair_Part_Right", 0, "hair", "Right Part", "No Part", "Part", 0f, 0f, 2f, false, null, null, null); + Params[142] = new VisualParam(142, "Hair_Part_Left", 0, "hair", "Left Part", "No Part", "Part", 0f, 0f, 2f, false, null, null, null); + Params[143] = new VisualParam(143, "Hair_Sides_Full", 0, "hair", "Full Hair Sides", "Mowhawk", "Full Sides", 0.125f, -4f, 1.5f, false, null, null, null); + Params[144] = new VisualParam(144, "Bangs_Front_Up", 1, "hair", "Front Bangs Up", "Bangs", "Bangs Up", 0f, 0f, 1f, false, null, null, null); + Params[145] = new VisualParam(145, "Bangs_Front_Down", 1, "hair", "Front Bangs Down", "Bangs", "Bangs Down", 0f, 0f, 5f, false, null, null, null); + Params[146] = new VisualParam(146, "Bangs_Sides_Up", 1, "hair", "Side Bangs Up", "Side Bangs", "Side Bangs Up", 0f, 0f, 1f, false, null, null, null); + Params[147] = new VisualParam(147, "Bangs_Sides_Down", 1, "hair", "Side Bangs Down", "Side Bangs", "Side Bangs Down", 0f, 0f, 2f, false, null, null, null); + Params[148] = new VisualParam(148, "Bangs_Back_Up", 1, "hair", "Back Bangs Up", "Back Bangs", "Back Bangs Up", 0f, 0f, 1f, false, null, null, null); + Params[149] = new VisualParam(149, "Bangs_Back_Down", 1, "hair", "Back Bangs Down", "Back Bangs", "Back Bangs Down", 0f, 0f, 2f, false, null, null, null); + Params[150] = new VisualParam(150, "Body Definition", 0, "skin", String.Empty, "Less", "More", 0f, 0f, 1f, false, new int[] { 125, 126, 160, 161, 874, 878 }, null, null); + Params[151] = new VisualParam(151, "Big_Butt_Legs", 1, "shape", "Butt Size", "Regular", "Large", 0f, 0f, 1f, false, null, null, null); + Params[152] = new VisualParam(152, "Muscular_Legs", 1, "shape", "Leg Muscles", "Regular Muscles", "More Muscles", 0f, 0f, 1.5f, false, null, null, null); + Params[153] = new VisualParam(153, "Male_Legs", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[155] = new VisualParam(155, "Lip Width", 0, "shape", "Lip Width", "Narrow Lips", "Wide Lips", 0f, -0.9f, 1.3f, false, new int[] { 29, 30 }, null, null); + Params[156] = new VisualParam(156, "Big_Belly_Legs", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[157] = new VisualParam(157, "Belly Size", 0, "shape", String.Empty, "Small", "Big", 0f, 0f, 1f, false, new int[] { 104, 156, 849 }, null, null); + Params[162] = new VisualParam(162, "Facial Definition", 0, "skin", String.Empty, "Less", "More", 0f, 0f, 1f, false, new int[] { 158, 159, 873 }, null, null); + Params[163] = new VisualParam(163, "Wrinkles", 0, "skin", String.Empty, "Less", "More", 0f, 0f, 1f, false, new int[] { 118 }, null, null); + Params[165] = new VisualParam(165, "Freckles", 0, "skin", String.Empty, "Less", "More", 0f, 0f, 1f, false, null, new VisualAlphaParam(0.5f, "freckles_alpha.tga", true, false), null); + Params[166] = new VisualParam(166, "Sideburns", 0, "hair", String.Empty, "Short Sideburns", "Mutton Chops", 0f, 0f, 1f, false, new int[] { 1004, 1005 }, null, null); + Params[167] = new VisualParam(167, "Moustache", 0, "hair", String.Empty, "Chaplin", "Handlebars", 0f, 0f, 1f, false, new int[] { 1006, 1007 }, null, null); + Params[168] = new VisualParam(168, "Soulpatch", 0, "hair", String.Empty, "Less soul", "More soul", 0f, 0f, 1f, false, new int[] { 1008, 1009 }, null, null); + Params[169] = new VisualParam(169, "Chin Curtains", 0, "hair", String.Empty, "Less Curtains", "More Curtains", 0f, 0f, 1f, false, new int[] { 1010, 1011 }, null, null); + Params[171] = new VisualParam(171, "Hair_Front_Down", 1, "hair", "Front Hair Down", "Front Hair", "Front Hair Down", 0f, 0f, 1f, false, null, null, null); + Params[172] = new VisualParam(172, "Hair_Front_Up", 1, "hair", "Front Hair Up", "Front Hair", "Front Hair Up", 0f, 0f, 1f, false, null, null, null); + Params[173] = new VisualParam(173, "Hair_Sides_Down", 1, "hair", "Sides Hair Down", "Sides Hair", "Sides Hair Down", 0f, 0f, 1f, false, null, null, null); + Params[174] = new VisualParam(174, "Hair_Sides_Up", 1, "hair", "Sides Hair Up", "Sides Hair", "Sides Hair Up", 0f, 0f, 1f, false, null, null, null); + Params[175] = new VisualParam(175, "Hair_Back_Down", 1, "hair", "Back Hair Down", "Back Hair", "Back Hair Down", 0f, 0f, 3f, false, null, null, null); + Params[176] = new VisualParam(176, "Hair_Back_Up", 1, "hair", "Back Hair Up", "Back Hair", "Back Hair Up", 0f, 0f, 1f, false, null, null, null); + Params[177] = new VisualParam(177, "Hair_Rumpled", 0, "hair", "Rumpled Hair", "Smooth Hair", "Rumpled Hair", 0f, 0f, 1f, false, null, null, null); + Params[178] = new VisualParam(178, "Hair_Swept_Back", 1, "hair", "Swept Back Hair", "NotHair", "Swept Back", 0f, 0f, 1f, false, null, null, null); + Params[179] = new VisualParam(179, "Hair_Swept_Forward", 1, "hair", "Swept Forward Hair", "Hair", "Swept Forward", 0f, 0f, 1f, false, null, null, null); + Params[180] = new VisualParam(180, "Hair_Volume", 1, "hair", "Hair Volume", "Less", "More", 0f, 0f, 1.3f, false, null, null, null); + Params[181] = new VisualParam(181, "Hair_Big_Front", 0, "hair", "Big Hair Front", "Less", "More", 0.14f, -1f, 1f, false, null, null, null); + Params[182] = new VisualParam(182, "Hair_Big_Top", 0, "hair", "Big Hair Top", "Less", "More", 0.7f, -1f, 1f, false, null, null, null); + Params[183] = new VisualParam(183, "Hair_Big_Back", 0, "hair", "Big Hair Back", "Less", "More", 0.05f, -1f, 1f, false, null, null, null); + Params[184] = new VisualParam(184, "Hair_Spiked", 0, "hair", "Spiked Hair", "No Spikes", "Big Spikes", 0f, 0f, 1f, false, null, null, null); + Params[185] = new VisualParam(185, "Deep_Chin", 0, "shape", "Chin Depth", "Shallow", "Deep", -1f, -1f, 1f, false, null, null, null); + Params[186] = new VisualParam(186, "Egg_Head", 1, "shape", "Egg Head", "Chin Heavy", "Forehead Heavy", -1.3f, -1.3f, 1f, false, null, null, null); + Params[187] = new VisualParam(187, "Squash_Stretch_Head", 1, "shape", "Squash/Stretch Head", "Squash Head", "Stretch Head", -0.5f, -0.5f, 1f, false, null, null, null); + Params[190] = new VisualParam(190, "Hair_Tilt_Right", 1, "hair", "Hair Tilted Right", "Hair", "Tilt Right", 0f, 0f, 1f, false, null, null, null); + Params[191] = new VisualParam(191, "Hair_Tilt_Left", 1, "hair", "Hair Tilted Left", "Hair", "Tilt Left", 0f, 0f, 1f, false, null, null, null); + Params[192] = new VisualParam(192, "Bangs_Part_Middle", 0, "hair", "Part Bangs", "No Part", "Part Bangs", 0f, 0f, 1f, false, null, null, null); + Params[193] = new VisualParam(193, "Head Shape", 0, "shape", "Head Shape", "More Square", "More Round", 0.5f, 0f, 1f, false, new int[] { 188, 642, 189, 643 }, null, null); + Params[194] = new VisualParam(194, "Eye_Spread", 1, "shape", String.Empty, "Eyes Together", "Eyes Spread", -2f, -2f, 2f, false, null, null, null); + Params[195] = new VisualParam(195, "EyeBone_Spread", 1, "shape", String.Empty, "Eyes Together", "Eyes Spread", -1f, -1f, 1f, false, null, null, null); + Params[196] = new VisualParam(196, "Eye Spacing", 0, "shape", "Eye Spacing", "Close Set Eyes", "Far Set Eyes", 0f, -2f, 1f, false, new int[] { 194, 195 }, null, null); + Params[197] = new VisualParam(197, "Shoe_Heels", 1, "shoes", String.Empty, "No Heels", "High Heels", 0f, 0f, 1f, false, null, null, null); + Params[198] = new VisualParam(198, "Heel Height", 0, "shoes", String.Empty, "Low Heels", "High Heels", 0f, 0f, 1f, false, new int[] { 197, 500 }, null, null); + Params[400] = new VisualParam(400, "Displace_Hair_Facial", 1, "hair", "Hair Thickess", "Cropped Hair", "Bushy Hair", 0f, 0f, 2f, false, null, null, null); + Params[500] = new VisualParam(500, "Shoe_Heel_Height", 1, "shoes", "Heel Height", "Low Heels", "High Heels", 0f, 0f, 1f, false, null, null, null); + Params[501] = new VisualParam(501, "Shoe_Platform_Height", 1, "shoes", "Platform Height", "Low Platforms", "High Platforms", 0f, 0f, 1f, false, null, null, null); + Params[502] = new VisualParam(502, "Shoe_Platform", 1, "shoes", String.Empty, "No Heels", "High Heels", 0f, 0f, 1f, false, null, null, null); + Params[503] = new VisualParam(503, "Platform Height", 0, "shoes", String.Empty, "Low Platforms", "High Platforms", 0f, 0f, 1f, false, new int[] { 501, 502 }, null, null); + Params[505] = new VisualParam(505, "Lip Thickness", 0, "shape", String.Empty, "Thin Lips", "Fat Lips", 0.5f, 0f, 1f, false, new int[] { 26, 28 }, null, null); + Params[506] = new VisualParam(506, "Mouth_Height", 0, "shape", "Mouth Position", "High", "Low", -2f, -2f, 2f, false, null, null, null); + Params[507] = new VisualParam(507, "Breast_Gravity", 0, "shape", "Breast Buoyancy", "Less Gravity", "More Gravity", 0f, -1.5f, 2f, false, null, null, null); + Params[508] = new VisualParam(508, "Shoe_Platform_Width", 0, "shoes", "Platform Width", "Narrow", "Wide", -1f, -1f, 2f, false, null, null, null); + Params[509] = new VisualParam(509, "Shoe_Heel_Point", 1, "shoes", "Heel Shape", "Default Heels", "Pointy Heels", 0f, 0f, 1f, false, null, null, null); + Params[510] = new VisualParam(510, "Shoe_Heel_Thick", 1, "shoes", "Heel Shape", "default Heels", "Thick Heels", 0f, 0f, 1f, false, null, null, null); + Params[511] = new VisualParam(511, "Shoe_Toe_Point", 1, "shoes", "Toe Shape", "Default Toe", "Pointy Toe", 0f, 0f, 1f, false, null, null, null); + Params[512] = new VisualParam(512, "Shoe_Toe_Square", 1, "shoes", "Toe Shape", "Default Toe", "Square Toe", 0f, 0f, 1f, false, null, null, null); + Params[513] = new VisualParam(513, "Heel Shape", 0, "shoes", String.Empty, "Pointy Heels", "Thick Heels", 0.5f, 0f, 1f, false, new int[] { 509, 510 }, null, null); + Params[514] = new VisualParam(514, "Toe Shape", 0, "shoes", String.Empty, "Pointy", "Square", 0.5f, 0f, 1f, false, new int[] { 511, 512 }, null, null); + Params[515] = new VisualParam(515, "Foot_Size", 0, "shape", "Foot Size", "Small", "Big", -1f, -1f, 3f, false, null, null, null); + Params[516] = new VisualParam(516, "Displace_Loose_Lowerbody", 1, "pants", "Pants Fit", String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[517] = new VisualParam(517, "Wide_Nose", 0, "shape", "Nose Width", "Narrow", "Wide", -0.5f, -0.5f, 1f, false, null, null, null); + Params[518] = new VisualParam(518, "Eyelashes_Long", 0, "shape", "Eyelash Length", "Short", "Long", -0.3f, -0.3f, 1.5f, false, null, null, null); + Params[600] = new VisualParam(600, "Sleeve Length Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.7f, 0f, 0.85f, false, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[601] = new VisualParam(601, "Shirt Bottom Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_bottom_alpha.tga", false, true), null); + Params[602] = new VisualParam(602, "Collar Front Height Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[603] = new VisualParam(603, "Sleeve Length", 0, "undershirt", String.Empty, "Short", "Long", 0.4f, 0.01f, 1f, false, new int[] { 1042, 1043 }, null, null); + Params[604] = new VisualParam(604, "Bottom", 0, "undershirt", String.Empty, "Short", "Long", 0.85f, 0f, 1f, false, new int[] { 1044, 1045 }, null, null); + Params[605] = new VisualParam(605, "Collar Front", 0, "undershirt", String.Empty, "Low", "High", 0.84f, 0f, 1f, false, new int[] { 1046, 1047 }, null, null); + Params[606] = new VisualParam(606, "Sleeve Length", 0, "jacket", String.Empty, "Short", "Long", 0.8f, 0f, 1f, false, new int[] { 1019, 1039, 1020 }, null, null); + Params[607] = new VisualParam(607, "Collar Front", 0, "jacket", String.Empty, "Low", "High", 0.8f, 0f, 1f, false, new int[] { 1021, 1040, 1022 }, null, null); + Params[608] = new VisualParam(608, "bottom length lower", 0, "jacket", "Jacket Length", "Short", "Long", 0.8f, 0f, 1f, false, new int[] { 620, 1025, 1037, 621, 1027, 1033 }, null, null); + Params[609] = new VisualParam(609, "open jacket", 0, "jacket", "Open Front", "Open", "Closed", 0.2f, 0f, 1f, false, new int[] { 622, 1026, 1038, 623, 1028, 1034 }, null, null); + Params[614] = new VisualParam(614, "Waist Height Cloth", 1, "pants", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "pants_waist_alpha.tga", false, false), null); + Params[615] = new VisualParam(615, "Pants Length Cloth", 1, "pants", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "pants_length_alpha.tga", false, false), null); + Params[616] = new VisualParam(616, "Shoe Height", 0, "shoes", String.Empty, "Short", "Tall", 0.1f, 0f, 1f, false, new int[] { 1052, 1053 }, null, null); + Params[617] = new VisualParam(617, "Socks Length", 0, "socks", String.Empty, "Short", "Long", 0.35f, 0f, 1f, false, new int[] { 1050, 1051 }, null, null); + Params[619] = new VisualParam(619, "Pants Length", 0, "underpants", String.Empty, "Short", "Long", 0.3f, 0f, 1f, false, new int[] { 1054, 1055 }, null, null); + Params[620] = new VisualParam(620, "bottom length upper", 1, "jacket", String.Empty, "hi cut", "low cut", 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "jacket_length_upper_alpha.tga", false, true), null); + Params[621] = new VisualParam(621, "bottom length lower", 1, "jacket", String.Empty, "hi cut", "low cut", 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "jacket_length_lower_alpha.tga", false, false), null); + Params[622] = new VisualParam(622, "open upper", 1, "jacket", String.Empty, "closed", "open", 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "jacket_open_upper_alpha.tga", false, true), null); + Params[623] = new VisualParam(623, "open lower", 1, "jacket", String.Empty, "open", "closed", 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "jacket_open_lower_alpha.tga", false, true), null); + Params[624] = new VisualParam(624, "Pants Waist", 0, "underpants", String.Empty, "Low", "High", 0.8f, 0f, 1f, false, new int[] { 1056, 1057 }, null, null); + Params[625] = new VisualParam(625, "Leg_Pantflair", 0, "pants", "Cuff Flare", "Tight Cuffs", "Flared Cuffs", 0f, 0f, 1.5f, false, null, null, null); + Params[626] = new VisualParam(626, "Big_Chest", 1, "shape", "Chest Size", "Small", "Large", 0f, 0f, 1f, false, null, null, null); + Params[627] = new VisualParam(627, "Small_Chest", 1, "shape", "Chest Size", "Large", "Small", 0f, 0f, 1f, false, null, null, null); + Params[628] = new VisualParam(628, "Displace_Loose_Upperbody", 1, "shirt", "Shirt Fit", String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[629] = new VisualParam(629, "Forehead Angle", 0, "shape", String.Empty, "More Vertical", "More Sloped", 0.5f, 0f, 1f, false, new int[] { 630, 644, 631, 645 }, null, null); + Params[633] = new VisualParam(633, "Fat_Head", 1, "shape", "Fat Head", "Skinny", "Fat", 0f, 0f, 1f, false, null, null, null); + Params[634] = new VisualParam(634, "Fat_Torso", 1, "shape", "Fat Torso", "skinny", "fat", 0f, 0f, 1f, false, null, null, null); + Params[635] = new VisualParam(635, "Fat_Legs", 1, "shape", "Fat Torso", "skinny", "fat", 0f, 0f, 1f, false, null, null, null); + Params[637] = new VisualParam(637, "Body Fat", 0, "shape", String.Empty, "Less Body Fat", "More Body Fat", 0f, 0f, 1f, false, new int[] { 633, 634, 635, 851 }, null, null); + Params[638] = new VisualParam(638, "Low_Crotch", 0, "pants", "Pants Crotch", "High and Tight", "Low and Loose", 0f, 0f, 1.3f, false, null, null, null); + Params[640] = new VisualParam(640, "Hair_Egg_Head", 1, "hair", String.Empty, String.Empty, String.Empty, -1.3f, -1.3f, 1f, false, null, null, null); + Params[641] = new VisualParam(641, "Hair_Squash_Stretch_Head", 1, "hair", String.Empty, String.Empty, String.Empty, -0.5f, -0.5f, 1f, false, null, null, null); + Params[642] = new VisualParam(642, "Hair_Square_Head", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[643] = new VisualParam(643, "Hair_Round_Head", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[644] = new VisualParam(644, "Hair_Forehead_Round", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[645] = new VisualParam(645, "Hair_Forehead_Slant", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[646] = new VisualParam(646, "Egg_Head", 0, "shape", "Egg Head", "Chin Heavy", "Forehead Heavy", 0f, -1.3f, 1f, false, new int[] { 640, 186 }, null, null); + Params[647] = new VisualParam(647, "Squash_Stretch_Head", 0, "shape", "Head Stretch", "Squash Head", "Stretch Head", 0f, -0.5f, 1f, false, new int[] { 641, 187 }, null, null); + Params[648] = new VisualParam(648, "Scrawny_Torso", 1, "shape", "Torso Muscles", "Regular", "Scrawny", 0f, 0f, 1.3f, false, null, null, null); + Params[649] = new VisualParam(649, "Torso Muscles", 0, "shape", "Torso Muscles", "Less Muscular", "More Muscular", 0.5f, 0f, 1f, false, new int[] { 648, 106 }, null, null); + Params[650] = new VisualParam(650, "Eyelid_Corner_Up", 0, "shape", "Outer Eye Corner", "Corner Down", "Corner Up", -1.3f, -1.3f, 1.2f, false, null, null, null); + Params[651] = new VisualParam(651, "Scrawny_Legs", 1, "shape", "Scrawny Leg", "Regular Muscles", "Less Muscles", 0f, 0f, 1.5f, false, null, null, null); + Params[652] = new VisualParam(652, "Leg Muscles", 0, "shape", String.Empty, "Less Muscular", "More Muscular", 0.5f, 0f, 1f, false, new int[] { 651, 152 }, null, null); + Params[653] = new VisualParam(653, "Tall_Lips", 0, "shape", "Lip Fullness", "Less Full", "More Full", -1f, -1f, 2f, false, null, null, null); + Params[654] = new VisualParam(654, "Shoe_Toe_Thick", 0, "shoes", "Toe Thickness", "Flat Toe", "Thick Toe", 0f, 0f, 2f, false, null, null, null); + Params[655] = new VisualParam(655, "Head Size", 1, "shape", "Head Size", "Small Head", "Big Head", -0.25f, -0.25f, 0.1f, false, null, null, null); + Params[656] = new VisualParam(656, "Crooked_Nose", 0, "shape", "Crooked Nose", "Nose Left", "Nose Right", -2f, -2f, 2f, false, null, null, null); + Params[657] = new VisualParam(657, "Smile_Mouth", 1, "shape", "Mouth Corner", "Corner Normal", "Corner Up", 0f, 0f, 1.4f, false, null, null, null); + Params[658] = new VisualParam(658, "Frown_Mouth", 1, "shape", "Mouth Corner", "Corner Normal", "Corner Down", 0f, 0f, 1.2f, false, null, null, null); + Params[659] = new VisualParam(659, "Mouth Corner", 0, "shape", String.Empty, "Corner Down", "Corner Up", 0.5f, 0f, 1f, false, new int[] { 658, 657 }, null, null); + Params[660] = new VisualParam(660, "Shear_Head", 1, "shape", "Shear Face", "Shear Left", "Shear Right", 0f, -2f, 2f, false, null, null, null); + Params[661] = new VisualParam(661, "EyeBone_Head_Shear", 1, "shape", String.Empty, "Eyes Shear Left Up", "Eyes Shear Right Up", -2f, -2f, 2f, false, null, null, null); + Params[662] = new VisualParam(662, "Face Shear", 0, "shape", String.Empty, "Shear Right Up", "Shear Left Up", 0.5f, 0f, 1f, false, new int[] { 660, 661, 774 }, null, null); + Params[663] = new VisualParam(663, "Shift_Mouth", 0, "shape", "Shift Mouth", "Shift Left", "Shift Right", 0f, -2f, 2f, false, null, null, null); + Params[664] = new VisualParam(664, "Pop_Eye", 0, "shape", "Eye Pop", "Pop Right Eye", "Pop Left Eye", 0f, -1.3f, 1.3f, false, null, null, null); + Params[665] = new VisualParam(665, "Jaw_Jut", 0, "shape", "Jaw Jut", "Overbite", "Underbite", 0f, -2f, 2f, false, null, null, null); + Params[674] = new VisualParam(674, "Hair_Shear_Back", 0, "hair", "Shear Back", "Full Back", "Sheared Back", -0.3f, -1f, 2f, false, null, null, null); + Params[675] = new VisualParam(675, "Hand Size", 0, "shape", String.Empty, "Small Hands", "Large Hands", -0.3f, -0.3f, 0.3f, false, null, null, null); + Params[676] = new VisualParam(676, "Love_Handles", 0, "shape", "Love Handles", "Less Love", "More Love", 0f, -1f, 2f, false, new int[] { 855, 856 }, null, null); + Params[677] = new VisualParam(677, "Scrawny_Torso_Male", 1, "shape", "Torso Scrawny", "Regular", "Scrawny", 0f, 0f, 1.3f, false, null, null, null); + Params[678] = new VisualParam(678, "Torso Muscles", 0, "shape", String.Empty, "Less Muscular", "More Muscular", 0.5f, 0f, 1f, false, new int[] { 677, 106 }, null, null); + Params[679] = new VisualParam(679, "Eyeball_Size", 1, "shape", "Eyeball Size", "small eye", "big eye", -0.25f, -0.25f, 0.1f, false, null, null, null); + Params[681] = new VisualParam(681, "Eyeball_Size", 1, "shape", "Eyeball Size", "small eye", "big eye", -0.25f, -0.25f, 0.1f, false, null, null, null); + Params[682] = new VisualParam(682, "Head Size", 0, "shape", "Head Size", "Small Head", "Big Head", 0.5f, 0f, 1f, false, new int[] { 679, 694, 680, 681, 655 }, null, null); + Params[683] = new VisualParam(683, "Neck Thickness", 0, "shape", String.Empty, "Skinny Neck", "Thick Neck", -0.15f, -0.4f, 0.2f, false, null, null, null); + Params[684] = new VisualParam(684, "Breast_Female_Cleavage", 0, "shape", "Breast Cleavage", "Separate", "Join", 0f, -0.3f, 1.3f, false, null, null, null); + Params[685] = new VisualParam(685, "Chest_Male_No_Pecs", 0, "shape", "Pectorals", "Big Pectorals", "Sunken Chest", 0f, -0.5f, 1.1f, false, null, null, null); + Params[686] = new VisualParam(686, "Head_Eyes_Big", 1, "shape", "Eye Size", "Beady Eyes", "Anime Eyes", 0f, -2f, 2f, false, null, null, null); + Params[687] = new VisualParam(687, "Eyeball_Size", 1, "shape", "Big Eyeball", "small eye", "big eye", -0.25f, -0.25f, 0.25f, false, null, null, null); + Params[689] = new VisualParam(689, "EyeBone_Big_Eyes", 1, "shape", String.Empty, "Eyes Back", "Eyes Forward", -1f, -1f, 1f, false, null, null, null); + Params[690] = new VisualParam(690, "Eye Size", 0, "shape", "Eye Size", "Beady Eyes", "Anime Eyes", 0.5f, 0f, 1f, false, new int[] { 686, 687, 695, 688, 691, 689 }, null, null); + Params[691] = new VisualParam(691, "Eyeball_Size", 1, "shape", "Big Eyeball", "small eye", "big eye", -0.25f, -0.25f, 0.25f, false, null, null, null); + Params[692] = new VisualParam(692, "Leg Length", 0, "shape", String.Empty, "Short Legs", "Long Legs", -1f, -1f, 1f, false, null, null, null); + Params[693] = new VisualParam(693, "Arm Length", 0, "shape", String.Empty, "Short Arms", "Long arms", 0.6f, -1f, 1f, false, null, null, null); + Params[694] = new VisualParam(694, "Eyeball_Size", 1, "shape", "Eyeball Size", "small eye", "big eye", -0.25f, -0.25f, 0.1f, false, null, null, null); + Params[695] = new VisualParam(695, "Eyeball_Size", 1, "shape", "Big Eyeball", "small eye", "big eye", -0.25f, -0.25f, 0.25f, false, null, null, null); + Params[700] = new VisualParam(700, "Lipstick Color", 0, "skin", String.Empty, "Pink", "Black", 0.25f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(245, 161, 177, 200), new Color4(216, 37, 67, 200), new Color4(178, 48, 76, 200), new Color4(68, 0, 11, 200), new Color4(252, 207, 184, 200), new Color4(241, 136, 106, 200), new Color4(208, 110, 85, 200), new Color4(106, 28, 18, 200), new Color4(58, 26, 49, 200), new Color4(14, 14, 14, 200) })); + Params[701] = new VisualParam(701, "Lipstick", 0, "skin", String.Empty, "No Lipstick", "More Lipstick", 0f, 0f, 0.9f, false, null, new VisualAlphaParam(0.05f, "lipstick_alpha.tga", true, false), null); + Params[702] = new VisualParam(702, "Lipgloss", 0, "skin", String.Empty, "No Lipgloss", "Glossy", 0f, 0f, 1f, false, null, new VisualAlphaParam(0.2f, "lipgloss_alpha.tga", true, false), null); + Params[703] = new VisualParam(703, "Eyeliner", 0, "skin", String.Empty, "No Eyeliner", "Full Eyeliner", 0f, 0f, 1f, false, null, new VisualAlphaParam(0.1f, "eyeliner_alpha.tga", true, false), null); + Params[704] = new VisualParam(704, "Blush", 0, "skin", String.Empty, "No Blush", "More Blush", 0f, 0f, 0.9f, false, null, new VisualAlphaParam(0.3f, "blush_alpha.tga", true, false), null); + Params[705] = new VisualParam(705, "Blush Color", 0, "skin", String.Empty, "Pink", "Orange", 0.5f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(253, 162, 193, 200), new Color4(247, 131, 152, 200), new Color4(213, 122, 140, 200), new Color4(253, 152, 144, 200), new Color4(236, 138, 103, 200), new Color4(195, 128, 122, 200), new Color4(148, 103, 100, 200), new Color4(168, 95, 62, 200) })); + Params[706] = new VisualParam(706, "Out Shdw Opacity", 0, "skin", String.Empty, "Clear", "Opaque", 0.6f, 0.2f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Blend, new Color4[] { new Color4(255, 255, 255, 0), new Color4(255, 255, 255, 255) })); + Params[707] = new VisualParam(707, "Outer Shadow", 0, "skin", String.Empty, "No Eyeshadow", "More Eyeshadow", 0f, 0f, 0.7f, false, null, new VisualAlphaParam(0.05f, "eyeshadow_outer_alpha.tga", true, false), null); + Params[708] = new VisualParam(708, "Out Shdw Color", 0, "skin", String.Empty, "Light", "Dark", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(252, 247, 246, 255), new Color4(255, 206, 206, 255), new Color4(233, 135, 149, 255), new Color4(220, 168, 192, 255), new Color4(228, 203, 232, 255), new Color4(255, 234, 195, 255), new Color4(230, 157, 101, 255), new Color4(255, 147, 86, 255), new Color4(228, 110, 89, 255), new Color4(228, 150, 120, 255), new Color4(223, 227, 213, 255), new Color4(96, 116, 87, 255), new Color4(88, 143, 107, 255), new Color4(194, 231, 223, 255), new Color4(207, 227, 234, 255), new Color4(41, 171, 212, 255), new Color4(180, 137, 130, 255), new Color4(173, 125, 105, 255), new Color4(144, 95, 98, 255), new Color4(115, 70, 77, 255), new Color4(155, 78, 47, 255), new Color4(239, 239, 239, 255), new Color4(194, 194, 194, 255), new Color4(120, 120, 120, 255), new Color4(10, 10, 10, 255) })); + Params[709] = new VisualParam(709, "Inner Shadow", 0, "skin", String.Empty, "No Eyeshadow", "More Eyeshadow", 0f, 0f, 1f, false, null, new VisualAlphaParam(0.2f, "eyeshadow_inner_alpha.tga", true, false), null); + Params[710] = new VisualParam(710, "Nail Polish", 0, "skin", String.Empty, "No Polish", "Painted Nails", 0f, 0f, 1f, false, null, new VisualAlphaParam(0.1f, "nailpolish_alpha.tga", true, false), null); + Params[711] = new VisualParam(711, "Blush Opacity", 0, "skin", String.Empty, "Clear", "Opaque", 0.5f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Blend, new Color4[] { new Color4(255, 255, 255, 0), new Color4(255, 255, 255, 255) })); + Params[712] = new VisualParam(712, "In Shdw Color", 0, "skin", String.Empty, "Light", "Dark", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(252, 247, 246, 255), new Color4(255, 206, 206, 255), new Color4(233, 135, 149, 255), new Color4(220, 168, 192, 255), new Color4(228, 203, 232, 255), new Color4(255, 234, 195, 255), new Color4(230, 157, 101, 255), new Color4(255, 147, 86, 255), new Color4(228, 110, 89, 255), new Color4(228, 150, 120, 255), new Color4(223, 227, 213, 255), new Color4(96, 116, 87, 255), new Color4(88, 143, 107, 255), new Color4(194, 231, 223, 255), new Color4(207, 227, 234, 255), new Color4(41, 171, 212, 255), new Color4(180, 137, 130, 255), new Color4(173, 125, 105, 255), new Color4(144, 95, 98, 255), new Color4(115, 70, 77, 255), new Color4(155, 78, 47, 255), new Color4(239, 239, 239, 255), new Color4(194, 194, 194, 255), new Color4(120, 120, 120, 255), new Color4(10, 10, 10, 255) })); + Params[713] = new VisualParam(713, "In Shdw Opacity", 0, "skin", String.Empty, "Clear", "Opaque", 0.7f, 0.2f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Blend, new Color4[] { new Color4(255, 255, 255, 0), new Color4(255, 255, 255, 255) })); + Params[714] = new VisualParam(714, "Eyeliner Color", 0, "skin", String.Empty, "Dark Green", "Black", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(24, 98, 40, 250), new Color4(9, 100, 127, 250), new Color4(61, 93, 134, 250), new Color4(70, 29, 27, 250), new Color4(115, 75, 65, 250), new Color4(100, 100, 100, 250), new Color4(91, 80, 74, 250), new Color4(112, 42, 76, 250), new Color4(14, 14, 14, 250) })); + Params[715] = new VisualParam(715, "Nail Polish Color", 0, "skin", String.Empty, "Pink", "Black", 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(255, 187, 200, 255), new Color4(194, 102, 127, 255), new Color4(227, 34, 99, 255), new Color4(168, 41, 60, 255), new Color4(97, 28, 59, 255), new Color4(234, 115, 93, 255), new Color4(142, 58, 47, 255), new Color4(114, 30, 46, 255), new Color4(14, 14, 14, 255) })); + Params[750] = new VisualParam(750, "Eyebrow Density", 0, "hair", String.Empty, "Sparse", "Dense", 0.7f, 0f, 1f, false, new int[] { 1002, 1003 }, null, null); + Params[751] = new VisualParam(751, "5 O'Clock Shadow", 1, "hair", String.Empty, "Dense hair", "Shadow hair", 0.7f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Blend, new Color4[] { new Color4(255, 255, 255, 255), new Color4(255, 255, 255, 30) })); + Params[752] = new VisualParam(752, "Hair Thickness", 0, "hair", String.Empty, "5 O'Clock Shadow", "Bushy Hair", 0.5f, 0f, 1f, false, new int[] { 751, 1012, 400 }, null, null); + Params[753] = new VisualParam(753, "Saddlebags", 0, "shape", "Saddle Bags", "Less Saddle", "More Saddle", 0f, -0.5f, 3f, false, new int[] { 850, 854 }, null, null); + Params[754] = new VisualParam(754, "Hair_Taper_Back", 0, "hair", "Taper Back", "Wide Back", "Narrow Back", 0f, -1f, 2f, false, null, null, null); + Params[755] = new VisualParam(755, "Hair_Taper_Front", 0, "hair", "Taper Front", "Wide Front", "Narrow Front", 0.05f, -1.5f, 1.5f, false, null, null, null); + Params[756] = new VisualParam(756, "Neck Length", 0, "shape", String.Empty, "Short Neck", "Long Neck", 0f, -1f, 1f, false, null, null, null); + Params[757] = new VisualParam(757, "Lower_Eyebrows", 0, "hair", "Eyebrow Height", "Higher", "Lower", -1f, -4f, 2f, false, new int[] { 871 }, null, null); + Params[758] = new VisualParam(758, "Lower_Bridge_Nose", 0, "shape", "Lower Bridge", "Low", "High", -1.5f, -1.5f, 1.5f, false, null, null, null); + Params[759] = new VisualParam(759, "Low_Septum_Nose", 0, "shape", "Nostril Division", "High", "Low", 0.5f, -1f, 1.5f, false, null, null, null); + Params[760] = new VisualParam(760, "Jaw_Angle", 0, "shape", "Jaw Angle", "Low Jaw", "High Jaw", 0f, -1.2f, 2f, false, null, null, null); + Params[761] = new VisualParam(761, "Hair_Volume_Small", 1, "hair", "Hair Volume", "Less", "More", 0f, 0f, 1.3f, false, null, null, null); + Params[762] = new VisualParam(762, "Hair_Shear_Front", 0, "hair", "Shear Front", "Full Front", "Sheared Front", 0f, 0f, 3f, false, null, null, null); + Params[763] = new VisualParam(763, "Hair Volume", 0, "hair", String.Empty, "Less Volume", "More Volume", 0.55f, 0f, 1f, false, new int[] { 761, 180 }, null, null); + Params[764] = new VisualParam(764, "Lip_Cleft_Deep", 0, "shape", "Lip Cleft Depth", "Shallow", "Deep", -0.5f, -0.5f, 1.2f, false, null, null, null); + Params[765] = new VisualParam(765, "Puffy_Lower_Lids", 0, "shape", "Puffy Eyelids", "Flat", "Puffy", -0.3f, -0.3f, 2.5f, false, null, null, null); + Params[767] = new VisualParam(767, "Bug_Eyed_Head", 1, "shape", "Eye Depth", "Sunken Eyes", "Bug Eyes", 0f, -2f, 2f, false, null, null, null); + Params[768] = new VisualParam(768, "EyeBone_Bug", 1, "shape", String.Empty, "Eyes Sunken", "Eyes Bugged", -2f, -2f, 2f, false, null, null, null); + Params[769] = new VisualParam(769, "Eye Depth", 0, "shape", String.Empty, "Sunken Eyes", "Bugged Eyes", 0.5f, 0f, 1f, false, new int[] { 767, 768 }, null, null); + Params[770] = new VisualParam(770, "Elongate_Head", 1, "shape", "Shear Face", "Flat Head", "Long Head", 0f, -1f, 1f, false, null, null, null); + Params[771] = new VisualParam(771, "Elongate_Head_Hair", 1, "hair", String.Empty, String.Empty, String.Empty, -1f, -1f, 1f, false, null, null, null); + Params[772] = new VisualParam(772, "EyeBone_Head_Elongate", 1, "shape", String.Empty, "Eyes Short Head", "Eyes Long Head", -1f, -1f, 1f, false, null, null, null); + Params[773] = new VisualParam(773, "Head Length", 0, "shape", String.Empty, "Flat Head", "Long Head", 0.5f, 0f, 1f, false, new int[] { 770, 771, 772 }, null, null); + Params[774] = new VisualParam(774, "Shear_Head_Hair", 1, "hair", String.Empty, String.Empty, String.Empty, -2f, -2f, 2f, false, null, null, null); + Params[775] = new VisualParam(775, "Body Freckles", 0, "skin", String.Empty, "Less Freckles", "More Freckles", 0f, 0f, 1f, false, new int[] { 776, 777 }, null, null); + Params[778] = new VisualParam(778, "Collar Back Height Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[779] = new VisualParam(779, "Collar Back", 0, "undershirt", String.Empty, "Low", "High", 0.84f, 0f, 1f, false, new int[] { 1048, 1049 }, null, null); + Params[780] = new VisualParam(780, "Collar Back", 0, "jacket", String.Empty, "Low", "High", 0.8f, 0f, 1f, false, new int[] { 1023, 1041, 1024 }, null, null); + Params[781] = new VisualParam(781, "Collar Back", 0, "shirt", String.Empty, "Low", "High", 0.78f, 0f, 1f, false, new int[] { 778, 1016, 1032, 903 }, null, null); + Params[782] = new VisualParam(782, "Hair_Pigtails_Short", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[783] = new VisualParam(783, "Hair_Pigtails_Med", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[784] = new VisualParam(784, "Hair_Pigtails_Long", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[785] = new VisualParam(785, "Pigtails", 0, "hair", String.Empty, "Short Pigtails", "Long Pigtails", 0f, 0f, 1f, false, new int[] { 782, 783, 790, 784 }, null, null); + Params[786] = new VisualParam(786, "Hair_Ponytail_Short", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[787] = new VisualParam(787, "Hair_Ponytail_Med", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[788] = new VisualParam(788, "Hair_Ponytail_Long", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[789] = new VisualParam(789, "Ponytail", 0, "hair", String.Empty, "Short Ponytail", "Long Ponytail", 0f, 0f, 1f, false, new int[] { 786, 787, 788 }, null, null); + Params[790] = new VisualParam(790, "Hair_Pigtails_Medlong", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[793] = new VisualParam(793, "Leg_Longcuffs", 1, "pants", "Longcuffs", String.Empty, String.Empty, 0f, 0f, 3f, false, null, null, null); + Params[794] = new VisualParam(794, "Small_Butt", 1, "shape", "Butt Size", "Regular", "Small", 0f, 0f, 1f, false, null, null, null); + Params[795] = new VisualParam(795, "Butt Size", 0, "shape", "Butt Size", "Flat Butt", "Big Butt", 0.25f, 0f, 1f, false, new int[] { 867, 794, 151, 852 }, null, null); + Params[796] = new VisualParam(796, "Pointy_Ears", 0, "shape", "Ear Tips", "Flat", "Pointy", -0.4f, -0.4f, 3f, false, null, null, null); + Params[797] = new VisualParam(797, "Fat_Upper_Lip", 1, "shape", "Fat Upper Lip", "Normal Upper", "Fat Upper", 0f, 0f, 1.5f, false, null, null, null); + Params[798] = new VisualParam(798, "Fat_Lower_Lip", 1, "shape", "Fat Lower Lip", "Normal Lower", "Fat Lower", 0f, 0f, 1.5f, false, null, null, null); + Params[799] = new VisualParam(799, "Lip Ratio", 0, "shape", "Lip Ratio", "More Upper Lip", "More Lower Lip", 0.5f, 0f, 1f, false, new int[] { 797, 798 }, null, null); + Params[800] = new VisualParam(800, "Sleeve Length", 0, "shirt", String.Empty, "Short", "Long", 0.89f, 0f, 1f, false, new int[] { 600, 1013, 1029, 900 }, null, null); + Params[801] = new VisualParam(801, "Shirt Bottom", 0, "shirt", String.Empty, "Short", "Long", 1f, 0f, 1f, false, new int[] { 601, 1014, 1030, 901 }, null, null); + Params[802] = new VisualParam(802, "Collar Front", 0, "shirt", String.Empty, "Low", "High", 0.78f, 0f, 1f, false, new int[] { 602, 1015, 1031, 902 }, null, null); + Params[803] = new VisualParam(803, "shirt_red", 0, "shirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[804] = new VisualParam(804, "shirt_green", 0, "shirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[805] = new VisualParam(805, "shirt_blue", 0, "shirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[806] = new VisualParam(806, "pants_red", 0, "pants", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[807] = new VisualParam(807, "pants_green", 0, "pants", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[808] = new VisualParam(808, "pants_blue", 0, "pants", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[809] = new VisualParam(809, "lower_jacket_red", 1, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[810] = new VisualParam(810, "lower_jacket_green", 1, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[811] = new VisualParam(811, "lower_jacket_blue", 1, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[812] = new VisualParam(812, "shoes_red", 0, "shoes", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[813] = new VisualParam(813, "shoes_green", 0, "shoes", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[814] = new VisualParam(814, "Waist Height", 0, "pants", String.Empty, "Low", "High", 1f, 0f, 1f, false, new int[] { 614, 1017, 1035, 914 }, null, null); + Params[815] = new VisualParam(815, "Pants Length", 0, "pants", String.Empty, "Short", "Long", 0.8f, 0f, 1f, false, new int[] { 615, 1018, 1036, 793, 915 }, null, null); + Params[816] = new VisualParam(816, "Loose Lower Clothing", 0, "pants", "Pants Fit", "Tight Pants", "Loose Pants", 0f, 0f, 1f, false, new int[] { 516, 913 }, null, null); + Params[817] = new VisualParam(817, "shoes_blue", 0, "shoes", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[818] = new VisualParam(818, "socks_red", 0, "socks", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[819] = new VisualParam(819, "socks_green", 0, "socks", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[820] = new VisualParam(820, "socks_blue", 0, "socks", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[821] = new VisualParam(821, "undershirt_red", 0, "undershirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[822] = new VisualParam(822, "undershirt_green", 0, "undershirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[823] = new VisualParam(823, "undershirt_blue", 0, "undershirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[824] = new VisualParam(824, "underpants_red", 0, "underpants", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[825] = new VisualParam(825, "underpants_green", 0, "underpants", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[826] = new VisualParam(826, "underpants_blue", 0, "underpants", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[827] = new VisualParam(827, "gloves_red", 0, "gloves", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[828] = new VisualParam(828, "Loose Upper Clothing", 0, "shirt", "Shirt Fit", "Tight Shirt", "Loose Shirt", 0f, 0f, 1f, false, new int[] { 628, 899 }, null, null); + Params[829] = new VisualParam(829, "gloves_green", 0, "gloves", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[830] = new VisualParam(830, "gloves_blue", 0, "gloves", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[831] = new VisualParam(831, "upper_jacket_red", 1, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[832] = new VisualParam(832, "upper_jacket_green", 1, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[833] = new VisualParam(833, "upper_jacket_blue", 1, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[834] = new VisualParam(834, "jacket_red", 0, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, new int[] { 809, 831 }, null, null); + Params[835] = new VisualParam(835, "jacket_green", 0, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, new int[] { 810, 832 }, null, null); + Params[836] = new VisualParam(836, "jacket_blue", 0, "jacket", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, new int[] { 811, 833 }, null, null); + Params[840] = new VisualParam(840, "Shirtsleeve_flair", 0, "shirt", "Sleeve Looseness", "Tight Sleeves", "Loose Sleeves", 0f, 0f, 1.5f, false, null, null, null); + Params[841] = new VisualParam(841, "Bowed_Legs", 0, "shape", "Knee Angle", "Knock Kneed", "Bow Legged", 0f, -1f, 1f, false, new int[] { 853, 847 }, null, null); + Params[842] = new VisualParam(842, "Hip Length", 0, "shape", String.Empty, "Short hips", "Long Hips", -1f, -1f, 1f, false, null, null, null); + Params[843] = new VisualParam(843, "No_Chest", 1, "shape", "Chest Size", "Some", "None", 0f, 0f, 1f, false, null, null, null); + Params[844] = new VisualParam(844, "Glove Fingers", 0, "gloves", String.Empty, "Fingerless", "Fingers", 1f, 0.01f, 1f, false, new int[] { 1060, 1061 }, null, null); + Params[845] = new VisualParam(845, "skirt_poofy", 1, "skirt", "poofy skirt", "less poofy", "more poofy", 0f, 0f, 1.5f, false, null, null, null); + Params[846] = new VisualParam(846, "skirt_loose", 1, "skirt", "loose skirt", "form fitting", "loose", 0f, 0f, 1f, false, null, null, null); + Params[847] = new VisualParam(847, "skirt_bowlegs", 1, "skirt", "legs skirt", String.Empty, String.Empty, 0f, -1f, 1f, false, null, null, null); + Params[848] = new VisualParam(848, "skirt_bustle", 0, "skirt", "bustle skirt", "no bustle", "more bustle", 0.2f, 0f, 2f, false, null, null, null); + Params[849] = new VisualParam(849, "skirt_belly", 1, "skirt", "big belly skirt", String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[850] = new VisualParam(850, "skirt_saddlebags", 1, "skirt", String.Empty, String.Empty, String.Empty, -0.5f, -0.5f, 3f, false, null, null, null); + Params[851] = new VisualParam(851, "skirt_chubby", 1, "skirt", String.Empty, "less", "more", 0f, 0f, 1f, false, null, null, null); + Params[852] = new VisualParam(852, "skirt_bigbutt", 1, "skirt", "bigbutt skirt", "less", "more", 0f, 0f, 1f, false, null, null, null); + Params[854] = new VisualParam(854, "Saddlebags", 1, "shape", String.Empty, String.Empty, String.Empty, -0.5f, -0.5f, 3f, false, null, null, null); + Params[855] = new VisualParam(855, "Love_Handles", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, -1f, 2f, false, null, null, null); + Params[856] = new VisualParam(856, "skirt_lovehandles", 1, "skirt", String.Empty, "less", "more", 0f, -1f, 2f, false, null, null, null); + Params[857] = new VisualParam(857, "skirt_male", 1, "skirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, null); + Params[858] = new VisualParam(858, "Skirt Length", 0, "skirt", String.Empty, "Short", "Long", 0.4f, 0.01f, 1f, false, null, new VisualAlphaParam(0f, "skirt_length_alpha.tga", false, true), null); + Params[859] = new VisualParam(859, "Slit Front", 0, "skirt", String.Empty, "Open Front", "Closed Front", 1f, 0f, 1f, false, null, new VisualAlphaParam(0f, "skirt_slit_front_alpha.tga", false, true), null); + Params[860] = new VisualParam(860, "Slit Back", 0, "skirt", String.Empty, "Open Back", "Closed Back", 1f, 0f, 1f, false, null, new VisualAlphaParam(0f, "skirt_slit_back_alpha.tga", false, true), null); + Params[861] = new VisualParam(861, "Slit Left", 0, "skirt", String.Empty, "Open Left", "Closed Left", 1f, 0f, 1f, false, null, new VisualAlphaParam(0f, "skirt_slit_left_alpha.tga", false, true), null); + Params[862] = new VisualParam(862, "Slit Right", 0, "skirt", String.Empty, "Open Right", "Closed Right", 1f, 0f, 1f, false, null, new VisualAlphaParam(0f, "skirt_slit_right_alpha.tga", false, true), null); + Params[863] = new VisualParam(863, "skirt_looseness", 0, "skirt", "Skirt Fit", "Tight Skirt", "Poofy Skirt", 0.333f, 0f, 1f, false, new int[] { 866, 846, 845 }, null, null); + Params[866] = new VisualParam(866, "skirt_tight", 1, "skirt", "tight skirt", "form fitting", "loose", 0f, 0f, 1f, false, null, null, null); + Params[867] = new VisualParam(867, "skirt_smallbutt", 1, "skirt", "tight skirt", "form fitting", "loose", 0f, 0f, 1f, false, null, null, null); + Params[868] = new VisualParam(868, "Shirt Wrinkles", 0, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, null, null); + Params[869] = new VisualParam(869, "Pants Wrinkles", 0, "pants", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, null, null); + Params[870] = new VisualParam(870, "Pointy_Eyebrows", 1, "hair", "Eyebrow Points", "Smooth", "Pointy", -0.5f, -0.5f, 1f, false, null, null, null); + Params[871] = new VisualParam(871, "Lower_Eyebrows", 1, "hair", "Eyebrow Height", "Higher", "Lower", -2f, -2f, 2f, false, null, null, null); + Params[872] = new VisualParam(872, "Arced_Eyebrows", 1, "hair", "Eyebrow Arc", "Flat", "Arced", 0f, 0f, 1f, false, null, null, null); + Params[873] = new VisualParam(873, "Bump base", 1, "skin", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0f, string.Empty, false, false), null); + Params[874] = new VisualParam(874, "Bump upperdef", 1, "skin", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0f, string.Empty, false, false), null); + Params[877] = new VisualParam(877, "Jacket Wrinkles", 0, "jacket", "Jacket Wrinkles", "No Wrinkles", "Wrinkles", 0f, 0f, 1f, false, new int[] { 875, 876 }, null, null); + Params[878] = new VisualParam(878, "Bump upperdef", 1, "skin", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0f, string.Empty, false, false), null); + Params[879] = new VisualParam(879, "Male_Package", 0, "shape", "Package", "Coin Purse", "Duffle Bag", 0f, -0.5f, 2f, false, null, null, null); + Params[880] = new VisualParam(880, "Eyelid_Inner_Corner_Up", 0, "shape", "Inner Eye Corner", "Corner Down", "Corner Up", -1.3f, -1.3f, 1.2f, false, null, null, null); + Params[899] = new VisualParam(899, "Upper Clothes Shading", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 0), new Color4(0, 0, 0, 80) })); + Params[900] = new VisualParam(900, "Sleeve Length Shadow", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.02f, 0.02f, 0.87f, false, null, new VisualAlphaParam(0.03f, "shirt_sleeve_alpha.tga", true, false), null); + Params[901] = new VisualParam(901, "Shirt Shadow Bottom", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.02f, 0.02f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_bottom_alpha.tga", true, true), null); + Params[902] = new VisualParam(902, "Collar Front Shadow Height", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.02f, 0.02f, 1f, false, null, new VisualAlphaParam(0.02f, "shirt_collar_alpha.tga", true, true), null); + Params[903] = new VisualParam(903, "Collar Back Shadow Height", 1, "shirt", String.Empty, String.Empty, String.Empty, 0.02f, 0.02f, 1f, false, null, new VisualAlphaParam(0.02f, "shirt_collar_back_alpha.tga", true, true), null); + Params[913] = new VisualParam(913, "Lower Clothes Shading", 1, "pants", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 0), new Color4(0, 0, 0, 80) })); + Params[914] = new VisualParam(914, "Waist Height Shadow", 1, "pants", String.Empty, String.Empty, String.Empty, 0.02f, 0.02f, 1f, false, null, new VisualAlphaParam(0.04f, "pants_waist_alpha.tga", true, false), null); + Params[915] = new VisualParam(915, "Pants Length Shadow", 1, "pants", String.Empty, String.Empty, String.Empty, 0.02f, 0.02f, 1f, false, null, new VisualAlphaParam(0.03f, "pants_length_alpha.tga", true, false), null); + Params[921] = new VisualParam(921, "skirt_red", 0, "skirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[922] = new VisualParam(922, "skirt_green", 0, "skirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[923] = new VisualParam(923, "skirt_blue", 0, "skirt", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[1000] = new VisualParam(1000, "Eyebrow Size Bump", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.1f, "eyebrows_alpha.tga", false, false), null); + Params[1001] = new VisualParam(1001, "Eyebrow Size", 1, "hair", String.Empty, String.Empty, String.Empty, 0.5f, 0f, 1f, false, null, new VisualAlphaParam(0.1f, "eyebrows_alpha.tga", false, false), null); + Params[1002] = new VisualParam(1002, "Eyebrow Density Bump", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(255, 255, 255, 0), new Color4(255, 255, 255, 255) })); + Params[1003] = new VisualParam(1003, "Eyebrow Density", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Blend, new Color4[] { new Color4(255, 255, 255, 0), new Color4(255, 255, 255, 255) })); + Params[1004] = new VisualParam(1004, "Sideburns bump", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "facehair_sideburns_alpha.tga", true, false), null); + Params[1005] = new VisualParam(1005, "Sideburns", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "facehair_sideburns_alpha.tga", true, false), null); + Params[1006] = new VisualParam(1006, "Moustache bump", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "facehair_moustache_alpha.tga", true, false), null); + Params[1007] = new VisualParam(1007, "Moustache", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "facehair_moustache_alpha.tga", true, false), null); + Params[1008] = new VisualParam(1008, "Soulpatch bump", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.1f, "facehair_soulpatch_alpha.tga", true, false), null); + Params[1009] = new VisualParam(1009, "Soulpatch", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, new VisualAlphaParam(0.1f, "facehair_soulpatch_alpha.tga", true, false), null); + Params[1010] = new VisualParam(1010, "Chin Curtains bump", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.03f, "facehair_chincurtains_alpha.tga", true, false), null); + Params[1011] = new VisualParam(1011, "Chin Curtains", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, new VisualAlphaParam(0.03f, "facehair_chincurtains_alpha.tga", true, false), null); + Params[1012] = new VisualParam(1012, "5 O'Clock Shadow bump", 1, "hair", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(255, 255, 255, 255), new Color4(255, 255, 255, 0) })); + Params[1013] = new VisualParam(1013, "Sleeve Length Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 0.85f, true, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[1014] = new VisualParam(1014, "Shirt Bottom Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_bottom_alpha.tga", false, true), null); + Params[1015] = new VisualParam(1015, "Collar Front Height Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[1016] = new VisualParam(1016, "Collar Back Height Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[1017] = new VisualParam(1017, "Waist Height Cloth", 1, "pants", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "pants_waist_alpha.tga", false, false), null); + Params[1018] = new VisualParam(1018, "Pants Length Cloth", 1, "pants", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "pants_length_alpha.tga", false, false), null); + Params[1019] = new VisualParam(1019, "Jacket Sleeve Length bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[1020] = new VisualParam(1020, "jacket Sleeve Length", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[1021] = new VisualParam(1021, "Jacket Collar Front bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[1022] = new VisualParam(1022, "jacket Collar Front", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[1023] = new VisualParam(1023, "Jacket Collar Back bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[1024] = new VisualParam(1024, "jacket Collar Back", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[1025] = new VisualParam(1025, "jacket bottom length upper bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_length_upper_alpha.tga", false, true), null); + Params[1026] = new VisualParam(1026, "jacket open upper bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_open_upper_alpha.tga", false, true), null); + Params[1027] = new VisualParam(1027, "jacket bottom length lower bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_length_lower_alpha.tga", false, false), null); + Params[1028] = new VisualParam(1028, "jacket open lower bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_open_lower_alpha.tga", false, true), null); + Params[1029] = new VisualParam(1029, "Sleeve Length Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 0.85f, true, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[1030] = new VisualParam(1030, "Shirt Bottom Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_bottom_alpha.tga", false, true), null); + Params[1031] = new VisualParam(1031, "Collar Front Height Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[1032] = new VisualParam(1032, "Collar Back Height Cloth", 1, "shirt", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[1033] = new VisualParam(1033, "jacket bottom length lower bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_length_lower_alpha.tga", false, false), null); + Params[1034] = new VisualParam(1034, "jacket open lower bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_open_lower_alpha.tga", false, true), null); + Params[1035] = new VisualParam(1035, "Waist Height Cloth", 1, "pants", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "pants_waist_alpha.tga", false, false), null); + Params[1036] = new VisualParam(1036, "Pants Length Cloth", 1, "pants", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "pants_length_alpha.tga", false, false), null); + Params[1037] = new VisualParam(1037, "jacket bottom length upper bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_length_upper_alpha.tga", false, true), null); + Params[1038] = new VisualParam(1038, "jacket open upper bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "jacket_open_upper_alpha.tga", false, true), null); + Params[1039] = new VisualParam(1039, "Jacket Sleeve Length bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[1040] = new VisualParam(1040, "Jacket Collar Front bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[1041] = new VisualParam(1041, "Jacket Collar Back bump", 1, "jacket", String.Empty, String.Empty, String.Empty, 0f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[1042] = new VisualParam(1042, "Sleeve Length", 1, "undershirt", String.Empty, String.Empty, String.Empty, 0.4f, 0.01f, 1f, false, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[1043] = new VisualParam(1043, "Sleeve Length bump", 1, "undershirt", String.Empty, String.Empty, String.Empty, 0.4f, 0.01f, 1f, true, null, new VisualAlphaParam(0.01f, "shirt_sleeve_alpha.tga", false, false), null); + Params[1044] = new VisualParam(1044, "Bottom", 1, "undershirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_bottom_alpha.tga", false, true), null); + Params[1045] = new VisualParam(1045, "Bottom bump", 1, "undershirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_bottom_alpha.tga", false, true), null); + Params[1046] = new VisualParam(1046, "Collar Front", 1, "undershirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[1047] = new VisualParam(1047, "Collar Front bump", 1, "undershirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_alpha.tga", false, true), null); + Params[1048] = new VisualParam(1048, "Collar Back", 1, "undershirt", String.Empty, "Low", "High", 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[1049] = new VisualParam(1049, "Collar Back bump", 1, "undershirt", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "shirt_collar_back_alpha.tga", false, true), null); + Params[1050] = new VisualParam(1050, "Socks Length bump", 1, "socks", String.Empty, String.Empty, String.Empty, 0.35f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "shoe_height_alpha.tga", false, false), null); + Params[1051] = new VisualParam(1051, "Socks Length bump", 1, "socks", String.Empty, String.Empty, String.Empty, 0.35f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "shoe_height_alpha.tga", false, false), null); + Params[1052] = new VisualParam(1052, "Shoe Height", 1, "shoes", String.Empty, String.Empty, String.Empty, 0.1f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "shoe_height_alpha.tga", false, false), null); + Params[1053] = new VisualParam(1053, "Shoe Height bump", 1, "shoes", String.Empty, String.Empty, String.Empty, 0.1f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "shoe_height_alpha.tga", false, false), null); + Params[1054] = new VisualParam(1054, "Pants Length", 1, "underpants", String.Empty, String.Empty, String.Empty, 0.3f, 0f, 1f, false, null, new VisualAlphaParam(0.01f, "pants_length_alpha.tga", false, false), null); + Params[1055] = new VisualParam(1055, "Pants Length", 1, "underpants", String.Empty, String.Empty, String.Empty, 0.3f, 0f, 1f, true, null, new VisualAlphaParam(0.01f, "pants_length_alpha.tga", false, false), null); + Params[1056] = new VisualParam(1056, "Pants Waist", 1, "underpants", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, false, null, new VisualAlphaParam(0.05f, "pants_waist_alpha.tga", false, false), null); + Params[1057] = new VisualParam(1057, "Pants Waist", 1, "underpants", String.Empty, String.Empty, String.Empty, 0.8f, 0f, 1f, true, null, new VisualAlphaParam(0.05f, "pants_waist_alpha.tga", false, false), null); + Params[1058] = new VisualParam(1058, "Glove Length", 1, "gloves", String.Empty, String.Empty, String.Empty, 0.8f, 0.01f, 1f, false, null, new VisualAlphaParam(0.01f, "glove_length_alpha.tga", false, false), null); + Params[1059] = new VisualParam(1059, "Glove Length bump", 1, "gloves", String.Empty, String.Empty, String.Empty, 0.8f, 0.01f, 1f, true, null, new VisualAlphaParam(0.01f, "glove_length_alpha.tga", false, false), null); + Params[1060] = new VisualParam(1060, "Glove Fingers", 1, "gloves", String.Empty, String.Empty, String.Empty, 1f, 0.01f, 1f, false, null, new VisualAlphaParam(0.01f, "gloves_fingers_alpha.tga", false, true), null); + Params[1061] = new VisualParam(1061, "Glove Fingers bump", 1, "gloves", String.Empty, String.Empty, String.Empty, 1f, 0.01f, 1f, true, null, new VisualAlphaParam(0.01f, "gloves_fingers_alpha.tga", false, true), null); + Params[1062] = new VisualParam(1062, "tattoo_head_red", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[1063] = new VisualParam(1063, "tattoo_head_green", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[1064] = new VisualParam(1064, "tattoo_head_blue", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[1065] = new VisualParam(1065, "tattoo_upper_red", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[1066] = new VisualParam(1066, "tattoo_upper_green", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[1067] = new VisualParam(1067, "tattoo_upper_blue", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[1068] = new VisualParam(1068, "tattoo_lower_red", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(255, 0, 0, 255) })); + Params[1069] = new VisualParam(1069, "tattoo_lower_green", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 255, 0, 255) })); + Params[1070] = new VisualParam(1070, "tattoo_lower_blue", 1, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, null, null, new VisualColorParam(VisualColorOperation.Add, new Color4[] { new Color4(0, 0, 0, 255), new Color4(0, 0, 255, 255) })); + Params[1071] = new VisualParam(1071, "tattoo_red", 2, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, new int[] { 1062, 1065, 1068 }, null, null); + Params[1072] = new VisualParam(1072, "tattoo_green", 2, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, new int[] { 1063, 1066, 1069 }, null, null); + Params[1073] = new VisualParam(1073, "tattoo_blue", 2, "tattoo", String.Empty, String.Empty, String.Empty, 1f, 0f, 1f, false, new int[] { 1064, 1067, 1070 }, null, null); + Params[1200] = new VisualParam(1200, "Breast_Physics_UpDown_Driven", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, -3f, 3f, false, null, null, null); + Params[1201] = new VisualParam(1201, "Breast_Physics_InOut_Driven", 1, "shape", String.Empty, String.Empty, String.Empty, 0f, -1.25f, 1.25f, false, null, null, null); + Params[1202] = new VisualParam(1202, "Belly_Physics_Legs_UpDown_Driven", 1, "physics", String.Empty, String.Empty, String.Empty, -1f, -1f, 1f, false, null, null, null); + Params[1203] = new VisualParam(1203, "Belly_Physics_Skirt_UpDown_Driven", 1, "physics", String.Empty, String.Empty, String.Empty, 0f, -1f, 1f, false, null, null, null); + Params[1204] = new VisualParam(1204, "Belly_Physics_Torso_UpDown_Driven", 1, "physics", String.Empty, String.Empty, String.Empty, 0f, -1f, 1f, false, null, null, null); + Params[1205] = new VisualParam(1205, "Butt_Physics_UpDown_Driven", 1, "physics", String.Empty, String.Empty, String.Empty, 0f, -1f, 1f, false, null, null, null); + Params[1206] = new VisualParam(1206, "Butt_Physics_LeftRight_Driven", 1, "physics", String.Empty, String.Empty, String.Empty, 0f, -1f, 1f, false, null, null, null); + Params[1207] = new VisualParam(1207, "Breast_Physics_LeftRight_Driven", 1, "physics", String.Empty, String.Empty, String.Empty, 0f, -2f, 2f, false, null, null, null); + Params[10000] = new VisualParam(10000, "Breast_Physics_Mass", 0, "physics", "Breast Physics Mass", String.Empty, String.Empty, 0.1f, 0.1f, 1f, false, null, null, null); + Params[10001] = new VisualParam(10001, "Breast_Physics_Gravity", 0, "physics", "Breast Physics Gravity", String.Empty, String.Empty, 0f, 0f, 30f, false, null, null, null); + Params[10002] = new VisualParam(10002, "Breast_Physics_Drag", 0, "physics", "Breast Physics Drag", String.Empty, String.Empty, 1f, 0f, 10f, false, null, null, null); + Params[10003] = new VisualParam(10003, "Breast_Physics_UpDown_Max_Effect", 0, "physics", "Breast Physics UpDown Max Effect", String.Empty, String.Empty, 0f, 0f, 3f, false, null, null, null); + Params[10004] = new VisualParam(10004, "Breast_Physics_UpDown_Spring", 0, "physics", "Breast Physics UpDown Spring", String.Empty, String.Empty, 10f, 0f, 100f, false, null, null, null); + Params[10005] = new VisualParam(10005, "Breast_Physics_UpDown_Gain", 0, "physics", "Breast Physics UpDown Gain", String.Empty, String.Empty, 10f, 1f, 100f, false, null, null, null); + Params[10006] = new VisualParam(10006, "Breast_Physics_UpDown_Damping", 0, "physics", "Breast Physics UpDown Damping", String.Empty, String.Empty, 0.2f, 0f, 1f, false, null, null, null); + Params[10007] = new VisualParam(10007, "Breast_Physics_InOut_Max_Effect", 0, "physics", "Breast Physics InOut Max Effect", String.Empty, String.Empty, 0f, 0f, 3f, false, null, null, null); + Params[10008] = new VisualParam(10008, "Breast_Physics_InOut_Spring", 0, "physics", "Breast Physics InOut Spring", String.Empty, String.Empty, 10f, 0f, 100f, false, null, null, null); + Params[10009] = new VisualParam(10009, "Breast_Physics_InOut_Gain", 0, "physics", "Breast Physics InOut Gain", String.Empty, String.Empty, 10f, 1f, 100f, false, null, null, null); + Params[10010] = new VisualParam(10010, "Breast_Physics_InOut_Damping", 0, "physics", "Breast Physics InOut Damping", String.Empty, String.Empty, 0.2f, 0f, 1f, false, null, null, null); + Params[10011] = new VisualParam(10011, "Belly_Physics_Mass", 0, "physics", "Belly Physics Mass", String.Empty, String.Empty, 0.1f, 0.1f, 1f, false, null, null, null); + Params[10012] = new VisualParam(10012, "Belly_Physics_Gravity", 0, "physics", "Belly Physics Gravity", String.Empty, String.Empty, 0f, 0f, 30f, false, null, null, null); + Params[10013] = new VisualParam(10013, "Belly_Physics_Drag", 0, "physics", "Belly Physics Drag", String.Empty, String.Empty, 1f, 0f, 10f, false, null, null, null); + Params[10014] = new VisualParam(10014, "Belly_Physics_UpDown_Max_Effect", 0, "physics", "Belly Physics UpDown Max Effect", String.Empty, String.Empty, 0f, 0f, 3f, false, null, null, null); + Params[10015] = new VisualParam(10015, "Belly_Physics_UpDown_Spring", 0, "physics", "Belly Physics UpDown Spring", String.Empty, String.Empty, 10f, 0f, 100f, false, null, null, null); + Params[10016] = new VisualParam(10016, "Belly_Physics_UpDown_Gain", 0, "physics", "Belly Physics UpDown Gain", String.Empty, String.Empty, 10f, 1f, 100f, false, null, null, null); + Params[10017] = new VisualParam(10017, "Belly_Physics_UpDown_Damping", 0, "physics", "Belly Physics UpDown Damping", String.Empty, String.Empty, 0.2f, 0f, 1f, false, null, null, null); + Params[10018] = new VisualParam(10018, "Butt_Physics_Mass", 0, "physics", "Butt Physics Mass", String.Empty, String.Empty, 0.1f, 0.1f, 1f, false, null, null, null); + Params[10019] = new VisualParam(10019, "Butt_Physics_Gravity", 0, "physics", "Butt Physics Gravity", String.Empty, String.Empty, 0f, 0f, 30f, false, null, null, null); + Params[10020] = new VisualParam(10020, "Butt_Physics_Drag", 0, "physics", "Butt Physics Drag", String.Empty, String.Empty, 1f, 0f, 10f, false, null, null, null); + Params[10021] = new VisualParam(10021, "Butt_Physics_UpDown_Max_Effect", 0, "physics", "Butt Physics UpDown Max Effect", String.Empty, String.Empty, 0f, 0f, 3f, false, null, null, null); + Params[10022] = new VisualParam(10022, "Butt_Physics_UpDown_Spring", 0, "physics", "Butt Physics UpDown Spring", String.Empty, String.Empty, 10f, 0f, 100f, false, null, null, null); + Params[10023] = new VisualParam(10023, "Butt_Physics_UpDown_Gain", 0, "physics", "Butt Physics UpDown Gain", String.Empty, String.Empty, 10f, 1f, 100f, false, null, null, null); + Params[10024] = new VisualParam(10024, "Butt_Physics_UpDown_Damping", 0, "physics", "Butt Physics UpDown Damping", String.Empty, String.Empty, 0.2f, 0f, 1f, false, null, null, null); + Params[10025] = new VisualParam(10025, "Butt_Physics_LeftRight_Max_Effect", 0, "physics", "Butt Physics LeftRight Max Effect", String.Empty, String.Empty, 0f, 0f, 3f, false, null, null, null); + Params[10026] = new VisualParam(10026, "Butt_Physics_LeftRight_Spring", 0, "physics", "Butt Physics LeftRight Spring", String.Empty, String.Empty, 10f, 0f, 100f, false, null, null, null); + Params[10027] = new VisualParam(10027, "Butt_Physics_LeftRight_Gain", 0, "physics", "Butt Physics LeftRight Gain", String.Empty, String.Empty, 10f, 1f, 100f, false, null, null, null); + Params[10028] = new VisualParam(10028, "Butt_Physics_LeftRight_Damping", 0, "physics", "Butt Physics LeftRight Damping", String.Empty, String.Empty, 0.2f, 0f, 1f, false, null, null, null); + Params[10029] = new VisualParam(10029, "Breast_Physics_LeftRight_Max_Effect", 0, "physics", "Breast Physics LeftRight Max Effect", String.Empty, String.Empty, 0f, 0f, 3f, false, null, null, null); + Params[10030] = new VisualParam(10030, "Breast_Physics_LeftRight_Spring", 0, "physics", "Breast Physics LeftRight Spring", String.Empty, String.Empty, 10f, 0f, 100f, false, null, null, null); + Params[10031] = new VisualParam(10031, "Breast_Physics_LeftRight_Gain", 0, "physics", "Breast Physics LeftRight Gain", String.Empty, String.Empty, 10f, 1f, 100f, false, null, null, null); + Params[10032] = new VisualParam(10032, "Breast_Physics_LeftRight_Damping", 0, "physics", "Breast Physics LeftRight Damping", String.Empty, String.Empty, 0.2f, 0f, 1f, false, null, null, null); + } + } +} diff --git a/OpenMetaverseTypes/BlockingQueue.cs b/OpenMetaverseTypes/BlockingQueue.cs new file mode 100644 index 0000000..da80336 --- /dev/null +++ b/OpenMetaverseTypes/BlockingQueue.cs @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse +{ + /// + /// Same as Queue except Dequeue function blocks until there is an object to return. + /// Note: This class does not need to be synchronized + /// + public class BlockingQueue : Queue + { + private object SyncRoot; + private bool open; + + /// + /// Create new BlockingQueue. + /// + /// The System.Collections.ICollection to copy elements from + public BlockingQueue(IEnumerable col) + : base(col) + { + SyncRoot = new object(); + open = true; + } + + /// + /// Create new BlockingQueue. + /// + /// The initial number of elements that the queue can contain + public BlockingQueue(int capacity) + : base(capacity) + { + SyncRoot = new object(); + open = true; + } + + /// + /// Create new BlockingQueue. + /// + public BlockingQueue() + : base() + { + SyncRoot = new object(); + open = true; + } + + /// + /// BlockingQueue Destructor (Close queue, resume any waiting thread). + /// + ~BlockingQueue() + { + Close(); + } + + /// + /// Remove all objects from the Queue. + /// + public new void Clear() + { + lock (SyncRoot) + { + base.Clear(); + } + } + + /// + /// Remove all objects from the Queue, resume all dequeue threads. + /// + public void Close() + { + lock (SyncRoot) + { + open = false; + base.Clear(); + Monitor.PulseAll(SyncRoot); // resume any waiting threads + } + } + + /// + /// Removes and returns the object at the beginning of the Queue. + /// + /// Object in queue. + public new T Dequeue() + { + return Dequeue(Timeout.Infinite); + } + + /// + /// Removes and returns the object at the beginning of the Queue. + /// + /// time to wait before returning + /// Object in queue. + public T Dequeue(TimeSpan timeout) + { + return Dequeue(timeout.Milliseconds); + } + + /// + /// Removes and returns the object at the beginning of the Queue. + /// + /// time to wait before returning (in milliseconds) + /// Object in queue. + public T Dequeue(int timeout) + { + lock (SyncRoot) + { + while (open && (base.Count == 0)) + { + if (!Monitor.Wait(SyncRoot, timeout)) + throw new InvalidOperationException("Timeout"); + } + if (open) + return base.Dequeue(); + else + throw new InvalidOperationException("Queue Closed"); + } + } + + public bool Dequeue(int timeout, ref T obj) + { + lock (SyncRoot) + { + while (open && (base.Count == 0)) + { + if (!Monitor.Wait(SyncRoot, timeout)) + return false; + } + if (open) + { + obj = base.Dequeue(); + return true; + } + else + { + obj = default(T); + return false; + } + } + } + + /// + /// Adds an object to the end of the Queue + /// + /// Object to put in queue + public new void Enqueue(T obj) + { + lock (SyncRoot) + { + base.Enqueue(obj); + Monitor.Pulse(SyncRoot); + } + } + + /// + /// Open Queue. + /// + public void Open() + { + lock (SyncRoot) + { + open = true; + } + } + + /// + /// Gets flag indicating if queue has been closed. + /// + public bool Closed + { + get { return !open; } + } + } +} diff --git a/OpenMetaverseTypes/CRC32.cs b/OpenMetaverseTypes/CRC32.cs new file mode 100644 index 0000000..9cd0b9a --- /dev/null +++ b/OpenMetaverseTypes/CRC32.cs @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + public class CRC32 + { + #region CRC table for polynomial 0xEDB88320 + + static readonly uint[] crcTable = new uint[] { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + + #endregion CRC table for polynomial 0xEDB88320 + + public uint CRC; + + public CRC32() + { + CRC = 0xffffffff; + } + + public void Update(byte value) + { + CRC = crcTable[(CRC ^ value) & 0xff] ^ (CRC >> 8); + } + + public void Update(byte[] value, int pos, int length) + { + for (int i = pos; i < length; i++) + CRC = crcTable[(CRC ^ value[i]) & 0xff] ^ (CRC >> 8); + } + } +} diff --git a/OpenMetaverseTypes/CircularQueue.cs b/OpenMetaverseTypes/CircularQueue.cs new file mode 100644 index 0000000..d84f807 --- /dev/null +++ b/OpenMetaverseTypes/CircularQueue.cs @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + public class CircularQueue + { + public readonly T[] Items; + + int first; + int next; + int capacity; + object syncRoot; + + public int First { get { return first; } } + public int Next { get { return next; } } + + public CircularQueue(int capacity) + { + this.capacity = capacity; + Items = new T[capacity]; + syncRoot = new object(); + } + + /// + /// Copy constructor + /// + /// Circular queue to copy + public CircularQueue(CircularQueue queue) + { + lock (queue.syncRoot) + { + capacity = queue.capacity; + Items = new T[capacity]; + syncRoot = new object(); + + for (int i = 0; i < capacity; i++) + Items[i] = queue.Items[i]; + + first = queue.first; + next = queue.next; + } + } + + public void Clear() + { + lock (syncRoot) + { + // Explicitly remove references to help garbage collection + for (int i = 0; i < capacity; i++) + Items[i] = default(T); + + first = next; + } + } + + public void Enqueue(T value) + { + lock (syncRoot) + { + Items[next] = value; + next = (next + 1) % capacity; + if (next == first) first = (first + 1) % capacity; + } + } + + public T Dequeue() + { + lock (syncRoot) + { + T value = Items[first]; + Items[first] = default(T); + + if (first != next) + first = (first + 1) % capacity; + + return value; + } + } + + public T DequeueLast() + { + lock (syncRoot) + { + // If the next element is right behind the first element (queue is full), + // back up the first element by one + int firstTest = first - 1; + if (firstTest < 0) firstTest = capacity - 1; + + if (firstTest == next) + { + --next; + if (next < 0) next = capacity - 1; + + --first; + if (first < 0) first = capacity - 1; + } + else if (first != next) + { + --next; + if (next < 0) next = capacity - 1; + } + + T value = Items[next]; + Items[next] = default(T); + + return value; + } + } + } +} diff --git a/OpenMetaverseTypes/Color4.cs b/OpenMetaverseTypes/Color4.cs new file mode 100644 index 0000000..ad56638 --- /dev/null +++ b/OpenMetaverseTypes/Color4.cs @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.InteropServices; + +namespace OpenMetaverse +{ + /// + /// An 8-bit color structure including an alpha channel + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Color4 : IComparable, IEquatable + { + /// Red + public float R; + /// Green + public float G; + /// Blue + public float B; + /// Alpha + public float A; + + #region Constructors + + /// + /// + /// + /// + /// + /// + /// + public Color4(byte r, byte g, byte b, byte a) + { + const float quanta = 1.0f / 255.0f; + + R = (float)r * quanta; + G = (float)g * quanta; + B = (float)b * quanta; + A = (float)a * quanta; + } + + public Color4(float r, float g, float b, float a) + { + // Quick check to see if someone is doing something obviously wrong + // like using float values from 0.0 - 255.0 + if (r > 1f || g > 1f || b > 1f || a > 1f) + throw new ArgumentException( + String.Format("Attempting to initialize Color4 with out of range values <{0},{1},{2},{3}>", + r, g, b, a)); + + // Valid range is from 0.0 to 1.0 + R = Utils.Clamp(r, 0f, 1f); + G = Utils.Clamp(g, 0f, 1f); + B = Utils.Clamp(b, 0f, 1f); + A = Utils.Clamp(a, 0f, 1f); + } + + /// + /// Builds a color from a byte array + /// + /// Byte array containing a 16 byte color + /// Beginning position in the byte array + /// True if the byte array stores inverted values, + /// otherwise false. For example the color black (fully opaque) inverted + /// would be 0xFF 0xFF 0xFF 0x00 + public Color4(byte[] byteArray, int pos, bool inverted) + { + R = G = B = A = 0f; + FromBytes(byteArray, pos, inverted); + } + + /// + /// Returns the raw bytes for this vector + /// + /// Byte array containing a 16 byte color + /// Beginning position in the byte array + /// True if the byte array stores inverted values, + /// otherwise false. For example the color black (fully opaque) inverted + /// would be 0xFF 0xFF 0xFF 0x00 + /// True if the alpha value is inverted in + /// addition to whatever the inverted parameter is. Setting inverted true + /// and alphaInverted true will flip the alpha value back to non-inverted, + /// but keep the other color bytes inverted + /// A 16 byte array containing R, G, B, and A + public Color4(byte[] byteArray, int pos, bool inverted, bool alphaInverted) + { + R = G = B = A = 0f; + FromBytes(byteArray, pos, inverted, alphaInverted); + } + + /// + /// Copy constructor + /// + /// Color to copy + public Color4(Color4 color) + { + R = color.R; + G = color.G; + B = color.B; + A = color.A; + } + + #endregion Constructors + + #region Public Methods + + /// + /// IComparable.CompareTo implementation + /// + /// Sorting ends up like this: |--Grayscale--||--Color--|. + /// Alpha is only used when the colors are otherwise equivalent + public int CompareTo(Color4 color) + { + float thisHue = GetHue(); + float thatHue = color.GetHue(); + + if (thisHue < 0f && thatHue < 0f) + { + // Both monochromatic + if (R == color.R) + { + // Monochromatic and equal, compare alpha + return A.CompareTo(color.A); + } + else + { + // Compare lightness + return R.CompareTo(R); + } + } + else + { + if (thisHue == thatHue) + { + // RGB is equal, compare alpha + return A.CompareTo(color.A); + } + else + { + // Compare hues + return thisHue.CompareTo(thatHue); + } + } + } + + public void FromBytes(byte[] byteArray, int pos, bool inverted) + { + const float quanta = 1.0f / 255.0f; + + if (inverted) + { + R = (float)(255 - byteArray[pos]) * quanta; + G = (float)(255 - byteArray[pos + 1]) * quanta; + B = (float)(255 - byteArray[pos + 2]) * quanta; + A = (float)(255 - byteArray[pos + 3]) * quanta; + } + else + { + R = (float)byteArray[pos] * quanta; + G = (float)byteArray[pos + 1] * quanta; + B = (float)byteArray[pos + 2] * quanta; + A = (float)byteArray[pos + 3] * quanta; + } + } + + /// + /// Builds a color from a byte array + /// + /// Byte array containing a 16 byte color + /// Beginning position in the byte array + /// True if the byte array stores inverted values, + /// otherwise false. For example the color black (fully opaque) inverted + /// would be 0xFF 0xFF 0xFF 0x00 + /// True if the alpha value is inverted in + /// addition to whatever the inverted parameter is. Setting inverted true + /// and alphaInverted true will flip the alpha value back to non-inverted, + /// but keep the other color bytes inverted + public void FromBytes(byte[] byteArray, int pos, bool inverted, bool alphaInverted) + { + FromBytes(byteArray, pos, inverted); + + if (alphaInverted) + A = 1.0f - A; + } + + public byte[] GetBytes() + { + return GetBytes(false); + } + + public byte[] GetBytes(bool inverted) + { + byte[] byteArray = new byte[4]; + ToBytes(byteArray, 0, inverted); + return byteArray; + } + + public byte[] GetFloatBytes() + { + byte[] bytes = new byte[16]; + ToFloatBytes(bytes, 0); + return bytes; + } + + /// + /// Writes the raw bytes for this color to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 16 bytes before the end of the array + public void ToBytes(byte[] dest, int pos) + { + ToBytes(dest, pos, false); + } + + /// + /// Serializes this color into four bytes in a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 4 bytes before the end of the array + /// True to invert the output (1.0 becomes 0 + /// instead of 255) + public void ToBytes(byte[] dest, int pos, bool inverted) + { + dest[pos + 0] = Utils.FloatToByte(R, 0f, 1f); + dest[pos + 1] = Utils.FloatToByte(G, 0f, 1f); + dest[pos + 2] = Utils.FloatToByte(B, 0f, 1f); + dest[pos + 3] = Utils.FloatToByte(A, 0f, 1f); + + if (inverted) + { + dest[pos + 0] = (byte)(255 - dest[pos + 0]); + dest[pos + 1] = (byte)(255 - dest[pos + 1]); + dest[pos + 2] = (byte)(255 - dest[pos + 2]); + dest[pos + 3] = (byte)(255 - dest[pos + 3]); + } + } + + /// + /// Writes the raw bytes for this color to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 16 bytes before the end of the array + public void ToFloatBytes(byte[] dest, int pos) + { + Buffer.BlockCopy(BitConverter.GetBytes(R), 0, dest, pos + 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(G), 0, dest, pos + 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(B), 0, dest, pos + 8, 4); + Buffer.BlockCopy(BitConverter.GetBytes(A), 0, dest, pos + 12, 4); + } + + public float GetHue() + { + const float HUE_MAX = 360f; + + float max = Math.Max(Math.Max(R, G), B); + float min = Math.Min(Math.Min(R, B), B); + + if (max == min) + { + // Achromatic, hue is undefined + return -1f; + } + else if (R == max) + { + float bDelta = (((max - B) * (HUE_MAX / 6f)) + ((max - min) / 2f)) / (max - min); + float gDelta = (((max - G) * (HUE_MAX / 6f)) + ((max - min) / 2f)) / (max - min); + return bDelta - gDelta; + } + else if (G == max) + { + float rDelta = (((max - R) * (HUE_MAX / 6f)) + ((max - min) / 2f)) / (max - min); + float bDelta = (((max - B) * (HUE_MAX / 6f)) + ((max - min) / 2f)) / (max - min); + return (HUE_MAX / 3f) + rDelta - bDelta; + } + else // B == max + { + float gDelta = (((max - G) * (HUE_MAX / 6f)) + ((max - min) / 2f)) / (max - min); + float rDelta = (((max - R) * (HUE_MAX / 6f)) + ((max - min) / 2f)) / (max - min); + return ((2f * HUE_MAX) / 3f) + gDelta - rDelta; + } + } + + /// + /// Ensures that values are in range 0-1 + /// + public void ClampValues() + { + if (R < 0f) + R = 0f; + if (G < 0f) + G = 0f; + if (B < 0f) + B = 0f; + if (A < 0f) + A = 0f; + if (R > 1f) + R = 1f; + if (G > 1f) + G = 1f; + if (B > 1f) + B = 1f; + if (A > 1f) + A = 1f; + } + + #endregion Public Methods + + #region Static Methods + + /// + /// Create an RGB color from a hue, saturation, value combination + /// + /// Hue + /// Saturation + /// Value + /// An fully opaque RGB color (alpha is 1.0) + public static Color4 FromHSV(double hue, double saturation, double value) + { + double r = 0d; + double g = 0d; + double b = 0d; + + if (saturation == 0d) + { + // If s is 0, all colors are the same. + // This is some flavor of gray. + r = value; + g = value; + b = value; + } + else + { + double p; + double q; + double t; + + double fractionalSector; + int sectorNumber; + double sectorPos; + + // The color wheel consists of 6 sectors. + // Figure out which sector you//re in. + sectorPos = hue / 60d; + sectorNumber = (int)(Math.Floor(sectorPos)); + + // get the fractional part of the sector. + // That is, how many degrees into the sector + // are you? + fractionalSector = sectorPos - sectorNumber; + + // Calculate values for the three axes + // of the color. + p = value * (1d - saturation); + q = value * (1d - (saturation * fractionalSector)); + t = value * (1d - (saturation * (1d - fractionalSector))); + + // Assign the fractional colors to r, g, and b + // based on the sector the angle is in. + switch (sectorNumber) + { + case 0: + r = value; + g = t; + b = p; + break; + case 1: + r = q; + g = value; + b = p; + break; + case 2: + r = p; + g = value; + b = t; + break; + case 3: + r = p; + g = q; + b = value; + break; + case 4: + r = t; + g = p; + b = value; + break; + case 5: + r = value; + g = p; + b = q; + break; + } + } + + return new Color4((float)r, (float)g, (float)b, 1f); + } + + /// + /// Performs linear interpolation between two colors + /// + /// Color to start at + /// Color to end at + /// Amount to interpolate + /// The interpolated color + public static Color4 Lerp(Color4 value1, Color4 value2, float amount) + { + return new Color4( + Utils.Lerp(value1.R, value2.R, amount), + Utils.Lerp(value1.G, value2.G, amount), + Utils.Lerp(value1.B, value2.B, amount), + Utils.Lerp(value1.A, value2.A, amount)); + } + + #endregion Static Methods + + #region Overrides + + public override string ToString() + { + return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}, {3}>", R, G, B, A); + } + + public string ToRGBString() + { + return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}>", R, G, B); + } + + public override bool Equals(object obj) + { + return (obj is Color4) ? this == (Color4)obj : false; + } + + public bool Equals(Color4 other) + { + return this == other; + } + + public override int GetHashCode() + { + return R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode(); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Color4 lhs, Color4 rhs) + { + return (lhs.R == rhs.R) && (lhs.G == rhs.G) && (lhs.B == rhs.B) && (lhs.A == rhs.A); + } + + public static bool operator !=(Color4 lhs, Color4 rhs) + { + return !(lhs == rhs); + } + + public static Color4 operator +(Color4 lhs, Color4 rhs) + { + lhs.R += rhs.R; + lhs.G += rhs.G; + lhs.B += rhs.B; + lhs.A += rhs.A; + lhs.ClampValues(); + + return lhs; + } + + public static Color4 operator -(Color4 lhs, Color4 rhs) + { + lhs.R -= rhs.R; + lhs.G -= rhs.G; + lhs.B -= rhs.B; + lhs.A -= rhs.A; + lhs.ClampValues(); + + return lhs; + } + + public static Color4 operator *(Color4 lhs, Color4 rhs) + { + lhs.R *= rhs.R; + lhs.G *= rhs.G; + lhs.B *= rhs.B; + lhs.A *= rhs.A; + lhs.ClampValues(); + + return lhs; + } + + #endregion Operators + + /// A Color4 with zero RGB values and fully opaque (alpha 1.0) + public readonly static Color4 Black = new Color4(0f, 0f, 0f, 1f); + + /// A Color4 with full RGB values (1.0) and fully opaque (alpha 1.0) + public readonly static Color4 White = new Color4(1f, 1f, 1f, 1f); + } +} diff --git a/OpenMetaverseTypes/DoubleDictionary.cs b/OpenMetaverseTypes/DoubleDictionary.cs new file mode 100644 index 0000000..f818972 --- /dev/null +++ b/OpenMetaverseTypes/DoubleDictionary.cs @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using System.Collections.Generic; + +#if VISUAL_STUDIO +using ReaderWriterLockImpl = System.Threading.ReaderWriterLockSlim; +#else +using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim; +#endif + +namespace OpenMetaverse +{ + public class DoubleDictionary + { + Dictionary Dictionary1; + Dictionary Dictionary2; + ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl(); + + public DoubleDictionary() + { + Dictionary1 = new Dictionary(); + Dictionary2 = new Dictionary(); + } + + public DoubleDictionary(int capacity) + { + Dictionary1 = new Dictionary(capacity); + Dictionary2 = new Dictionary(capacity); + } + + public void Add(TKey1 key1, TKey2 key2, TValue value) + { + rwLock.EnterWriteLock(); + + try + { + if (Dictionary1.ContainsKey(key1)) + { + if (!Dictionary2.ContainsKey(key2)) + throw new ArgumentException("key1 exists in the dictionary but not key2"); + } + else if (Dictionary2.ContainsKey(key2)) + { + if (!Dictionary1.ContainsKey(key1)) + throw new ArgumentException("key2 exists in the dictionary but not key1"); + } + + Dictionary1[key1] = value; + Dictionary2[key2] = value; + } + finally { rwLock.ExitWriteLock(); } + } + + public bool Remove(TKey1 key1, TKey2 key2) + { + bool success; + rwLock.EnterWriteLock(); + + try + { + Dictionary1.Remove(key1); + success = Dictionary2.Remove(key2); + } + finally { rwLock.ExitWriteLock(); } + + return success; + } + + public bool Remove(TKey1 key1) + { + bool found = false; + rwLock.EnterWriteLock(); + + try + { + // This is an O(n) operation! + TValue value; + if (Dictionary1.TryGetValue(key1, out value)) + { + foreach (KeyValuePair kvp in Dictionary2) + { + if (kvp.Value.Equals(value)) + { + Dictionary1.Remove(key1); + Dictionary2.Remove(kvp.Key); + found = true; + break; + } + } + } + } + finally { rwLock.ExitWriteLock(); } + + return found; + } + + public bool Remove(TKey2 key2) + { + bool found = false; + rwLock.EnterWriteLock(); + + try + { + // This is an O(n) operation! + TValue value; + if (Dictionary2.TryGetValue(key2, out value)) + { + foreach (KeyValuePair kvp in Dictionary1) + { + if (kvp.Value.Equals(value)) + { + Dictionary2.Remove(key2); + Dictionary1.Remove(kvp.Key); + found = true; + break; + } + } + } + } + finally { rwLock.ExitWriteLock(); } + + return found; + } + + public void Clear() + { + rwLock.EnterWriteLock(); + + try + { + Dictionary1.Clear(); + Dictionary2.Clear(); + } + finally { rwLock.ExitWriteLock(); } + } + + public int Count + { + get { return Dictionary1.Count; } + } + + public bool ContainsKey(TKey1 key) + { + return Dictionary1.ContainsKey(key); + } + + public bool ContainsKey(TKey2 key) + { + return Dictionary2.ContainsKey(key); + } + + public bool TryGetValue(TKey1 key, out TValue value) + { + bool success; + rwLock.EnterReadLock(); + + try { success = Dictionary1.TryGetValue(key, out value); } + finally { rwLock.ExitReadLock(); } + + return success; + } + + public bool TryGetValue(TKey2 key, out TValue value) + { + bool success; + rwLock.EnterReadLock(); + + try { success = Dictionary2.TryGetValue(key, out value); } + finally { rwLock.ExitReadLock(); } + + return success; + } + + public void ForEach(Action action) + { + rwLock.EnterReadLock(); + + try + { + foreach (TValue value in Dictionary1.Values) + action(value); + } + finally { rwLock.ExitReadLock(); } + } + + public void ForEach(Action> action) + { + rwLock.EnterReadLock(); + + try + { + foreach (KeyValuePair entry in Dictionary1) + action(entry); + } + finally { rwLock.ExitReadLock(); } + } + + public void ForEach(Action> action) + { + rwLock.EnterReadLock(); + + try + { + foreach (KeyValuePair entry in Dictionary2) + action(entry); + } + finally { rwLock.ExitReadLock(); } + } + + public TValue FindValue(Predicate predicate) + { + rwLock.EnterReadLock(); + try + { + foreach (TValue value in Dictionary1.Values) + { + if (predicate(value)) + return value; + } + } + finally { rwLock.ExitReadLock(); } + + return default(TValue); + } + + public IList FindAll(Predicate predicate) + { + IList list = new List(); + rwLock.EnterReadLock(); + + try + { + foreach (TValue value in Dictionary1.Values) + { + if (predicate(value)) + list.Add(value); + } + } + finally { rwLock.ExitReadLock(); } + + return list; + } + + public int RemoveAll(Predicate predicate) + { + IList list = new List(); + + rwLock.EnterUpgradeableReadLock(); + + try + { + foreach (KeyValuePair kvp in Dictionary1) + { + if (predicate(kvp.Value)) + list.Add(kvp.Key); + } + + IList list2 = new List(list.Count); + foreach (KeyValuePair kvp in Dictionary2) + { + if (predicate(kvp.Value)) + list2.Add(kvp.Key); + } + + rwLock.EnterWriteLock(); + + try + { + for (int i = 0; i < list.Count; i++) + Dictionary1.Remove(list[i]); + + for (int i = 0; i < list2.Count; i++) + Dictionary2.Remove(list2[i]); + } + finally { rwLock.ExitWriteLock(); } + } + finally { rwLock.ExitUpgradeableReadLock(); } + + return list.Count; + } + } +} diff --git a/OpenMetaverseTypes/Enums.cs b/OpenMetaverseTypes/Enums.cs new file mode 100644 index 0000000..1d4d2ae --- /dev/null +++ b/OpenMetaverseTypes/Enums.cs @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + /// + /// Attribute class that allows extra attributes to be attached to ENUMs + /// + public class EnumInfoAttribute : Attribute + { + /// Text used when presenting ENUM to user + public string Text = string.Empty; + + /// Default initializer + public EnumInfoAttribute() { } + + /// Text used when presenting ENUM to user + public EnumInfoAttribute(string text) + { + this.Text = text; + } + } + + /// + /// The different types of grid assets + /// + public enum AssetType : sbyte + { + /// Unknown asset type + Unknown = -1, + /// Texture asset, stores in JPEG2000 J2C stream format + Texture = 0, + /// Sound asset + Sound = 1, + /// Calling card for another avatar + CallingCard = 2, + /// Link to a location in world + Landmark = 3, + // Legacy script asset, you should never see one of these + //[Obsolete] + //Script = 4, + /// Collection of textures and parameters that can be + /// worn by an avatar + Clothing = 5, + /// Primitive that can contain textures, sounds, + /// scripts and more + Object = 6, + /// Notecard asset + Notecard = 7, + /// Holds a collection of inventory items + Folder = 8, + /// Root inventory folder + RootFolder = 9, + /// Linden scripting language script + LSLText = 10, + /// LSO bytecode for a script + LSLBytecode = 11, + /// Uncompressed TGA texture + TextureTGA = 12, + /// Collection of textures and shape parameters that can + /// be worn + Bodypart = 13, + /// Trash folder + TrashFolder = 14, + /// Snapshot folder + SnapshotFolder = 15, + /// Lost and found folder + LostAndFoundFolder = 16, + /// Uncompressed sound + SoundWAV = 17, + /// Uncompressed TGA non-square image, not to be used as a + /// texture + ImageTGA = 18, + /// Compressed JPEG non-square image, not to be used as a + /// texture + ImageJPEG = 19, + /// Animation + Animation = 20, + /// Sequence of animations, sounds, chat, and pauses + Gesture = 21, + /// Simstate file + Simstate = 22, + /// Contains landmarks for favorites + FavoriteFolder = 23, + /// Asset is a link to another inventory item + Link = 24, + /// Asset is a link to another inventory folder + LinkFolder = 25, + /// Beginning of the range reserved for ensembles + EnsembleStart = 26, + /// End of the range reserved for ensembles + EnsembleEnd = 45, + /// Folder containing inventory links to wearables and attachments + /// that are part of the current outfit + CurrentOutfitFolder = 46, + /// Folder containing inventory items or links to + /// inventory items of wearables and attachments + /// together make a full outfit + OutfitFolder = 47, + /// Root folder for the folders of type OutfitFolder + MyOutfitsFolder = 48, + /// Linden mesh format + Mesh = 49, + /// Marketplace direct delivery inbox ("Received Items") + Inbox = 50, + /// Marketplace direct delivery outbox + Outbox = 51, + /// + BasicRoot = 51, + } + + /// + /// Inventory Item Types, eg Script, Notecard, Folder, etc + /// + public enum InventoryType : sbyte + { + /// Unknown + Unknown = -1, + /// Texture + Texture = 0, + /// Sound + Sound = 1, + /// Calling Card + CallingCard = 2, + /// Landmark + Landmark = 3, + /* + /// Script + //[Obsolete("See LSL")] Script = 4, + /// Clothing + //[Obsolete("See Wearable")] Clothing = 5, + /// Object, both single and coalesced + */ + Object = 6, + /// Notecard + Notecard = 7, + /// + Category = 8, + /// Folder + Folder = 8, + /// + RootCategory = 9, + /// an LSL Script + LSL = 10, + /* + /// + //[Obsolete("See LSL")] LSLBytecode = 11, + /// + //[Obsolete("See Texture")] TextureTGA = 12, + /// + //[Obsolete] Bodypart = 13, + /// + //[Obsolete] Trash = 14, + */ + /// + Snapshot = 15, + /* + /// + //[Obsolete] LostAndFound = 16, + */ + /// + Attachment = 17, + /// + Wearable = 18, + /// + Animation = 19, + /// + Gesture = 20, + + /// + Mesh = 22, + } + + /// + /// Item Sale Status + /// + public enum SaleType : byte + { + /// Not for sale + Not = 0, + /// The original is for sale + Original = 1, + /// Copies are for sale + Copy = 2, + /// The contents of the object are for sale + Contents = 3 + } + + /// + /// Types of wearable assets + /// + public enum WearableType : byte + { + /// Body shape + Shape = 0, + /// Skin textures and attributes + Skin, + /// Hair + Hair, + /// Eyes + Eyes, + /// Shirt + Shirt, + /// Pants + Pants, + /// Shoes + Shoes, + /// Socks + Socks, + /// Jacket + Jacket, + /// Gloves + Gloves, + /// Undershirt + Undershirt, + /// Underpants + Underpants, + /// Skirt + Skirt, + /// Alpha mask to hide parts of the avatar + Alpha, + /// Tattoo + Tattoo, + /// Physics + Physics, + /// Invalid wearable asset + Invalid = 255 + }; +} diff --git a/OpenMetaverseTypes/EnumsPrimitive.cs b/OpenMetaverseTypes/EnumsPrimitive.cs new file mode 100644 index 0000000..86a398f --- /dev/null +++ b/OpenMetaverseTypes/EnumsPrimitive.cs @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + /// + /// Identifier code for primitive types + /// + public enum PCode : byte + { + /// None + None = 0, + /// A Primitive + Prim = 9, + /// A Avatar + Avatar = 47, + /// Linden grass + Grass = 95, + /// Linden tree + NewTree = 111, + /// A primitive that acts as the source for a particle stream + ParticleSystem = 143, + /// A Linden tree + Tree = 255 + } + + /// + /// Primary parameters for primitives such as Physics Enabled or Phantom + /// + [Flags] + public enum PrimFlags : uint + { + /// Deprecated + None = 0, + /// Whether physics are enabled for this object + Physics = 0x00000001, + /// + CreateSelected = 0x00000002, + /// + ObjectModify = 0x00000004, + /// + ObjectCopy = 0x00000008, + /// + ObjectAnyOwner = 0x00000010, + /// + ObjectYouOwner = 0x00000020, + /// + Scripted = 0x00000040, + /// Whether this object contains an active touch script + Touch = 0x00000080, + /// + ObjectMove = 0x00000100, + /// Whether this object can receive payments + Money = 0x00000200, + /// Whether this object is phantom (no collisions) + Phantom = 0x00000400, + /// + InventoryEmpty = 0x00000800, + /// + JointHinge = 0x00001000, + /// + JointP2P = 0x00002000, + /// + JointLP2P = 0x00004000, + /// Deprecated + JointWheel = 0x00008000, + /// + AllowInventoryDrop = 0x00010000, + /// + ObjectTransfer = 0x00020000, + /// + ObjectGroupOwned = 0x00040000, + /// Deprecated + ObjectYouOfficer = 0x00080000, + /// + CameraDecoupled = 0x00100000, + /// + AnimSource = 0x00200000, + /// + CameraSource = 0x00400000, + /// + CastShadows = 0x00800000, + /// Server flag, will not be sent to clients. Specifies that + /// the object is destroyed when it touches a simulator edge + DieAtEdge = 0x01000000, + /// Server flag, will not be sent to clients. Specifies that + /// the object will be returned to the owner's inventory when it + /// touches a simulator edge + ReturnAtEdge = 0x02000000, + /// Server flag, will not be sent to clients. + Sandbox = 0x04000000, + /// Server flag, will not be sent to client. Specifies that + /// the object is hovering/flying + Flying = 0x08000000, + /// + ObjectOwnerModify = 0x10000000, + /// + TemporaryOnRez = 0x20000000, + /// + Temporary = 0x40000000, + /// + ZlibCompressed = 0x80000000 + } + + /// + /// Sound flags for sounds attached to primitives + /// + [Flags] + public enum SoundFlags : byte + { + /// + None = 0, + /// + Loop = 0x01, + /// + SyncMaster = 0x02, + /// + SyncSlave = 0x04, + /// + SyncPending = 0x08, + /// + Queue = 0x10, + /// + Stop = 0x20 + } + + public enum ProfileCurve : byte + { + Circle = 0x00, + Square = 0x01, + IsoTriangle = 0x02, + EqualTriangle = 0x03, + RightTriangle = 0x04, + HalfCircle = 0x05 + } + + public enum HoleType : byte + { + Same = 0x00, + Circle = 0x10, + Square = 0x20, + Triangle = 0x30 + } + + public enum PathCurve : byte + { + Line = 0x10, + Circle = 0x20, + Circle2 = 0x30, + Test = 0x40, + Flexible = 0x80 + } + + /// + /// Material type for a primitive + /// + public enum Material : byte + { + /// + Stone = 0, + /// + Metal, + /// + Glass, + /// + Wood, + /// + Flesh, + /// + Plastic, + /// + Rubber, + /// + Light + } + + /// + /// Used in a helper function to roughly determine prim shape + /// + public enum PrimType + { + Unknown, + Box, + Cylinder, + Prism, + Sphere, + Torus, + Tube, + Ring, + Sculpt, + Mesh + } + + /// + /// Extra parameters for primitives, these flags are for features that have + /// been added after the original ObjectFlags that has all eight bits + /// reserved already + /// + [Flags] + public enum ExtraParamType : ushort + { + /// Whether this object has flexible parameters + Flexible = 0x10, + /// Whether this object has light parameters + Light = 0x20, + /// Whether this object is a sculpted prim + Sculpt = 0x30, + /// Whether this object is a light image map + LightImage = 0x40, + /// Whether this object is a mesh + Mesh = 0x60, + } + + /// + /// + /// + public enum JointType : byte + { + /// + Invalid = 0, + /// + Hinge = 1, + /// + Point = 2, + // + //[Obsolete] + //LPoint = 3, + //[Obsolete] + //Wheel = 4 + } + + /// + /// + /// + public enum SculptType : byte + { + /// + None = 0, + /// + Sphere = 1, + /// + Torus = 2, + /// + Plane = 3, + /// + Cylinder = 4, + /// + Mesh = 5, + /// + Invert = 64, + /// + Mirror = 128 + } + + /// + /// + /// + public enum FaceType : ushort + { + /// + PathBegin = 0x1 << 0, + /// + PathEnd = 0x1 << 1, + /// + InnerSide = 0x1 << 2, + /// + ProfileBegin = 0x1 << 3, + /// + ProfileEnd = 0x1 << 4, + /// + OuterSide0 = 0x1 << 5, + /// + OuterSide1 = 0x1 << 6, + /// + OuterSide2 = 0x1 << 7, + /// + OuterSide3 = 0x1 << 8 + } + + /// + /// + /// + public enum ObjectCategory + { + /// + Invalid = -1, + /// + None = 0, + /// + Owner, + /// + Group, + /// + Other, + /// + Selected, + /// + Temporary + } + + /// + /// Attachment points for objects on avatar bodies + /// + /// + /// Both InventoryObject and InventoryAttachment types can be attached + /// + public enum AttachmentPoint : byte + { + /// Right hand if object was not previously attached + [EnumInfo(Text = "Default")] + Default = 0, + /// Chest + [EnumInfo(Text = "Chest")] + Chest = 1, + /// Skull + [EnumInfo(Text = "Head")] + Skull, + /// Left shoulder + [EnumInfo(Text = "Left Shoulder")] + LeftShoulder, + /// Right shoulder + [EnumInfo(Text = "Right Shoulder")] + RightShoulder, + /// Left hand + [EnumInfo(Text = "Left Hand")] + LeftHand, + /// Right hand + [EnumInfo(Text = "Right Hand")] + RightHand, + /// Left foot + [EnumInfo(Text = "Left Foot")] + LeftFoot, + /// Right foot + [EnumInfo(Text = "Right Foot")] + RightFoot, + /// Spine + [EnumInfo(Text = "Back")] + Spine, + /// Pelvis + [EnumInfo(Text = "Pelvis")] + Pelvis, + /// Mouth + [EnumInfo(Text = "Mouth")] + Mouth, + /// Chin + [EnumInfo(Text = "Chin")] + Chin, + /// Left ear + [EnumInfo(Text = "Left Ear")] + LeftEar, + /// Right ear + [EnumInfo(Text = "Right Ear")] + RightEar, + /// Left eyeball + [EnumInfo(Text = "Left Eye")] + LeftEyeball, + /// Right eyeball + [EnumInfo(Text = "Right Eye")] + RightEyeball, + /// Nose + [EnumInfo(Text = "Nose")] + Nose, + /// Right upper arm + [EnumInfo(Text = "Right Upper Arm")] + RightUpperArm, + /// Right forearm + [EnumInfo(Text = "Right Lower Arm")] + RightForearm, + /// Left upper arm + [EnumInfo(Text = "Left Upper Arm")] + LeftUpperArm, + /// Left forearm + [EnumInfo(Text = "Left Lower Arm")] + LeftForearm, + /// Right hip + [EnumInfo(Text = "Right Hip")] + RightHip, + /// Right upper leg + [EnumInfo(Text = "Right Upper Leg")] + RightUpperLeg, + /// Right lower leg + [EnumInfo(Text = "Right Lower Leg")] + RightLowerLeg, + /// Left hip + [EnumInfo(Text = "Left Hip")] + LeftHip, + /// Left upper leg + [EnumInfo(Text = "Left Upper Leg")] + LeftUpperLeg, + /// Left lower leg + [EnumInfo(Text = "Left Lower Leg")] + LeftLowerLeg, + /// Stomach + [EnumInfo(Text = "Belly")] + Stomach, + /// Left pectoral + [EnumInfo(Text = "Left Pec")] + LeftPec, + /// Right pectoral + [EnumInfo(Text = "Right Pec")] + RightPec, + /// HUD Center position 2 + [EnumInfo(Text = "HUD Center 2")] + HUDCenter2, + /// HUD Top-right + [EnumInfo(Text = "HUD Top Right")] + HUDTopRight, + /// HUD Top + [EnumInfo(Text = "HUD Top Center")] + HUDTop, + /// HUD Top-left + [EnumInfo(Text = "HUD Top Left")] + HUDTopLeft, + /// HUD Center + [EnumInfo(Text = "HUD Center 1")] + HUDCenter, + /// HUD Bottom-left + [EnumInfo(Text = "HUD Bottom Left")] + HUDBottomLeft, + /// HUD Bottom + [EnumInfo(Text = "HUD Bottom")] + HUDBottom, + /// HUD Bottom-right + [EnumInfo(Text = "HUD Bottom Right")] + HUDBottomRight, + /// Neck + [EnumInfo(Text = "Neck")] + Neck, + /// Avatar Center + [EnumInfo(Text = "Avatar Center")] + Root, + } + + /// + /// Tree foliage types + /// + public enum Tree : byte + { + /// Pine1 tree + Pine1 = 0, + /// Oak tree + Oak, + /// Tropical Bush1 + TropicalBush1, + /// Palm1 tree + Palm1, + /// Dogwood tree + Dogwood, + /// Tropical Bush2 + TropicalBush2, + /// Palm2 tree + Palm2, + /// Cypress1 tree + Cypress1, + /// Cypress2 tree + Cypress2, + /// Pine2 tree + Pine2, + /// Plumeria + Plumeria, + /// Winter pinetree1 + WinterPine1, + /// Winter Aspen tree + WinterAspen, + /// Winter pinetree2 + WinterPine2, + /// Eucalyptus tree + Eucalyptus, + /// Fern + Fern, + /// Eelgrass + Eelgrass, + /// Sea Sword + SeaSword, + /// Kelp1 plant + Kelp1, + /// Beach grass + BeachGrass1, + /// Kelp2 plant + Kelp2 + } + + /// + /// Grass foliage types + /// + public enum Grass : byte + { + /// + Grass0 = 0, + /// + Grass1, + /// + Grass2, + /// + Grass3, + /// + Grass4, + /// + Undergrowth1 + } + + /// + /// Action associated with clicking on an object + /// + public enum ClickAction : byte + { + /// Touch object + Touch = 0, + /// Sit on object + Sit = 1, + /// Purchase object or contents + Buy = 2, + /// Pay the object + Pay = 3, + /// Open task inventory + OpenTask = 4, + /// Play parcel media + PlayMedia = 5, + /// Open parcel media + OpenMedia = 6 + } + + /// + /// Type of physics representation used for this prim in the simulator + /// + public enum PhysicsShapeType : byte + { + /// Use prim physics form this object + Prim = 0, + /// No physics, prim doesn't collide + None, + /// Use convex hull represantion of this prim + ConvexHull + } +} \ No newline at end of file diff --git a/OpenMetaverseTypes/ExpiringCache.cs b/OpenMetaverseTypes/ExpiringCache.cs new file mode 100644 index 0000000..221b09b --- /dev/null +++ b/OpenMetaverseTypes/ExpiringCache.cs @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using System.Collections.Generic; + +namespace OpenMetaverse +{ + #region TimedCacheKey Class + + class TimedCacheKey : IComparable + { + private DateTime expirationDate; + private bool slidingExpiration; + private TimeSpan slidingExpirationWindowSize; + private TKey key; + + public DateTime ExpirationDate { get { return expirationDate; } } + public TKey Key { get { return key; } } + public bool SlidingExpiration { get { return slidingExpiration; } } + public TimeSpan SlidingExpirationWindowSize { get { return slidingExpirationWindowSize; } } + + public TimedCacheKey(TKey key, DateTime expirationDate) + { + this.key = key; + this.slidingExpiration = false; + this.expirationDate = expirationDate; + } + + public TimedCacheKey(TKey key, TimeSpan slidingExpirationWindowSize) + { + this.key = key; + this.slidingExpiration = true; + this.slidingExpirationWindowSize = slidingExpirationWindowSize; + Accessed(); + } + + public void Accessed() + { + if (slidingExpiration) + expirationDate = DateTime.Now.Add(slidingExpirationWindowSize); + } + + public int CompareTo(TKey other) + { + return key.GetHashCode().CompareTo(other.GetHashCode()); + } + } + + #endregion + + public sealed class ExpiringCache + { + const double CACHE_PURGE_HZ = 1.0; + const int MAX_LOCK_WAIT = 5000; // milliseconds + + #region Private fields + + /// For thread safety + object syncRoot = new object(); + /// For thread safety + object isPurging = new object(); + + Dictionary, TValue> timedStorage = new Dictionary, TValue>(); + Dictionary> timedStorageIndex = new Dictionary>(); + private System.Timers.Timer timer = new System.Timers.Timer(TimeSpan.FromSeconds(CACHE_PURGE_HZ).TotalMilliseconds); + + #endregion + + #region Constructor + + public ExpiringCache() + { + timer.Elapsed += PurgeCache; + timer.Start(); + } + + #endregion + + #region Public methods + + public bool Add(TKey key, TValue value, double expirationSeconds) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + // This is the actual adding of the key + if (timedStorageIndex.ContainsKey(key)) + { + return false; + } + else + { + TimedCacheKey internalKey = new TimedCacheKey(key, DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds)); + timedStorage.Add(internalKey, value); + timedStorageIndex.Add(key, internalKey); + return true; + } + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Add(TKey key, TValue value, TimeSpan slidingExpiration) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + // This is the actual adding of the key + if (timedStorageIndex.ContainsKey(key)) + { + return false; + } + else + { + TimedCacheKey internalKey = new TimedCacheKey(key, slidingExpiration); + timedStorage.Add(internalKey, value); + timedStorageIndex.Add(key, internalKey); + return true; + } + } + finally { Monitor.Exit(syncRoot); } + } + + public bool AddOrUpdate(TKey key, TValue value, double expirationSeconds) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (Contains(key)) + { + Update(key, value, expirationSeconds); + return false; + } + else + { + Add(key, value, expirationSeconds); + return true; + } + } + finally { Monitor.Exit(syncRoot); } + } + + public bool AddOrUpdate(TKey key, TValue value, TimeSpan slidingExpiration) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (Contains(key)) + { + Update(key, value, slidingExpiration); + return false; + } + else + { + Add(key, value, slidingExpiration); + return true; + } + } + finally { Monitor.Exit(syncRoot); } + } + + public void Clear() + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + timedStorage.Clear(); + timedStorageIndex.Clear(); + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Contains(TKey key) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + return timedStorageIndex.ContainsKey(key); + } + finally { Monitor.Exit(syncRoot); } + } + + public int Count + { + get + { + return timedStorage.Count; + } + } + + public object this[TKey key] + { + get + { + TValue o; + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (timedStorageIndex.ContainsKey(key)) + { + TimedCacheKey tkey = timedStorageIndex[key]; + o = timedStorage[tkey]; + timedStorage.Remove(tkey); + tkey.Accessed(); + timedStorage.Add(tkey, o); + return o; + } + else + { + throw new ArgumentException("Key not found in the cache"); + } + } + finally { Monitor.Exit(syncRoot); } + } + } + + public bool Remove(TKey key) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (timedStorageIndex.ContainsKey(key)) + { + timedStorage.Remove(timedStorageIndex[key]); + timedStorageIndex.Remove(key); + return true; + } + else + { + return false; + } + } + finally { Monitor.Exit(syncRoot); } + } + + public bool TryGetValue(TKey key, out TValue value) + { + TValue o; + + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (timedStorageIndex.ContainsKey(key)) + { + TimedCacheKey tkey = timedStorageIndex[key]; + o = timedStorage[tkey]; + timedStorage.Remove(tkey); + tkey.Accessed(); + timedStorage.Add(tkey, o); + value = o; + return true; + } + } + finally { Monitor.Exit(syncRoot); } + + value = default(TValue); + return false; + } + + public bool Update(TKey key, TValue value) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (timedStorageIndex.ContainsKey(key)) + { + timedStorage.Remove(timedStorageIndex[key]); + timedStorageIndex[key].Accessed(); + timedStorage.Add(timedStorageIndex[key], value); + return true; + } + else + { + return false; + } + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Update(TKey key, TValue value, double expirationSeconds) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (timedStorageIndex.ContainsKey(key)) + { + timedStorage.Remove(timedStorageIndex[key]); + timedStorageIndex.Remove(key); + } + else + { + return false; + } + + TimedCacheKey internalKey = new TimedCacheKey(key, DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds)); + timedStorage.Add(internalKey, value); + timedStorageIndex.Add(key, internalKey); + return true; + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Update(TKey key, TValue value, TimeSpan slidingExpiration) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + if (timedStorageIndex.ContainsKey(key)) + { + timedStorage.Remove(timedStorageIndex[key]); + timedStorageIndex.Remove(key); + } + else + { + return false; + } + + TimedCacheKey internalKey = new TimedCacheKey(key, slidingExpiration); + timedStorage.Add(internalKey, value); + timedStorageIndex.Add(key, internalKey); + return true; + } + finally { Monitor.Exit(syncRoot); } + } + + public void CopyTo(Array array, int startIndex) + { + // Error checking + if (array == null) { throw new ArgumentNullException("array"); } + + if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex", "startIndex must be >= 0."); } + + if (array.Rank > 1) { throw new ArgumentException("array must be of Rank 1 (one-dimensional)", "array"); } + if (startIndex >= array.Length) { throw new ArgumentException("startIndex must be less than the length of the array.", "startIndex"); } + if (Count > array.Length - startIndex) { throw new ArgumentException("There is not enough space from startIndex to the end of the array to accomodate all items in the cache."); } + + // Copy the data to the array (in a thread-safe manner) + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + foreach (object o in timedStorage) + { + array.SetValue(o, startIndex); + startIndex++; + } + } + finally { Monitor.Exit(syncRoot); } + } + + #endregion + + #region Private methods + + /// + /// Purges expired objects from the cache. Called automatically by the purge timer. + /// + private void PurgeCache(object sender, System.Timers.ElapsedEventArgs e) + { + // Only let one thread purge at once - a buildup could cause a crash + // This could cause the purge to be delayed while there are lots of read/write ops + // happening on the cache + if (!Monitor.TryEnter(isPurging)) + return; + + DateTime signalTime = DateTime.UtcNow; + + try + { + // If we fail to acquire a lock on the synchronization root after MAX_LOCK_WAIT, skip this purge cycle + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + return; + try + { + Lazy> expiredItems = new Lazy>(); + + foreach (TimedCacheKey timedKey in timedStorage.Keys) + { + if (timedKey.ExpirationDate < signalTime) + { + // Mark the object for purge + expiredItems.Value.Add(timedKey.Key); + } + else + { + break; + } + } + + if (expiredItems.IsValueCreated) + { + foreach (TKey key in expiredItems.Value) + { + TimedCacheKey timedKey = timedStorageIndex[key]; + timedStorageIndex.Remove(timedKey.Key); + timedStorage.Remove(timedKey); + } + } + } + finally { Monitor.Exit(syncRoot); } + } + finally { Monitor.Exit(isPurging); } + } + + #endregion + } +} diff --git a/OpenMetaverseTypes/Lazy.cs b/OpenMetaverseTypes/Lazy.cs new file mode 100644 index 0000000..30ff039 --- /dev/null +++ b/OpenMetaverseTypes/Lazy.cs @@ -0,0 +1,100 @@ +/* + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace OpenMetaverse +{ + public class Lazy + { + private T _value = default(T); + private volatile bool _isValueCreated = false; + private Func _valueFactory = null; + private object _lock; + + public bool IsValueCreated { get { return _isValueCreated; } } + + public Lazy() + : this(() => Activator.CreateInstance()) + { + } + + public Lazy(bool isThreadSafe) + : this(() => Activator.CreateInstance(), isThreadSafe) + { + } + + public Lazy(Func valueFactory) : + this(valueFactory, true) + { + } + + public Lazy(Func valueFactory, bool isThreadSafe) + { + if (isThreadSafe) + { + this._lock = new object(); + } + + this._valueFactory = valueFactory; + } + + + public T Value + { + get + { + if (!this._isValueCreated) + { + if (this._lock != null) + { + Monitor.Enter(this._lock); + } + + try + { + T value = this._valueFactory.Invoke(); + this._valueFactory = null; + Thread.MemoryBarrier(); + this._value = value; + this._isValueCreated = true; + } + finally + { + if (this._lock != null) + { + Monitor.Exit(this._lock); + } + } + } + return this._value; + } + } + } +} diff --git a/OpenMetaverseTypes/LocklessQueue.cs b/OpenMetaverseTypes/LocklessQueue.cs new file mode 100644 index 0000000..bd42af4 --- /dev/null +++ b/OpenMetaverseTypes/LocklessQueue.cs @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; + +namespace OpenMetaverse +{ + /// + /// A thread-safe lockless queue that supports multiple readers and + /// multiple writers + /// + public sealed class LocklessQueue + { + /// + /// Provides a node container for data in a singly linked list + /// + private sealed class SingleLinkNode + { + /// Pointer to the next node in list + public SingleLinkNode Next; + /// The data contained by the node + public T Item; + + /// + /// Constructor + /// + public SingleLinkNode() { } + + /// + /// Constructor + /// + public SingleLinkNode(T item) + { + this.Item = item; + } + } + + /// Queue head + SingleLinkNode head; + /// Queue tail + SingleLinkNode tail; + /// Queue item count + int count; + + /// Gets the current number of items in the queue. Since this + /// is a lockless collection this value should be treated as a close + /// estimate + public int Count { get { return count; } } + + /// + /// Constructor + /// + public LocklessQueue() + { + count = 0; + head = tail = new SingleLinkNode(); + } + + /// + /// Enqueue an item + /// + /// Item to enqeue + public void Enqueue(T item) + { + SingleLinkNode newNode = new SingleLinkNode { Item = item }; + + while (true) + { + SingleLinkNode oldTail = tail; + SingleLinkNode oldTailNext = oldTail.Next; + + if (tail == oldTail) + { + if (oldTailNext != null) + { + CAS(ref tail, oldTail, oldTailNext); + } + else if (CAS(ref tail.Next, null, newNode)) + { + CAS(ref tail, oldTail, newNode); + Interlocked.Increment(ref count); + return; + } + } + } + } + + /// + /// Try to dequeue an item + /// + /// Dequeued item if the dequeue was successful + /// True if an item was successfully deqeued, otherwise false + public bool TryDequeue(out T item) + { + while (true) + { + SingleLinkNode oldHead = head; + SingleLinkNode oldHeadNext = oldHead.Next; + + if (oldHead == head) + { + if (oldHeadNext == null) + { + item = default(T); + count = 0; + return false; + } + if (CAS(ref head, oldHead, oldHeadNext)) + { + item = oldHeadNext.Item; + Interlocked.Decrement(ref count); + return true; + } + } + } + } + + private static bool CAS(ref SingleLinkNode location, SingleLinkNode comparand, SingleLinkNode newValue) + { + return + (object)comparand == + (object)Interlocked.CompareExchange(ref location, newValue, comparand); + } + } +} \ No newline at end of file diff --git a/OpenMetaverseTypes/Matrix4.cs b/OpenMetaverseTypes/Matrix4.cs new file mode 100644 index 0000000..a8d6816 --- /dev/null +++ b/OpenMetaverseTypes/Matrix4.cs @@ -0,0 +1,1262 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.InteropServices; + +namespace OpenMetaverse +{ + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Matrix4 : IEquatable + { + public float M11, M12, M13, M14; + public float M21, M22, M23, M24; + public float M31, M32, M33, M34; + public float M41, M42, M43, M44; + + #region Properties + + public Vector3 AtAxis + { + get + { + return new Vector3(M11, M21, M31); + } + set + { + M11 = value.X; + M21 = value.Y; + M31 = value.Z; + } + } + + public Vector3 LeftAxis + { + get + { + return new Vector3(M12, M22, M32); + } + set + { + M12 = value.X; + M22 = value.Y; + M32 = value.Z; + } + } + + public Vector3 UpAxis + { + get + { + return new Vector3(M13, M23, M33); + } + set + { + M13 = value.X; + M23 = value.Y; + M33 = value.Z; + } + } + + #endregion Properties + + #region Constructors + + public Matrix4( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34, + float m41, float m42, float m43, float m44) + { + M11 = m11; + M12 = m12; + M13 = m13; + M14 = m14; + + M21 = m21; + M22 = m22; + M23 = m23; + M24 = m24; + + M31 = m31; + M32 = m32; + M33 = m33; + M34 = m34; + + M41 = m41; + M42 = m42; + M43 = m43; + M44 = m44; + } + + public Matrix4(float roll, float pitch, float yaw) + { + this = CreateFromEulers(roll, pitch, yaw); + } + + public Matrix4(Matrix4 m) + { + M11 = m.M11; + M12 = m.M12; + M13 = m.M13; + M14 = m.M14; + + M21 = m.M21; + M22 = m.M22; + M23 = m.M23; + M24 = m.M24; + + M31 = m.M31; + M32 = m.M32; + M33 = m.M33; + M34 = m.M34; + + M41 = m.M41; + M42 = m.M42; + M43 = m.M43; + M44 = m.M44; + } + + #endregion Constructors + + #region Public Methods + + public float Determinant() + { + return + M14 * M23 * M32 * M41 - M13 * M24 * M32 * M41 - M14 * M22 * M33 * M41 + M12 * M24 * M33 * M41 + + M13 * M22 * M34 * M41 - M12 * M23 * M34 * M41 - M14 * M23 * M31 * M42 + M13 * M24 * M31 * M42 + + M14 * M21 * M33 * M42 - M11 * M24 * M33 * M42 - M13 * M21 * M34 * M42 + M11 * M23 * M34 * M42 + + M14 * M22 * M31 * M43 - M12 * M24 * M31 * M43 - M14 * M21 * M32 * M43 + M11 * M24 * M32 * M43 + + M12 * M21 * M34 * M43 - M11 * M22 * M34 * M43 - M13 * M22 * M31 * M44 + M12 * M23 * M31 * M44 + + M13 * M21 * M32 * M44 - M11 * M23 * M32 * M44 - M12 * M21 * M33 * M44 + M11 * M22 * M33 * M44; + } + + public float Determinant3x3() + { + float det = 0f; + + float diag1 = M11 * M22 * M33; + float diag2 = M12 * M32 * M31; + float diag3 = M13 * M21 * M32; + float diag4 = M31 * M22 * M13; + float diag5 = M32 * M23 * M11; + float diag6 = M33 * M21 * M12; + + det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6); + + return det; + } + + public float Trace() + { + return M11 + M22 + M33 + M44; + } + + /// + /// Convert this matrix to euler rotations + /// + /// X euler angle + /// Y euler angle + /// Z euler angle + public void GetEulerAngles(out float roll, out float pitch, out float yaw) + { + double angleX, angleY, angleZ; + double cx, cy, cz; // cosines + double sx, sz; // sines + + angleY = Math.Asin(Utils.Clamp(M13, -1f, 1f)); + cy = Math.Cos(angleY); + + if (Math.Abs(cy) > 0.005f) + { + // No gimbal lock + cx = M33 / cy; + sx = (-M23) / cy; + + angleX = (float)Math.Atan2(sx, cx); + + cz = M11 / cy; + sz = (-M12) / cy; + + angleZ = (float)Math.Atan2(sz, cz); + } + else + { + // Gimbal lock + angleX = 0; + + cz = M22; + sz = M21; + + angleZ = Math.Atan2(sz, cz); + } + + // Return only positive angles in [0,360] + if (angleX < 0) angleX += 360d; + if (angleY < 0) angleY += 360d; + if (angleZ < 0) angleZ += 360d; + + roll = (float)angleX; + pitch = (float)angleY; + yaw = (float)angleZ; + } + + /// + /// Convert this matrix to a quaternion rotation + /// + /// A quaternion representation of this rotation matrix + public Quaternion GetQuaternion() + { + Quaternion quat = new Quaternion(); + float trace = Trace() + 1f; + + if (trace > Single.Epsilon) + { + float s = 0.5f / (float)Math.Sqrt(trace); + + quat.X = (M32 - M23) * s; + quat.Y = (M13 - M31) * s; + quat.Z = (M21 - M12) * s; + quat.W = 0.25f / s; + } + else + { + if (M11 > M22 && M11 > M33) + { + float s = 2.0f * (float)Math.Sqrt(1.0f + M11 - M22 - M33); + + quat.X = 0.25f * s; + quat.Y = (M12 + M21) / s; + quat.Z = (M13 + M31) / s; + quat.W = (M23 - M32) / s; + } + else if (M22 > M33) + { + float s = 2.0f * (float)Math.Sqrt(1.0f + M22 - M11 - M33); + + quat.X = (M12 + M21) / s; + quat.Y = 0.25f * s; + quat.Z = (M23 + M32) / s; + quat.W = (M13 - M31) / s; + } + else + { + float s = 2.0f * (float)Math.Sqrt(1.0f + M33 - M11 - M22); + + quat.X = (M13 + M31) / s; + quat.Y = (M23 + M32) / s; + quat.Z = 0.25f * s; + quat.W = (M12 - M21) / s; + } + } + + return quat; + } + + public bool Decompose(out Vector3 scale, out Quaternion rotation, out Vector3 translation) + { + translation.X = this.M41; + translation.Y = this.M42; + translation.Z = this.M43; + + float xs = (Math.Sign(M11 * M12 * M13 * M14) < 0) ? -1 : 1; + float ys = (Math.Sign(M21 * M22 * M23 * M24) < 0) ? -1 : 1; + float zs = (Math.Sign(M31 * M32 * M33 * M34) < 0) ? -1 : 1; + + scale.X = xs * (float)Math.Sqrt(this.M11 * this.M11 + this.M12 * this.M12 + this.M13 * this.M13); + scale.Y = ys * (float)Math.Sqrt(this.M21 * this.M21 + this.M22 * this.M22 + this.M23 * this.M23); + scale.Z = zs * (float)Math.Sqrt(this.M31 * this.M31 + this.M32 * this.M32 + this.M33 * this.M33); + + if (scale.X == 0.0 || scale.Y == 0.0 || scale.Z == 0.0) + { + rotation = Quaternion.Identity; + return false; + } + + Matrix4 m1 = new Matrix4(this.M11 / scale.X, M12 / scale.X, M13 / scale.X, 0, + this.M21 / scale.Y, M22 / scale.Y, M23 / scale.Y, 0, + this.M31 / scale.Z, M32 / scale.Z, M33 / scale.Z, 0, + 0, 0, 0, 1); + + rotation = Quaternion.CreateFromRotationMatrix(m1); + return true; + } + + #endregion Public Methods + + #region Static Methods + + public static Matrix4 Add(Matrix4 matrix1, Matrix4 matrix2) + { + Matrix4 matrix; + matrix.M11 = matrix1.M11 + matrix2.M11; + matrix.M12 = matrix1.M12 + matrix2.M12; + matrix.M13 = matrix1.M13 + matrix2.M13; + matrix.M14 = matrix1.M14 + matrix2.M14; + + matrix.M21 = matrix1.M21 + matrix2.M21; + matrix.M22 = matrix1.M22 + matrix2.M22; + matrix.M23 = matrix1.M23 + matrix2.M23; + matrix.M24 = matrix1.M24 + matrix2.M24; + + matrix.M31 = matrix1.M31 + matrix2.M31; + matrix.M32 = matrix1.M32 + matrix2.M32; + matrix.M33 = matrix1.M33 + matrix2.M33; + matrix.M34 = matrix1.M34 + matrix2.M34; + + matrix.M41 = matrix1.M41 + matrix2.M41; + matrix.M42 = matrix1.M42 + matrix2.M42; + matrix.M43 = matrix1.M43 + matrix2.M43; + matrix.M44 = matrix1.M44 + matrix2.M44; + return matrix; + } + + public static Matrix4 CreateFromAxisAngle(Vector3 axis, float angle) + { + Matrix4 matrix = new Matrix4(); + + float x = axis.X; + float y = axis.Y; + float z = axis.Z; + float sin = (float)Math.Sin(angle); + float cos = (float)Math.Cos(angle); + float xx = x * x; + float yy = y * y; + float zz = z * z; + float xy = x * y; + float xz = x * z; + float yz = y * z; + + matrix.M11 = xx + (cos * (1f - xx)); + matrix.M12 = (xy - (cos * xy)) + (sin * z); + matrix.M13 = (xz - (cos * xz)) - (sin * y); + //matrix.M14 = 0f; + + matrix.M21 = (xy - (cos * xy)) - (sin * z); + matrix.M22 = yy + (cos * (1f - yy)); + matrix.M23 = (yz - (cos * yz)) + (sin * x); + //matrix.M24 = 0f; + + matrix.M31 = (xz - (cos * xz)) + (sin * y); + matrix.M32 = (yz - (cos * yz)) - (sin * x); + matrix.M33 = zz + (cos * (1f - zz)); + //matrix.M34 = 0f; + + //matrix.M41 = matrix.M42 = matrix.M43 = 0f; + matrix.M44 = 1f; + + return matrix; + } + + /// + /// Construct a matrix from euler rotation values in radians + /// + /// X euler angle in radians + /// Y euler angle in radians + /// Z euler angle in radians + public static Matrix4 CreateFromEulers(float roll, float pitch, float yaw) + { + Matrix4 m; + + float a, b, c, d, e, f; + float ad, bd; + + a = (float)Math.Cos(roll); + b = (float)Math.Sin(roll); + c = (float)Math.Cos(pitch); + d = (float)Math.Sin(pitch); + e = (float)Math.Cos(yaw); + f = (float)Math.Sin(yaw); + + ad = a * d; + bd = b * d; + + m.M11 = c * e; + m.M12 = -c * f; + m.M13 = d; + m.M14 = 0f; + + m.M21 = bd * e + a * f; + m.M22 = -bd * f + a * e; + m.M23 = -b * c; + m.M24 = 0f; + + m.M31 = -ad * e + b * f; + m.M32 = ad * f + b * e; + m.M33 = a * c; + m.M34 = 0f; + + m.M41 = m.M42 = m.M43 = 0f; + m.M44 = 1f; + + return m; + } + + public static Matrix4 CreateFromQuaternion(Quaternion quaternion) + { + Matrix4 matrix; + + float xx = quaternion.X * quaternion.X; + float yy = quaternion.Y * quaternion.Y; + float zz = quaternion.Z * quaternion.Z; + float xy = quaternion.X * quaternion.Y; + float zw = quaternion.Z * quaternion.W; + float zx = quaternion.Z * quaternion.X; + float yw = quaternion.Y * quaternion.W; + float yz = quaternion.Y * quaternion.Z; + float xw = quaternion.X * quaternion.W; + + matrix.M11 = 1f - (2f * (yy + zz)); + matrix.M12 = 2f * (xy + zw); + matrix.M13 = 2f * (zx - yw); + matrix.M14 = 0f; + + matrix.M21 = 2f * (xy - zw); + matrix.M22 = 1f - (2f * (zz + xx)); + matrix.M23 = 2f * (yz + xw); + matrix.M24 = 0f; + + matrix.M31 = 2f * (zx + yw); + matrix.M32 = 2f * (yz - xw); + matrix.M33 = 1f - (2f * (yy + xx)); + matrix.M34 = 0f; + + matrix.M41 = matrix.M42 = matrix.M43 = 0f; + matrix.M44 = 1f; + + return matrix; + } + + public static Matrix4 CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector) + { + Matrix4 matrix; + + Vector3 z = Vector3.Normalize(cameraPosition - cameraTarget); + Vector3 x = Vector3.Normalize(Vector3.Cross(cameraUpVector, z)); + Vector3 y = Vector3.Cross(z, x); + + matrix.M11 = x.X; + matrix.M12 = y.X; + matrix.M13 = z.X; + matrix.M14 = 0f; + + matrix.M21 = x.Y; + matrix.M22 = y.Y; + matrix.M23 = z.Y; + matrix.M24 = 0f; + + matrix.M31 = x.Z; + matrix.M32 = y.Z; + matrix.M33 = z.Z; + matrix.M34 = 0f; + + matrix.M41 = -Vector3.Dot(x, cameraPosition); + matrix.M42 = -Vector3.Dot(y, cameraPosition); + matrix.M43 = -Vector3.Dot(z, cameraPosition); + matrix.M44 = 1f; + + return matrix; + } + + public static Matrix4 CreateRotationX(float radians) + { + Matrix4 matrix; + + float cos = (float)Math.Cos(radians); + float sin = (float)Math.Sin(radians); + + matrix.M11 = 1f; + matrix.M12 = 0f; + matrix.M13 = 0f; + matrix.M14 = 0f; + + matrix.M21 = 0f; + matrix.M22 = cos; + matrix.M23 = sin; + matrix.M24 = 0f; + + matrix.M31 = 0f; + matrix.M32 = -sin; + matrix.M33 = cos; + matrix.M34 = 0f; + + matrix.M41 = 0f; + matrix.M42 = 0f; + matrix.M43 = 0f; + matrix.M44 = 1f; + + return matrix; + } + + public static Matrix4 CreateRotationY(float radians) + { + Matrix4 matrix; + + float cos = (float)Math.Cos(radians); + float sin = (float)Math.Sin(radians); + + matrix.M11 = cos; + matrix.M12 = 0f; + matrix.M13 = -sin; + matrix.M14 = 0f; + + matrix.M21 = 0f; + matrix.M22 = 1f; + matrix.M23 = 0f; + matrix.M24 = 0f; + + matrix.M31 = sin; + matrix.M32 = 0f; + matrix.M33 = cos; + matrix.M34 = 0f; + + matrix.M41 = 0f; + matrix.M42 = 0f; + matrix.M43 = 0f; + matrix.M44 = 1f; + + return matrix; + } + + public static Matrix4 CreateRotationZ(float radians) + { + Matrix4 matrix; + + float cos = (float)Math.Cos(radians); + float sin = (float)Math.Sin(radians); + + matrix.M11 = cos; + matrix.M12 = sin; + matrix.M13 = 0f; + matrix.M14 = 0f; + + matrix.M21 = -sin; + matrix.M22 = cos; + matrix.M23 = 0f; + matrix.M24 = 0f; + + matrix.M31 = 0f; + matrix.M32 = 0f; + matrix.M33 = 1f; + matrix.M34 = 0f; + + matrix.M41 = 0f; + matrix.M42 = 0f; + matrix.M43 = 0f; + matrix.M44 = 1f; + + return matrix; + } + + public static Matrix4 CreateScale(Vector3 scale) + { + Matrix4 matrix; + + matrix.M11 = scale.X; + matrix.M12 = 0f; + matrix.M13 = 0f; + matrix.M14 = 0f; + + matrix.M21 = 0f; + matrix.M22 = scale.Y; + matrix.M23 = 0f; + matrix.M24 = 0f; + + matrix.M31 = 0f; + matrix.M32 = 0f; + matrix.M33 = scale.Z; + matrix.M34 = 0f; + + matrix.M41 = 0f; + matrix.M42 = 0f; + matrix.M43 = 0f; + matrix.M44 = 1f; + + return matrix; + } + + public static Matrix4 CreateTranslation(Vector3 position) + { + Matrix4 matrix; + + matrix.M11 = 1f; + matrix.M12 = 0f; + matrix.M13 = 0f; + matrix.M14 = 0f; + + matrix.M21 = 0f; + matrix.M22 = 1f; + matrix.M23 = 0f; + matrix.M24 = 0f; + + matrix.M31 = 0f; + matrix.M32 = 0f; + matrix.M33 = 1f; + matrix.M34 = 0f; + + matrix.M41 = position.X; + matrix.M42 = position.Y; + matrix.M43 = position.Z; + matrix.M44 = 1f; + + return matrix; + } + + public static Matrix4 CreateWorld(Vector3 position, Vector3 forward, Vector3 up) + { + Matrix4 result; + + // Normalize forward vector + forward.Normalize(); + + // Calculate right vector + Vector3 right = Vector3.Cross(forward, up); + right.Normalize(); + + // Recalculate up vector + up = Vector3.Cross(right, forward); + up.Normalize(); + + result.M11 = right.X; + result.M12 = right.Y; + result.M13 = right.Z; + result.M14 = 0.0f; + + result.M21 = up.X; + result.M22 = up.Y; + result.M23 = up.Z; + result.M24 = 0.0f; + + result.M31 = -forward.X; + result.M32 = -forward.Y; + result.M33 = -forward.Z; + result.M34 = 0.0f; + + result.M41 = position.X; + result.M42 = position.Y; + result.M43 = position.Z; + result.M44 = 1.0f; + + return result; + } + + public static Matrix4 Divide(Matrix4 matrix1, Matrix4 matrix2) + { + Matrix4 matrix; + + matrix.M11 = matrix1.M11 / matrix2.M11; + matrix.M12 = matrix1.M12 / matrix2.M12; + matrix.M13 = matrix1.M13 / matrix2.M13; + matrix.M14 = matrix1.M14 / matrix2.M14; + + matrix.M21 = matrix1.M21 / matrix2.M21; + matrix.M22 = matrix1.M22 / matrix2.M22; + matrix.M23 = matrix1.M23 / matrix2.M23; + matrix.M24 = matrix1.M24 / matrix2.M24; + + matrix.M31 = matrix1.M31 / matrix2.M31; + matrix.M32 = matrix1.M32 / matrix2.M32; + matrix.M33 = matrix1.M33 / matrix2.M33; + matrix.M34 = matrix1.M34 / matrix2.M34; + + matrix.M41 = matrix1.M41 / matrix2.M41; + matrix.M42 = matrix1.M42 / matrix2.M42; + matrix.M43 = matrix1.M43 / matrix2.M43; + matrix.M44 = matrix1.M44 / matrix2.M44; + + return matrix; + } + + public static Matrix4 Divide(Matrix4 matrix1, float divider) + { + Matrix4 matrix; + + float oodivider = 1f / divider; + matrix.M11 = matrix1.M11 * oodivider; + matrix.M12 = matrix1.M12 * oodivider; + matrix.M13 = matrix1.M13 * oodivider; + matrix.M14 = matrix1.M14 * oodivider; + + matrix.M21 = matrix1.M21 * oodivider; + matrix.M22 = matrix1.M22 * oodivider; + matrix.M23 = matrix1.M23 * oodivider; + matrix.M24 = matrix1.M24 * oodivider; + + matrix.M31 = matrix1.M31 * oodivider; + matrix.M32 = matrix1.M32 * oodivider; + matrix.M33 = matrix1.M33 * oodivider; + matrix.M34 = matrix1.M34 * oodivider; + + matrix.M41 = matrix1.M41 * oodivider; + matrix.M42 = matrix1.M42 * oodivider; + matrix.M43 = matrix1.M43 * oodivider; + matrix.M44 = matrix1.M44 * oodivider; + + return matrix; + } + + public static Matrix4 Lerp(Matrix4 matrix1, Matrix4 matrix2, float amount) + { + Matrix4 matrix; + + matrix.M11 = matrix1.M11 + ((matrix2.M11 - matrix1.M11) * amount); + matrix.M12 = matrix1.M12 + ((matrix2.M12 - matrix1.M12) * amount); + matrix.M13 = matrix1.M13 + ((matrix2.M13 - matrix1.M13) * amount); + matrix.M14 = matrix1.M14 + ((matrix2.M14 - matrix1.M14) * amount); + + matrix.M21 = matrix1.M21 + ((matrix2.M21 - matrix1.M21) * amount); + matrix.M22 = matrix1.M22 + ((matrix2.M22 - matrix1.M22) * amount); + matrix.M23 = matrix1.M23 + ((matrix2.M23 - matrix1.M23) * amount); + matrix.M24 = matrix1.M24 + ((matrix2.M24 - matrix1.M24) * amount); + + matrix.M31 = matrix1.M31 + ((matrix2.M31 - matrix1.M31) * amount); + matrix.M32 = matrix1.M32 + ((matrix2.M32 - matrix1.M32) * amount); + matrix.M33 = matrix1.M33 + ((matrix2.M33 - matrix1.M33) * amount); + matrix.M34 = matrix1.M34 + ((matrix2.M34 - matrix1.M34) * amount); + + matrix.M41 = matrix1.M41 + ((matrix2.M41 - matrix1.M41) * amount); + matrix.M42 = matrix1.M42 + ((matrix2.M42 - matrix1.M42) * amount); + matrix.M43 = matrix1.M43 + ((matrix2.M43 - matrix1.M43) * amount); + matrix.M44 = matrix1.M44 + ((matrix2.M44 - matrix1.M44) * amount); + + return matrix; + } + + public static Matrix4 Multiply(Matrix4 matrix1, Matrix4 matrix2) + { + return new Matrix4( + matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21 + matrix1.M13 * matrix2.M31 + matrix1.M14 * matrix2.M41, + matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22 + matrix1.M13 * matrix2.M32 + matrix1.M14 * matrix2.M42, + matrix1.M11 * matrix2.M13 + matrix1.M12 * matrix2.M23 + matrix1.M13 * matrix2.M33 + matrix1.M14 * matrix2.M43, + matrix1.M11 * matrix2.M14 + matrix1.M12 * matrix2.M24 + matrix1.M13 * matrix2.M34 + matrix1.M14 * matrix2.M44, + + matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21 + matrix1.M23 * matrix2.M31 + matrix1.M24 * matrix2.M41, + matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22 + matrix1.M23 * matrix2.M32 + matrix1.M24 * matrix2.M42, + matrix1.M21 * matrix2.M13 + matrix1.M22 * matrix2.M23 + matrix1.M23 * matrix2.M33 + matrix1.M24 * matrix2.M43, + matrix1.M21 * matrix2.M14 + matrix1.M22 * matrix2.M24 + matrix1.M23 * matrix2.M34 + matrix1.M24 * matrix2.M44, + + matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix1.M33 * matrix2.M31 + matrix1.M34 * matrix2.M41, + matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix1.M33 * matrix2.M32 + matrix1.M34 * matrix2.M42, + matrix1.M31 * matrix2.M13 + matrix1.M32 * matrix2.M23 + matrix1.M33 * matrix2.M33 + matrix1.M34 * matrix2.M43, + matrix1.M31 * matrix2.M14 + matrix1.M32 * matrix2.M24 + matrix1.M33 * matrix2.M34 + matrix1.M34 * matrix2.M44, + + matrix1.M41 * matrix2.M11 + matrix1.M42 * matrix2.M21 + matrix1.M43 * matrix2.M31 + matrix1.M44 * matrix2.M41, + matrix1.M41 * matrix2.M12 + matrix1.M42 * matrix2.M22 + matrix1.M43 * matrix2.M32 + matrix1.M44 * matrix2.M42, + matrix1.M41 * matrix2.M13 + matrix1.M42 * matrix2.M23 + matrix1.M43 * matrix2.M33 + matrix1.M44 * matrix2.M43, + matrix1.M41 * matrix2.M14 + matrix1.M42 * matrix2.M24 + matrix1.M43 * matrix2.M34 + matrix1.M44 * matrix2.M44 + ); + } + + public static Matrix4 Multiply(Matrix4 matrix1, float scaleFactor) + { + Matrix4 matrix; + matrix.M11 = matrix1.M11 * scaleFactor; + matrix.M12 = matrix1.M12 * scaleFactor; + matrix.M13 = matrix1.M13 * scaleFactor; + matrix.M14 = matrix1.M14 * scaleFactor; + + matrix.M21 = matrix1.M21 * scaleFactor; + matrix.M22 = matrix1.M22 * scaleFactor; + matrix.M23 = matrix1.M23 * scaleFactor; + matrix.M24 = matrix1.M24 * scaleFactor; + + matrix.M31 = matrix1.M31 * scaleFactor; + matrix.M32 = matrix1.M32 * scaleFactor; + matrix.M33 = matrix1.M33 * scaleFactor; + matrix.M34 = matrix1.M34 * scaleFactor; + + matrix.M41 = matrix1.M41 * scaleFactor; + matrix.M42 = matrix1.M42 * scaleFactor; + matrix.M43 = matrix1.M43 * scaleFactor; + matrix.M44 = matrix1.M44 * scaleFactor; + return matrix; + } + + public static Matrix4 Negate(Matrix4 matrix) + { + Matrix4 result; + result.M11 = -matrix.M11; + result.M12 = -matrix.M12; + result.M13 = -matrix.M13; + result.M14 = -matrix.M14; + + result.M21 = -matrix.M21; + result.M22 = -matrix.M22; + result.M23 = -matrix.M23; + result.M24 = -matrix.M24; + + result.M31 = -matrix.M31; + result.M32 = -matrix.M32; + result.M33 = -matrix.M33; + result.M34 = -matrix.M34; + + result.M41 = -matrix.M41; + result.M42 = -matrix.M42; + result.M43 = -matrix.M43; + result.M44 = -matrix.M44; + return result; + } + + public static Matrix4 Subtract(Matrix4 matrix1, Matrix4 matrix2) + { + Matrix4 matrix; + matrix.M11 = matrix1.M11 - matrix2.M11; + matrix.M12 = matrix1.M12 - matrix2.M12; + matrix.M13 = matrix1.M13 - matrix2.M13; + matrix.M14 = matrix1.M14 - matrix2.M14; + + matrix.M21 = matrix1.M21 - matrix2.M21; + matrix.M22 = matrix1.M22 - matrix2.M22; + matrix.M23 = matrix1.M23 - matrix2.M23; + matrix.M24 = matrix1.M24 - matrix2.M24; + + matrix.M31 = matrix1.M31 - matrix2.M31; + matrix.M32 = matrix1.M32 - matrix2.M32; + matrix.M33 = matrix1.M33 - matrix2.M33; + matrix.M34 = matrix1.M34 - matrix2.M34; + + matrix.M41 = matrix1.M41 - matrix2.M41; + matrix.M42 = matrix1.M42 - matrix2.M42; + matrix.M43 = matrix1.M43 - matrix2.M43; + matrix.M44 = matrix1.M44 - matrix2.M44; + return matrix; + } + + public static Matrix4 Transform(Matrix4 value, Quaternion rotation) + { + Matrix4 matrix; + + float x2 = rotation.X + rotation.X; + float y2 = rotation.Y + rotation.Y; + float z2 = rotation.Z + rotation.Z; + + float a = (1f - rotation.Y * y2) - rotation.Z * z2; + float b = rotation.X * y2 - rotation.W * z2; + float c = rotation.X * z2 + rotation.W * y2; + float d = rotation.X * y2 + rotation.W * z2; + float e = (1f - rotation.X * x2) - rotation.Z * z2; + float f = rotation.Y * z2 - rotation.W * x2; + float g = rotation.X * z2 - rotation.W * y2; + float h = rotation.Y * z2 + rotation.W * x2; + float i = (1f - rotation.X * x2) - rotation.Y * y2; + + matrix.M11 = ((value.M11 * a) + (value.M12 * b)) + (value.M13 * c); + matrix.M12 = ((value.M11 * d) + (value.M12 * e)) + (value.M13 * f); + matrix.M13 = ((value.M11 * g) + (value.M12 * h)) + (value.M13 * i); + matrix.M14 = value.M14; + + matrix.M21 = ((value.M21 * a) + (value.M22 * b)) + (value.M23 * c); + matrix.M22 = ((value.M21 * d) + (value.M22 * e)) + (value.M23 * f); + matrix.M23 = ((value.M21 * g) + (value.M22 * h)) + (value.M23 * i); + matrix.M24 = value.M24; + + matrix.M31 = ((value.M31 * a) + (value.M32 * b)) + (value.M33 * c); + matrix.M32 = ((value.M31 * d) + (value.M32 * e)) + (value.M33 * f); + matrix.M33 = ((value.M31 * g) + (value.M32 * h)) + (value.M33 * i); + matrix.M34 = value.M34; + + matrix.M41 = ((value.M41 * a) + (value.M42 * b)) + (value.M43 * c); + matrix.M42 = ((value.M41 * d) + (value.M42 * e)) + (value.M43 * f); + matrix.M43 = ((value.M41 * g) + (value.M42 * h)) + (value.M43 * i); + matrix.M44 = value.M44; + + return matrix; + } + + public static Matrix4 Transpose(Matrix4 matrix) + { + Matrix4 result; + + result.M11 = matrix.M11; + result.M12 = matrix.M21; + result.M13 = matrix.M31; + result.M14 = matrix.M41; + + result.M21 = matrix.M12; + result.M22 = matrix.M22; + result.M23 = matrix.M32; + result.M24 = matrix.M42; + + result.M31 = matrix.M13; + result.M32 = matrix.M23; + result.M33 = matrix.M33; + result.M34 = matrix.M43; + + result.M41 = matrix.M14; + result.M42 = matrix.M24; + result.M43 = matrix.M34; + result.M44 = matrix.M44; + + return result; + } + + public static Matrix4 Inverse3x3(Matrix4 matrix) + { + if (matrix.Determinant3x3() == 0f) + throw new ArgumentException("Singular matrix inverse not possible"); + + return (Adjoint3x3(matrix) / matrix.Determinant3x3()); + } + + public static Matrix4 Adjoint3x3(Matrix4 matrix) + { + Matrix4 adjointMatrix = new Matrix4(); + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + adjointMatrix[i,j] = (float)(Math.Pow(-1, i + j) * (Minor(matrix, i, j).Determinant3x3())); + } + + adjointMatrix = Transpose(adjointMatrix); + return adjointMatrix; + } + + public static Matrix4 Inverse(Matrix4 matrix) + { + if (matrix.Determinant() == 0f) + throw new ArgumentException("Singular matrix inverse not possible"); + + return (Adjoint(matrix) / matrix.Determinant()); + } + + public static Matrix4 Adjoint(Matrix4 matrix) + { + Matrix4 adjointMatrix = new Matrix4(); + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + adjointMatrix[i,j] = (float)(Math.Pow(-1, i + j) * ((Minor(matrix, i, j)).Determinant())); + } + + adjointMatrix = Transpose(adjointMatrix); + return adjointMatrix; + } + + public static Matrix4 Minor(Matrix4 matrix, int row, int col) + { + Matrix4 minor = new Matrix4(); + int m = 0, n = 0; + + for (int i = 0; i < 4; i++) + { + if (i == row) + continue; + n = 0; + for (int j = 0; j < 4; j++) + { + if (j == col) + continue; + minor[m,n] = matrix[i,j]; + n++; + } + m++; + } + + return minor; + } + + #endregion Static Methods + + #region Overrides + + public override bool Equals(object obj) + { + return (obj is Matrix4) ? this == (Matrix4)obj : false; + } + + public bool Equals(Matrix4 other) + { + return this == other; + } + + public override int GetHashCode() + { + return + M11.GetHashCode() ^ M12.GetHashCode() ^ M13.GetHashCode() ^ M14.GetHashCode() ^ + M21.GetHashCode() ^ M22.GetHashCode() ^ M23.GetHashCode() ^ M24.GetHashCode() ^ + M31.GetHashCode() ^ M32.GetHashCode() ^ M33.GetHashCode() ^ M34.GetHashCode() ^ + M41.GetHashCode() ^ M42.GetHashCode() ^ M43.GetHashCode() ^ M44.GetHashCode(); + } + + /// + /// Get a formatted string representation of the vector + /// + /// A string representation of the vector + public override string ToString() + { + return string.Format(Utils.EnUsCulture, + "|{0}, {1}, {2}, {3}|\n|{4}, {5}, {6}, {7}|\n|{8}, {9}, {10}, {11}|\n|{12}, {13}, {14}, {15}|", + M11, M12, M13, M14, M21, M22, M23, M24, M31, M32, M33, M34, M41, M42, M43, M44); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Matrix4 left, Matrix4 right) + { + return left.Equals(right); + } + + public static bool operator !=(Matrix4 left, Matrix4 right) + { + return !left.Equals(right); + } + + public static Matrix4 operator +(Matrix4 left, Matrix4 right) + { + return Add(left, right); + } + + public static Matrix4 operator -(Matrix4 matrix) + { + return Negate(matrix); + } + + public static Matrix4 operator -(Matrix4 left, Matrix4 right) + { + return Subtract(left, right); + } + + public static Matrix4 operator *(Matrix4 left, Matrix4 right) + { + return Multiply(left, right); + } + + public static Matrix4 operator *(Matrix4 left, float scalar) + { + return Multiply(left, scalar); + } + + public static Matrix4 operator /(Matrix4 left, Matrix4 right) + { + return Divide(left, right); + } + + public static Matrix4 operator /(Matrix4 matrix, float divider) + { + return Divide(matrix, divider); + } + + public Vector4 this[int row] + { + get + { + switch (row) + { + case 0: + return new Vector4(M11, M12, M13, M14); + case 1: + return new Vector4(M21, M22, M23, M24); + case 2: + return new Vector4(M31, M32, M33, M34); + case 3: + return new Vector4(M41, M42, M43, M44); + default: + throw new IndexOutOfRangeException("Matrix4 row index must be from 0-3"); + } + } + set + { + switch (row) + { + case 0: + M11 = value.X; + M12 = value.Y; + M13 = value.Z; + M14 = value.W; + break; + case 1: + M21 = value.X; + M22 = value.Y; + M23 = value.Z; + M24 = value.W; + break; + case 2: + M31 = value.X; + M32 = value.Y; + M33 = value.Z; + M34 = value.W; + break; + case 3: + M41 = value.X; + M42 = value.Y; + M43 = value.Z; + M44 = value.W; + break; + default: + throw new IndexOutOfRangeException("Matrix4 row index must be from 0-3"); + } + } + } + + public float this[int row, int column] + { + get + { + switch (row) + { + case 0: + switch (column) + { + case 0: + return M11; + case 1: + return M12; + case 2: + return M13; + case 3: + return M14; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + case 1: + switch (column) + { + case 0: + return M21; + case 1: + return M22; + case 2: + return M23; + case 3: + return M24; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + case 2: + switch (column) + { + case 0: + return M31; + case 1: + return M32; + case 2: + return M33; + case 3: + return M34; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + case 3: + switch (column) + { + case 0: + return M41; + case 1: + return M42; + case 2: + return M43; + case 3: + return M44; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + } + set + { + switch (row) + { + case 0: + switch (column) + { + case 0: + M11 = value; return; + case 1: + M12 = value; return; + case 2: + M13 = value; return; + case 3: + M14 = value; return; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + case 1: + switch (column) + { + case 0: + M21 = value; return; + case 1: + M22 = value; return; + case 2: + M23 = value; return; + case 3: + M24 = value; return; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + case 2: + switch (column) + { + case 0: + M31 = value; return; + case 1: + M32 = value; return; + case 2: + M33 = value; return; + case 3: + M34 = value; return; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + case 3: + switch (column) + { + case 0: + M41 = value; return; + case 1: + M42 = value; return; + case 2: + M43 = value; return; + case 3: + M44 = value; return; + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + default: + throw new IndexOutOfRangeException("Matrix4 row and column values must be from 0-3"); + } + } + } + + #endregion Operators + + /// A 4x4 matrix containing all zeroes + public static readonly Matrix4 Zero = new Matrix4(); + + /// A 4x4 identity matrix + public static readonly Matrix4 Identity = new Matrix4( + 1f, 0f, 0f, 0f, + 0f, 1f, 0f, 0f, + 0f, 0f, 1f, 0f, + 0f, 0f, 0f, 1f); + } +} diff --git a/OpenMetaverseTypes/OpenMetaverseTypes.dll.build b/OpenMetaverseTypes/OpenMetaverseTypes.dll.build new file mode 100644 index 0000000..61a17aa --- /dev/null +++ b/OpenMetaverseTypes/OpenMetaverseTypes.dll.build @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverseTypes/OpenMetaverseTypes.mdp b/OpenMetaverseTypes/OpenMetaverseTypes.mdp new file mode 100644 index 0000000..496aec7 --- /dev/null +++ b/OpenMetaverseTypes/OpenMetaverseTypes.mdp @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenMetaverseTypes/Quaternion.cs b/OpenMetaverseTypes/Quaternion.cs new file mode 100644 index 0000000..afb163a --- /dev/null +++ b/OpenMetaverseTypes/Quaternion.cs @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.InteropServices; +using System.Globalization; + +namespace OpenMetaverse +{ + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Quaternion : IEquatable + { + /// X value + public float X; + /// Y value + public float Y; + /// Z value + public float Z; + /// W value + public float W; + + #region Constructors + + public Quaternion(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public Quaternion(Vector3 vectorPart, float scalarPart) + { + X = vectorPart.X; + Y = vectorPart.Y; + Z = vectorPart.Z; + W = scalarPart; + } + + /// + /// Build a quaternion from normalized float values + /// + /// X value from -1.0 to 1.0 + /// Y value from -1.0 to 1.0 + /// Z value from -1.0 to 1.0 + public Quaternion(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + + float xyzsum = 1 - X * X - Y * Y - Z * Z; + W = (xyzsum > 0) ? (float)Math.Sqrt(xyzsum) : 0; + } + + /// + /// Constructor, builds a quaternion object from a byte array + /// + /// Byte array containing four four-byte floats + /// Offset in the byte array to start reading at + /// Whether the source data is normalized or + /// not. If this is true 12 bytes will be read, otherwise 16 bytes will + /// be read. + public Quaternion(byte[] byteArray, int pos, bool normalized) + { + X = Y = Z = W = 0; + FromBytes(byteArray, pos, normalized); + } + + public Quaternion(Quaternion q) + { + X = q.X; + Y = q.Y; + Z = q.Z; + W = q.W; + } + + #endregion Constructors + + #region Public Methods + + public bool ApproxEquals(Quaternion quat, float tolerance) + { + Quaternion diff = this - quat; + return (diff.LengthSquared() <= tolerance * tolerance); + } + + public float Length() + { + return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + } + + public float LengthSquared() + { + return (X * X + Y * Y + Z * Z + W * W); + } + + /// + /// Normalizes the quaternion + /// + public void Normalize() + { + this = Normalize(this); + } + + /// + /// Builds a quaternion object from a byte array + /// + /// The source byte array + /// Offset in the byte array to start reading at + /// Whether the source data is normalized or + /// not. If this is true 12 bytes will be read, otherwise 16 bytes will + /// be read. + public void FromBytes(byte[] byteArray, int pos, bool normalized) + { + if (!normalized) + { + if (!BitConverter.IsLittleEndian) + { + // Big endian architecture + byte[] conversionBuffer = new byte[16]; + + Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 16); + + Array.Reverse(conversionBuffer, 0, 4); + Array.Reverse(conversionBuffer, 4, 4); + Array.Reverse(conversionBuffer, 8, 4); + Array.Reverse(conversionBuffer, 12, 4); + + X = BitConverter.ToSingle(conversionBuffer, 0); + Y = BitConverter.ToSingle(conversionBuffer, 4); + Z = BitConverter.ToSingle(conversionBuffer, 8); + W = BitConverter.ToSingle(conversionBuffer, 12); + } + else + { + // Little endian architecture + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + W = BitConverter.ToSingle(byteArray, pos + 12); + } + } + else + { + if (!BitConverter.IsLittleEndian) + { + // Big endian architecture + byte[] conversionBuffer = new byte[16]; + + Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 12); + + Array.Reverse(conversionBuffer, 0, 4); + Array.Reverse(conversionBuffer, 4, 4); + Array.Reverse(conversionBuffer, 8, 4); + + X = BitConverter.ToSingle(conversionBuffer, 0); + Y = BitConverter.ToSingle(conversionBuffer, 4); + Z = BitConverter.ToSingle(conversionBuffer, 8); + } + else + { + // Little endian architecture + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + } + + float xyzsum = 1f - X * X - Y * Y - Z * Z; + W = (xyzsum > 0f) ? (float)Math.Sqrt(xyzsum) : 0f; + } + } + + /// + /// Normalize this quaternion and serialize it to a byte array + /// + /// A 12 byte array containing normalized X, Y, and Z floating + /// point values in order using little endian byte ordering + public byte[] GetBytes() + { + byte[] bytes = new byte[12]; + ToBytes(bytes, 0); + return bytes; + } + + /// + /// Writes the raw bytes for this quaternion to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 12 bytes before the end of the array + public void ToBytes(byte[] dest, int pos) + { + float norm = (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + + if (norm != 0f) + { + norm = 1f / norm; + + float x, y, z; + if (W >= 0f) + { + x = X; y = Y; z = Z; + } + else + { + x = -X; y = -Y; z = -Z; + } + + Buffer.BlockCopy(BitConverter.GetBytes(norm * x), 0, dest, pos + 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(norm * y), 0, dest, pos + 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(norm * z), 0, dest, pos + 8, 4); + + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(dest, pos + 0, 4); + Array.Reverse(dest, pos + 4, 4); + Array.Reverse(dest, pos + 8, 4); + } + } + else + { + throw new InvalidOperationException(String.Format( + "Quaternion {0} normalized to zero", ToString())); + } + } + + /// + /// Convert this quaternion to euler angles + /// + /// X euler angle + /// Y euler angle + /// Z euler angle + public void GetEulerAngles(out float roll, out float pitch, out float yaw) + { + roll = 0f; + pitch = 0f; + yaw = 0f; + + Quaternion t = new Quaternion(this.X * this.X, this.Y * this.Y, this.Z * this.Z, this.W * this.W); + + float m = (t.X + t.Y + t.Z + t.W); + if (Math.Abs(m) < 0.001d) return; + float n = 2 * (this.Y * this.W + this.X * this.Z); + float p = m * m - n * n; + + if (p > 0f) + { + roll = (float)Math.Atan2(2.0f * (this.X * this.W - this.Y * this.Z), (-t.X - t.Y + t.Z + t.W)); + pitch = (float)Math.Atan2(n, Math.Sqrt(p)); + yaw = (float)Math.Atan2(2.0f * (this.Z * this.W - this.X * this.Y), t.X - t.Y - t.Z + t.W); + } + else if (n > 0f) + { + roll = 0f; + pitch = (float)(Math.PI / 2d); + yaw = (float)Math.Atan2((this.Z * this.W + this.X * this.Y), 0.5f - t.X - t.Y); + } + else + { + roll = 0f; + pitch = -(float)(Math.PI / 2d); + yaw = (float)Math.Atan2((this.Z * this.W + this.X * this.Y), 0.5f - t.X - t.Z); + } + + //float sqx = X * X; + //float sqy = Y * Y; + //float sqz = Z * Z; + //float sqw = W * W; + + //// Unit will be a correction factor if the quaternion is not normalized + //float unit = sqx + sqy + sqz + sqw; + //double test = X * Y + Z * W; + + //if (test > 0.499f * unit) + //{ + // // Singularity at north pole + // yaw = 2f * (float)Math.Atan2(X, W); + // pitch = (float)Math.PI / 2f; + // roll = 0f; + //} + //else if (test < -0.499f * unit) + //{ + // // Singularity at south pole + // yaw = -2f * (float)Math.Atan2(X, W); + // pitch = -(float)Math.PI / 2f; + // roll = 0f; + //} + //else + //{ + // yaw = (float)Math.Atan2(2f * Y * W - 2f * X * Z, sqx - sqy - sqz + sqw); + // pitch = (float)Math.Asin(2f * test / unit); + // roll = (float)Math.Atan2(2f * X * W - 2f * Y * Z, -sqx + sqy - sqz + sqw); + //} + } + + /// + /// Convert this quaternion to an angle around an axis + /// + /// Unit vector describing the axis + /// Angle around the axis, in radians + public void GetAxisAngle(out Vector3 axis, out float angle) + { + Quaternion q = Normalize(this); + + float sin = (float)Math.Sqrt(1.0f - q.W * q.W); + if (sin >= 0.001) + { + float invSin = 1.0f / sin; + if (q.W < 0) invSin = -invSin; + axis = new Vector3(q.X, q.Y, q.Z) * invSin; + + angle = 2.0f * (float)Math.Acos(q.W); + if (angle > Math.PI) + angle = 2.0f * (float)Math.PI - angle; + } + else + { + axis = Vector3.UnitX; + angle = 0f; + } + } + + #endregion Public Methods + + #region Static Methods + + public static Quaternion Add(Quaternion quaternion1, Quaternion quaternion2) + { + quaternion1.X += quaternion2.X; + quaternion1.Y += quaternion2.Y; + quaternion1.Z += quaternion2.Z; + quaternion1.W += quaternion2.W; + return quaternion1; + } + + /// + /// Returns the conjugate (spatial inverse) of a quaternion + /// + public static Quaternion Conjugate(Quaternion quaternion) + { + quaternion.X = -quaternion.X; + quaternion.Y = -quaternion.Y; + quaternion.Z = -quaternion.Z; + return quaternion; + } + + /// + /// Build a quaternion from an axis and an angle of rotation around + /// that axis + /// + public static Quaternion CreateFromAxisAngle(float axisX, float axisY, float axisZ, float angle) + { + Vector3 axis = new Vector3(axisX, axisY, axisZ); + return CreateFromAxisAngle(axis, angle); + } + + /// + /// Build a quaternion from an axis and an angle of rotation around + /// that axis + /// + /// Axis of rotation + /// Angle of rotation + public static Quaternion CreateFromAxisAngle(Vector3 axis, float angle) + { + Quaternion q; + axis = Vector3.Normalize(axis); + + angle *= 0.5f; + float c = (float)Math.Cos(angle); + float s = (float)Math.Sin(angle); + + q.X = axis.X * s; + q.Y = axis.Y * s; + q.Z = axis.Z * s; + q.W = c; + + return Quaternion.Normalize(q); + } + + /// + /// Creates a quaternion from a vector containing roll, pitch, and yaw + /// in radians + /// + /// Vector representation of the euler angles in + /// radians + /// Quaternion representation of the euler angles + public static Quaternion CreateFromEulers(Vector3 eulers) + { + return CreateFromEulers(eulers.X, eulers.Y, eulers.Z); + } + + /// + /// Creates a quaternion from roll, pitch, and yaw euler angles in + /// radians + /// + /// X angle in radians + /// Y angle in radians + /// Z angle in radians + /// Quaternion representation of the euler angles + public static Quaternion CreateFromEulers(float roll, float pitch, float yaw) + { + if (roll > Utils.TWO_PI || pitch > Utils.TWO_PI || yaw > Utils.TWO_PI) + throw new ArgumentException("Euler angles must be in radians"); + + double atCos = Math.Cos(roll / 2f); + double atSin = Math.Sin(roll / 2f); + double leftCos = Math.Cos(pitch / 2f); + double leftSin = Math.Sin(pitch / 2f); + double upCos = Math.Cos(yaw / 2f); + double upSin = Math.Sin(yaw / 2f); + double atLeftCos = atCos * leftCos; + double atLeftSin = atSin * leftSin; + return new Quaternion( + (float)(atSin * leftCos * upCos + atCos * leftSin * upSin), + (float)(atCos * leftSin * upCos - atSin * leftCos * upSin), + (float)(atLeftCos * upSin + atLeftSin * upCos), + (float)(atLeftCos * upCos - atLeftSin * upSin) + ); + } + + public static Quaternion CreateFromRotationMatrix(Matrix4 matrix) + { + float num8 = (matrix.M11 + matrix.M22) + matrix.M33; + Quaternion quaternion = new Quaternion(); + if (num8 > 0f) + { + float num = (float)Math.Sqrt((double)(num8 + 1f)); + quaternion.W = num * 0.5f; + num = 0.5f / num; + quaternion.X = (matrix.M23 - matrix.M32) * num; + quaternion.Y = (matrix.M31 - matrix.M13) * num; + quaternion.Z = (matrix.M12 - matrix.M21) * num; + return quaternion; + } + if ((matrix.M11 >= matrix.M22) && (matrix.M11 >= matrix.M33)) + { + float num7 = (float)Math.Sqrt((double)(((1f + matrix.M11) - matrix.M22) - matrix.M33)); + float num4 = 0.5f / num7; + quaternion.X = 0.5f * num7; + quaternion.Y = (matrix.M12 + matrix.M21) * num4; + quaternion.Z = (matrix.M13 + matrix.M31) * num4; + quaternion.W = (matrix.M23 - matrix.M32) * num4; + return quaternion; + } + if (matrix.M22 > matrix.M33) + { + float num6 = (float)Math.Sqrt((double)(((1f + matrix.M22) - matrix.M11) - matrix.M33)); + float num3 = 0.5f / num6; + quaternion.X = (matrix.M21 + matrix.M12) * num3; + quaternion.Y = 0.5f * num6; + quaternion.Z = (matrix.M32 + matrix.M23) * num3; + quaternion.W = (matrix.M31 - matrix.M13) * num3; + return quaternion; + } + float num5 = (float)Math.Sqrt((double)(((1f + matrix.M33) - matrix.M11) - matrix.M22)); + float num2 = 0.5f / num5; + quaternion.X = (matrix.M31 + matrix.M13) * num2; + quaternion.Y = (matrix.M32 + matrix.M23) * num2; + quaternion.Z = 0.5f * num5; + quaternion.W = (matrix.M12 - matrix.M21) * num2; + + return quaternion; + } + + public static Quaternion Divide(Quaternion q1, Quaternion q2) + { + return Quaternion.Inverse(q1) * q2; + } + + public static float Dot(Quaternion q1, Quaternion q2) + { + return (q1.X * q2.X) + (q1.Y * q2.Y) + (q1.Z * q2.Z) + (q1.W * q2.W); + } + + /// + /// Conjugates and renormalizes a vector + /// + public static Quaternion Inverse(Quaternion quaternion) + { + float norm = quaternion.LengthSquared(); + + if (norm == 0f) + { + quaternion.X = quaternion.Y = quaternion.Z = quaternion.W = 0f; + } + else + { + float oonorm = 1f / norm; + quaternion = Conjugate(quaternion); + + quaternion.X *= oonorm; + quaternion.Y *= oonorm; + quaternion.Z *= oonorm; + quaternion.W *= oonorm; + } + + return quaternion; + } + + /// + /// Spherical linear interpolation between two quaternions + /// + public static Quaternion Slerp(Quaternion q1, Quaternion q2, float amount) + { + float angle = Dot(q1, q2); + + if (angle < 0f) + { + q1 *= -1f; + angle *= -1f; + } + + float scale; + float invscale; + + if ((angle + 1f) > 0.05f) + { + if ((1f - angle) >= 0.05f) + { + // slerp + float theta = (float)Math.Acos(angle); + float invsintheta = 1f / (float)Math.Sin(theta); + scale = (float)Math.Sin(theta * (1f - amount)) * invsintheta; + invscale = (float)Math.Sin(theta * amount) * invsintheta; + } + else + { + // lerp + scale = 1f - amount; + invscale = amount; + } + } + else + { + q2.X = -q1.Y; + q2.Y = q1.X; + q2.Z = -q1.W; + q2.W = q1.Z; + + scale = (float)Math.Sin(Utils.PI * (0.5f - amount)); + invscale = (float)Math.Sin(Utils.PI * amount); + } + + return (q1 * scale) + (q2 * invscale); + } + + public static Quaternion Subtract(Quaternion quaternion1, Quaternion quaternion2) + { + quaternion1.X -= quaternion2.X; + quaternion1.Y -= quaternion2.Y; + quaternion1.Z -= quaternion2.Z; + quaternion1.W -= quaternion2.W; + return quaternion1; + } + + public static Quaternion Multiply(Quaternion a, Quaternion b) + { + return new Quaternion( + a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, + a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z, + a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X, + a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z + ); + } + + public static Quaternion Multiply(Quaternion quaternion, float scaleFactor) + { + quaternion.X *= scaleFactor; + quaternion.Y *= scaleFactor; + quaternion.Z *= scaleFactor; + quaternion.W *= scaleFactor; + return quaternion; + } + + public static Quaternion Negate(Quaternion quaternion) + { + quaternion.X = -quaternion.X; + quaternion.Y = -quaternion.Y; + quaternion.Z = -quaternion.Z; + quaternion.W = -quaternion.W; + return quaternion; + } + + public static Quaternion Normalize(Quaternion q) + { + const float MAG_THRESHOLD = 0.0000001f; + float mag = q.Length(); + + // Catch very small rounding errors when normalizing + if (mag > MAG_THRESHOLD) + { + float oomag = 1f / mag; + q.X *= oomag; + q.Y *= oomag; + q.Z *= oomag; + q.W *= oomag; + } + else + { + q.X = 0f; + q.Y = 0f; + q.Z = 0f; + q.W = 1f; + } + + return q; + } + + public static Quaternion Parse(string val) + { + char[] splitChar = { ',' }; + string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); + if (split.Length == 3) + { + return new Quaternion( + float.Parse(split[0].Trim(), Utils.EnUsCulture), + float.Parse(split[1].Trim(), Utils.EnUsCulture), + float.Parse(split[2].Trim(), Utils.EnUsCulture)); + } + else + { + return new Quaternion( + float.Parse(split[0].Trim(), Utils.EnUsCulture), + float.Parse(split[1].Trim(), Utils.EnUsCulture), + float.Parse(split[2].Trim(), Utils.EnUsCulture), + float.Parse(split[3].Trim(), Utils.EnUsCulture)); + } + } + + public static bool TryParse(string val, out Quaternion result) + { + try + { + result = Parse(val); + return true; + } + catch (Exception) + { + result = new Quaternion(); + return false; + } + } + + #endregion Static Methods + + #region Overrides + + public override bool Equals(object obj) + { + return (obj is Quaternion) ? this == (Quaternion)obj : false; + } + + public bool Equals(Quaternion other) + { + return W == other.W + && X == other.X + && Y == other.Y + && Z == other.Z; + } + + public override int GetHashCode() + { + return (X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode()); + } + + public override string ToString() + { + return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}, {3}>", X, Y, Z, W); + } + + /// + /// Get a string representation of the quaternion elements with up to three + /// decimal digits and separated by spaces only + /// + /// Raw string representation of the quaternion + public string ToRawString() + { + CultureInfo enUs = new CultureInfo("en-us"); + enUs.NumberFormat.NumberDecimalDigits = 3; + + return String.Format(enUs, "{0} {1} {2} {3}", X, Y, Z, W); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Quaternion quaternion1, Quaternion quaternion2) + { + return quaternion1.Equals(quaternion2); + } + + public static bool operator !=(Quaternion quaternion1, Quaternion quaternion2) + { + return !(quaternion1 == quaternion2); + } + + public static Quaternion operator +(Quaternion quaternion1, Quaternion quaternion2) + { + return Add(quaternion1, quaternion2); + } + + public static Quaternion operator -(Quaternion quaternion) + { + return Negate(quaternion); + } + + public static Quaternion operator -(Quaternion quaternion1, Quaternion quaternion2) + { + return Subtract(quaternion1, quaternion2); + } + + public static Quaternion operator *(Quaternion a, Quaternion b) + { + return Multiply(a, b); + } + + public static Quaternion operator *(Quaternion quaternion, float scaleFactor) + { + return Multiply(quaternion, scaleFactor); + } + + public static Quaternion operator /(Quaternion quaternion1, Quaternion quaternion2) + { + return Divide(quaternion1, quaternion2); + } + + #endregion Operators + + /// A quaternion with a value of 0,0,0,1 + public readonly static Quaternion Identity = new Quaternion(0f, 0f, 0f, 1f); + } +} diff --git a/OpenMetaverseTypes/Ray.cs b/OpenMetaverseTypes/Ray.cs new file mode 100644 index 0000000..13f0307 --- /dev/null +++ b/OpenMetaverseTypes/Ray.cs @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + public struct Ray + { + public Vector3 Origin; + public Vector3 Direction; + + public Ray(Vector3 origin, Vector3 direction) + { + Origin = origin; + Direction = direction; + } + } +} diff --git a/OpenMetaverseTypes/ReaderWriterLockSlim.cs b/OpenMetaverseTypes/ReaderWriterLockSlim.cs new file mode 100644 index 0000000..601ac5d --- /dev/null +++ b/OpenMetaverseTypes/ReaderWriterLockSlim.cs @@ -0,0 +1,618 @@ +// +// System.Threading.ReaderWriterLockSlim.cs +// +// Authors: +// Miguel de Icaza (miguel@novell.com) +// Dick Porter (dick@ximian.com) +// Jackson Harper (jackson@ximian.com) +// Lluis Sanchez Gual (lluis@ximian.com) +// Marek Safar (marek.safar@gmail.com) +// +// Copyright 2004-2008 Novell, Inc (http://www.novell.com) +// Copyright 2003, Ximian, Inc. +// +// NoRecursion code based on the blog post from Vance Morrison: +// http://blogs.msdn.com/vancem/archive/2006/03/28/563180.aspx +// +// Recursion code based on Mono's implementation of ReaderWriterLock. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Security.Permissions; +using System.Diagnostics; +using System.Runtime.Serialization; +using System.Threading; + +namespace OpenMetaverse +{ + [Serializable] + public class LockRecursionException : Exception + { + public LockRecursionException() + : base() + { + } + + public LockRecursionException(string message) + : base(message) + { + } + + public LockRecursionException(string message, Exception e) + : base(message, e) + { + } + + protected LockRecursionException(SerializationInfo info, StreamingContext sc) + : base(info, sc) + { + } + } + + // + // This implementation is based on the light-weight + // Reader/Writer lock sample from Vance Morrison's blog: + // + // http://blogs.msdn.com/vancem/archive/2006/03/28/563180.aspx + // + // And in Mono's ReaderWriterLock + // + [HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)] + [HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] + public class ReaderWriterLockSlim : IDisposable + { + sealed class LockDetails + { + public int ThreadId; + public int ReadLocks; + } + + // Are we on a multiprocessor? + static readonly bool smp; + + // Lock specifiation for myLock: This lock protects exactly the local fields associted + // instance of MyReaderWriterLock. It does NOT protect the memory associted with the + // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent). + int myLock; + + // Who owns the lock owners > 0 => readers + // owners = -1 means there is one writer, Owners must be >= -1. + int owners; + Thread upgradable_thread; + Thread write_thread; + + // These variables allow use to avoid Setting events (which is expensive) if we don't have to. + uint numWriteWaiters; // maximum number of threads that can be doing a WaitOne on the writeEvent + uint numReadWaiters; // maximum number of threads that can be doing a WaitOne on the readEvent + uint numUpgradeWaiters; // maximum number of threads that can be doing a WaitOne on the upgradeEvent (at most 1). + + // conditions we wait on. + EventWaitHandle writeEvent; // threads waiting to aquire a write lock go here. + EventWaitHandle readEvent; // threads waiting to aquire a read lock go here (will be released in bulk) + EventWaitHandle upgradeEvent; // thread waiting to upgrade a read lock to a write lock go here (at most one) + + //int lock_owner; + + // Only set if we are a recursive lock + //Dictionary reader_locks; + + LockDetails[] read_locks = new LockDetails[8]; + + static ReaderWriterLockSlim() + { + smp = Environment.ProcessorCount > 1; + } + + public ReaderWriterLockSlim() + { + // NoRecursion (0) is the default value + } + + public void EnterReadLock() + { + TryEnterReadLock(-1); + } + + public bool TryEnterReadLock(int millisecondsTimeout) + { + if (millisecondsTimeout < Timeout.Infinite) + throw new ArgumentOutOfRangeException("millisecondsTimeout"); + + if (read_locks == null) + throw new ObjectDisposedException(null); + + if (Thread.CurrentThread == write_thread) + throw new LockRecursionException("Read lock cannot be acquired while write lock is held"); + + EnterMyLock(); + + LockDetails ld = GetReadLockDetails(Thread.CurrentThread.ManagedThreadId, true); + if (ld.ReadLocks != 0) + { + ExitMyLock(); + throw new LockRecursionException("Recursive read lock can only be aquired in SupportsRecursion mode"); + } + ++ld.ReadLocks; + + while (true) + { + // Easy case, no contention + // owners >= 0 means there might be readers (but no writer) + if (owners >= 0 && numWriteWaiters == 0) + { + owners++; + break; + } + + // If the request is to probe. + if (millisecondsTimeout == 0) + { + ExitMyLock(); + return false; + } + + // We need to wait. Mark that we have waiters and wait. + if (readEvent == null) + { + LazyCreateEvent(ref readEvent, false); + // since we left the lock, start over. + continue; + } + + if (!WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout)) + return false; + } + ExitMyLock(); + + return true; + } + + public bool TryEnterReadLock(TimeSpan timeout) + { + return TryEnterReadLock(CheckTimeout(timeout)); + } + + // + // TODO: What to do if we are releasing a ReadLock and we do not own it? + // + public void ExitReadLock() + { + EnterMyLock(); + + if (owners < 1) + { + ExitMyLock(); + throw new SynchronizationLockException("Releasing lock and no read lock taken"); + } + + --owners; + --GetReadLockDetails(Thread.CurrentThread.ManagedThreadId, false).ReadLocks; + + ExitAndWakeUpAppropriateWaiters(); + } + + public void EnterWriteLock() + { + TryEnterWriteLock(-1); + } + + public bool TryEnterWriteLock(int millisecondsTimeout) + { + if (millisecondsTimeout < Timeout.Infinite) + throw new ArgumentOutOfRangeException("millisecondsTimeout"); + + if (read_locks == null) + throw new ObjectDisposedException(null); + + if (IsWriteLockHeld) + throw new LockRecursionException(); + + EnterMyLock(); + + LockDetails ld = GetReadLockDetails(Thread.CurrentThread.ManagedThreadId, false); + if (ld != null && ld.ReadLocks > 0) + { + ExitMyLock(); + throw new LockRecursionException("Write lock cannot be acquired while read lock is held"); + } + + while (true) + { + // There is no contention, we are done + if (owners == 0) + { + // Indicate that we have a writer + owners = -1; + write_thread = Thread.CurrentThread; + break; + } + + // If we are the thread that took the Upgradable read lock + if (owners == 1 && upgradable_thread == Thread.CurrentThread) + { + owners = -1; + write_thread = Thread.CurrentThread; + break; + } + + // If the request is to probe. + if (millisecondsTimeout == 0) + { + ExitMyLock(); + return false; + } + + // We need to wait, figure out what kind of waiting. + + if (upgradable_thread == Thread.CurrentThread) + { + // We are the upgradable thread, register our interest. + + if (upgradeEvent == null) + { + LazyCreateEvent(ref upgradeEvent, false); + + // since we left the lock, start over. + continue; + } + + if (numUpgradeWaiters > 0) + { + ExitMyLock(); + throw new ApplicationException("Upgrading lock to writer lock already in process, deadlock"); + } + + if (!WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, millisecondsTimeout)) + return false; + } + else + { + if (writeEvent == null) + { + LazyCreateEvent(ref writeEvent, true); + + // since we left the lock, retry + continue; + } + if (!WaitOnEvent(writeEvent, ref numWriteWaiters, millisecondsTimeout)) + return false; + } + } + + Debug.Assert(owners == -1, "Owners is not -1"); + ExitMyLock(); + return true; + } + + public bool TryEnterWriteLock(TimeSpan timeout) + { + return TryEnterWriteLock(CheckTimeout(timeout)); + } + + public void ExitWriteLock() + { + EnterMyLock(); + + if (owners != -1) + { + ExitMyLock(); + throw new SynchronizationLockException("Calling ExitWriterLock when no write lock is held"); + } + + //Debug.Assert (numUpgradeWaiters > 0); + write_thread = upgradable_thread = null; + owners = 0; + ExitAndWakeUpAppropriateWaiters(); + } + + public void EnterUpgradeableReadLock() + { + TryEnterUpgradeableReadLock(-1); + } + + // + // Taking the Upgradable read lock is like taking a read lock + // but we limit it to a single upgradable at a time. + // + public bool TryEnterUpgradeableReadLock(int millisecondsTimeout) + { + if (millisecondsTimeout < Timeout.Infinite) + throw new ArgumentOutOfRangeException("millisecondsTimeout"); + + if (read_locks == null) + throw new ObjectDisposedException(null); + + if (IsUpgradeableReadLockHeld) + throw new LockRecursionException(); + + if (IsWriteLockHeld) + throw new LockRecursionException(); + + EnterMyLock(); + while (true) + { + if (owners == 0 && numWriteWaiters == 0 && upgradable_thread == null) + { + owners++; + upgradable_thread = Thread.CurrentThread; + break; + } + + // If the request is to probe + if (millisecondsTimeout == 0) + { + ExitMyLock(); + return false; + } + + if (readEvent == null) + { + LazyCreateEvent(ref readEvent, false); + // since we left the lock, start over. + continue; + } + + if (!WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout)) + return false; + } + + ExitMyLock(); + return true; + } + + public bool TryEnterUpgradeableReadLock(TimeSpan timeout) + { + return TryEnterUpgradeableReadLock(CheckTimeout(timeout)); + } + + public void ExitUpgradeableReadLock() + { + EnterMyLock(); + Debug.Assert(owners > 0, "Releasing an upgradable lock, but there was no reader!"); + --owners; + upgradable_thread = null; + ExitAndWakeUpAppropriateWaiters(); + } + + public void Dispose() + { + read_locks = null; + } + + public bool IsReadLockHeld + { + get { return RecursiveReadCount != 0; } + } + + public bool IsWriteLockHeld + { + get { return RecursiveWriteCount != 0; } + } + + public bool IsUpgradeableReadLockHeld + { + get { return RecursiveUpgradeCount != 0; } + } + + public int CurrentReadCount + { + get { return owners & 0xFFFFFFF; } + } + + public int RecursiveReadCount + { + get + { + EnterMyLock(); + LockDetails ld = GetReadLockDetails(Thread.CurrentThread.ManagedThreadId, false); + int count = ld == null ? 0 : ld.ReadLocks; + ExitMyLock(); + return count; + } + } + + public int RecursiveUpgradeCount + { + get { return upgradable_thread == Thread.CurrentThread ? 1 : 0; } + } + + public int RecursiveWriteCount + { + get { return write_thread == Thread.CurrentThread ? 1 : 0; } + } + + public int WaitingReadCount + { + get { return (int)numReadWaiters; } + } + + public int WaitingUpgradeCount + { + get { return (int)numUpgradeWaiters; } + } + + public int WaitingWriteCount + { + get { return (int)numWriteWaiters; } + } + + #region Private methods + void EnterMyLock() + { + if (Interlocked.CompareExchange(ref myLock, 1, 0) != 0) + EnterMyLockSpin(); + } + + void EnterMyLockSpin() + { + + for (int i = 0; ; i++) + { + if (i < 3 && smp) + Thread.SpinWait(20); // Wait a few dozen instructions to let another processor release lock. + else + Thread.Sleep(0); // Give up my quantum. + + if (Interlocked.CompareExchange(ref myLock, 1, 0) == 0) + return; + } + } + + void ExitMyLock() + { + Debug.Assert(myLock != 0, "Exiting spin lock that is not held"); + myLock = 0; + } + + bool MyLockHeld { get { return myLock != 0; } } + + /// + /// Determines the appropriate events to set, leaves the locks, and sets the events. + /// + private void ExitAndWakeUpAppropriateWaiters() + { + Debug.Assert(MyLockHeld); + + // First a writing thread waiting on being upgraded + if (owners == 1 && numUpgradeWaiters != 0) + { + // Exit before signaling to improve efficiency (wakee will need the lock) + ExitMyLock(); + // release all upgraders (however there can be at most one). + upgradeEvent.Set(); + // + // TODO: What does the following comment mean? + // two threads upgrading is a guarenteed deadlock, so we throw in that case. + } + else if (owners == 0 && numWriteWaiters > 0) + { + // Exit before signaling to improve efficiency (wakee will need the lock) + ExitMyLock(); + // release one writer. + writeEvent.Set(); + } + else if (owners >= 0 && numReadWaiters != 0) + { + // Exit before signaling to improve efficiency (wakee will need the lock) + ExitMyLock(); + // release all readers. + readEvent.Set(); + } + else + ExitMyLock(); + } + + /// + /// A routine for lazily creating a event outside the lock (so if errors + /// happen they are outside the lock and that we don't do much work + /// while holding a spin lock). If all goes well, reenter the lock and + /// set 'waitEvent' + /// + void LazyCreateEvent(ref EventWaitHandle waitEvent, bool makeAutoResetEvent) + { + Debug.Assert(MyLockHeld); + Debug.Assert(waitEvent == null); + + ExitMyLock(); + EventWaitHandle newEvent; + if (makeAutoResetEvent) + newEvent = new AutoResetEvent(false); + else + newEvent = new ManualResetEvent(false); + + EnterMyLock(); + + // maybe someone snuck in. + if (waitEvent == null) + waitEvent = newEvent; + } + + /// + /// Waits on 'waitEvent' with a timeout of 'millisceondsTimeout. + /// Before the wait 'numWaiters' is incremented and is restored before leaving this routine. + /// + bool WaitOnEvent(EventWaitHandle waitEvent, ref uint numWaiters, int millisecondsTimeout) + { + Debug.Assert(MyLockHeld); + + waitEvent.Reset(); + numWaiters++; + + bool waitSuccessful = false; + + // Do the wait outside of any lock + ExitMyLock(); + try + { + waitSuccessful = waitEvent.WaitOne(millisecondsTimeout, false); + } + finally + { + EnterMyLock(); + --numWaiters; + if (!waitSuccessful) + ExitMyLock(); + } + return waitSuccessful; + } + + static int CheckTimeout(TimeSpan timeout) + { + try + { + return checked((int)timeout.TotalMilliseconds); + } + catch (System.OverflowException) + { + throw new ArgumentOutOfRangeException("timeout"); + } + } + + LockDetails GetReadLockDetails(int threadId, bool create) + { + int i; + LockDetails ld; + for (i = 0; i < read_locks.Length; ++i) + { + ld = read_locks[i]; + if (ld == null) + break; + + if (ld.ThreadId == threadId) + return ld; + } + + if (!create) + return null; + + if (i == read_locks.Length) + Array.Resize(ref read_locks, read_locks.Length * 2); + + ld = read_locks[i] = new LockDetails(); + ld.ThreadId = threadId; + return ld; + } + #endregion + } +} diff --git a/OpenMetaverseTypes/ThreadSafeDictionary.cs b/OpenMetaverseTypes/ThreadSafeDictionary.cs new file mode 100644 index 0000000..e02fb71 --- /dev/null +++ b/OpenMetaverseTypes/ThreadSafeDictionary.cs @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenMetaverse +{ + public class ThreadSafeDictionary + { + Dictionary Dictionary; + object syncObject = new object(); + + public ThreadSafeDictionary() + { + Dictionary = new Dictionary(); + } + + public ThreadSafeDictionary(int capacity) + { + Dictionary = new Dictionary(capacity); + } + + public void Add(TKey key, TValue value) + { + lock (syncObject) + { + Dictionary[key] = value; + } + } + + public bool Remove(TKey key) + { + lock (syncObject) + { + return Dictionary.Remove(key); + } + } + + public void Clear() + { + lock (syncObject) + { + Dictionary.Clear(); + } + } + + public int Count + { + get { return Dictionary.Count; } + } + + public bool ContainsKey(TKey key) + { + return Dictionary.ContainsKey(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return Dictionary.TryGetValue(key, out value); + } + + public void ForEach(Action action) + { + lock (syncObject) + { + foreach (TValue value in Dictionary.Values) + action(value); + } + } + + public void ForEach(Action> action) + { + lock (syncObject) + { + foreach (KeyValuePair entry in Dictionary) + action(entry); + } + } + + public TValue FindValue(Predicate predicate) + { + lock (syncObject) + { + foreach (TValue value in Dictionary.Values) + { + if (predicate(value)) + return value; + } + } + + return default(TValue); + } + + public IList FindAll(Predicate predicate) + { + IList list = new List(); + + lock (syncObject) + { + foreach (TValue value in Dictionary.Values) + { + if (predicate(value)) + list.Add(value); + } + } + + return list; + } + + public int RemoveAll(Predicate predicate) + { + IList list = new List(); + + lock (syncObject) + { + foreach (KeyValuePair kvp in Dictionary) + { + if (predicate(kvp.Value)) + list.Add(kvp.Key); + } + + for (int i = 0; i < list.Count; i++) + Dictionary.Remove(list[i]); + } + + return list.Count; + } + + public TValue this[TKey key] + { + get { return Dictionary[key]; } + } + } +} diff --git a/OpenMetaverseTypes/TokenBucket.cs b/OpenMetaverseTypes/TokenBucket.cs new file mode 100644 index 0000000..18337fc --- /dev/null +++ b/OpenMetaverseTypes/TokenBucket.cs @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + /// + /// A hierarchical token bucket for bandwidth throttling. See + /// http://en.wikipedia.org/wiki/Token_bucket for more information + /// + public class TokenBucket + { + /// Parent bucket to this bucket, or null if this is a root + /// bucket + TokenBucket parent; + /// Size of the bucket in bytes. If zero, the bucket has + /// infinite capacity + int maxBurst; + /// Rate that the bucket fills, in bytes per millisecond. If + /// zero, the bucket always remains full + int tokensPerMS; + /// Number of tokens currently in the bucket + int content; + /// Time of the last drip, in system ticks + int lastDrip; + + #region Properties + + /// + /// The parent bucket of this bucket, or null if this bucket has no + /// parent. The parent bucket will limit the aggregate bandwidth of all + /// of its children buckets + /// + public TokenBucket Parent + { + get { return parent; } + } + + /// + /// Maximum burst rate in bytes per second. This is the maximum number + /// of tokens that can accumulate in the bucket at any one time + /// + public int MaxBurst + { + get { return maxBurst; } + set { maxBurst = (value >= 0 ? value : 0); } + } + + /// + /// The speed limit of this bucket in bytes per second. This is the + /// number of tokens that are added to the bucket per second + /// + /// Tokens are added to the bucket any time + /// is called, at the granularity of + /// the system tick interval (typically around 15-22ms) + public int DripRate + { + get { return tokensPerMS * 1000; } + set + { + if (value == 0) + tokensPerMS = 0; + else if (value / 1000 <= 0) + tokensPerMS = 1; // 1 byte/ms is the minimum granularity + else + tokensPerMS = value / 1000; + } + } + + /// + /// The number of bytes that can be sent at this moment. This is the + /// current number of tokens in the bucket + /// If this bucket has a parent bucket that does not have + /// enough tokens for a request, will + /// return false regardless of the content of this bucket + /// + public int Content + { + get { return content; } + } + + #endregion Properties + + /// + /// Default constructor + /// + /// Parent bucket if this is a child bucket, or + /// null if this is a root bucket + /// Maximum size of the bucket in bytes, or + /// zero if this bucket has no maximum capacity + /// Rate that the bucket fills, in bytes per + /// second. If zero, the bucket always remains full + public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) + { + this.parent = parent; + MaxBurst = maxBurst; + DripRate = dripRate; + lastDrip = Environment.TickCount & Int32.MaxValue; + } + + /// + /// Remove a given number of tokens from the bucket + /// + /// Number of tokens to remove from the bucket + /// True if the requested number of tokens were removed from + /// the bucket, otherwise false + public bool RemoveTokens(int amount) + { + bool dummy; + return RemoveTokens(amount, out dummy); + } + + /// + /// Remove a given number of tokens from the bucket + /// + /// Number of tokens to remove from the bucket + /// True if tokens were added to the bucket + /// during this call, otherwise false + /// True if the requested number of tokens were removed from + /// the bucket, otherwise false + public bool RemoveTokens(int amount, out bool dripSucceeded) + { + if (maxBurst == 0) + { + dripSucceeded = true; + return true; + } + + dripSucceeded = Drip(); + + if (content - amount >= 0) + { + if (parent != null && !parent.RemoveTokens(amount)) + return false; + + content -= amount; + return true; + } + else + { + return false; + } + } + + /// + /// Add tokens to the bucket over time. The number of tokens added each + /// call depends on the length of time that has passed since the last + /// call to Drip + /// + /// True if tokens were added to the bucket, otherwise false + private bool Drip() + { + if (tokensPerMS == 0) + { + content = maxBurst; + return true; + } + else + { + int now = Environment.TickCount & Int32.MaxValue; + int deltaMS = now - lastDrip; + + if (deltaMS <= 0) + { + if (deltaMS < 0) + lastDrip = now; + return false; + } + + int dripAmount = deltaMS * tokensPerMS; + + content = Math.Min(content + dripAmount, maxBurst); + lastDrip = now; + + return true; + } + } + } +} diff --git a/OpenMetaverseTypes/UUID.cs b/OpenMetaverseTypes/UUID.cs new file mode 100644 index 0000000..50f2731 --- /dev/null +++ b/OpenMetaverseTypes/UUID.cs @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenMetaverse +{ + /// + /// A 128-bit Universally Unique Identifier, used throughout the Second + /// Life networking protocol + /// + [Serializable] + public struct UUID : IComparable, IEquatable + { + /// The System.Guid object this struct wraps around + public Guid Guid; + + #region Constructors + + /// + /// Constructor that takes a string UUID representation + /// + /// A string representation of a UUID, case + /// insensitive and can either be hyphenated or non-hyphenated + /// UUID("11f8aa9c-b071-4242-836b-13b7abe0d489") + public UUID(string val) + { + if (String.IsNullOrEmpty(val)) + Guid = new Guid(); + else + Guid = new Guid(val); + } + + /// + /// Constructor that takes a System.Guid object + /// + /// A Guid object that contains the unique identifier + /// to be represented by this UUID + public UUID(Guid val) + { + Guid = val; + } + + /// + /// Constructor that takes a byte array containing a UUID + /// + /// Byte array containing a 16 byte UUID + /// Beginning offset in the array + public UUID(byte[] source, int pos) + { + Guid = UUID.Zero.Guid; + FromBytes(source, pos); + } + + /// + /// Constructor that takes an unsigned 64-bit unsigned integer to + /// convert to a UUID + /// + /// 64-bit unsigned integer to convert to a UUID + public UUID(ulong val) + { + byte[] end = BitConverter.GetBytes(val); + if (!BitConverter.IsLittleEndian) + Array.Reverse(end); + + Guid = new Guid(0, 0, 0, end); + } + + /// + /// Copy constructor + /// + /// UUID to copy + public UUID(UUID val) + { + Guid = val.Guid; + } + + #endregion Constructors + + #region Public Methods + + /// + /// IComparable.CompareTo implementation + /// + public int CompareTo(UUID id) + { + return Guid.CompareTo(id.Guid); + } + + /// + /// Assigns this UUID from 16 bytes out of a byte array + /// + /// Byte array containing the UUID to assign this UUID to + /// Starting position of the UUID in the byte array + public void FromBytes(byte[] source, int pos) + { + int a = (source[pos + 0] << 24) | (source[pos + 1] << 16) | (source[pos + 2] << 8) | source[pos + 3]; + short b = (short)((source[pos + 4] << 8) | source[pos + 5]); + short c = (short)((source[pos + 6] << 8) | source[pos + 7]); + + Guid = new Guid(a, b, c, source[pos + 8], source[pos + 9], source[pos + 10], source[pos + 11], + source[pos + 12], source[pos + 13], source[pos + 14], source[pos + 15]); + } + + /// + /// Returns a copy of the raw bytes for this UUID + /// + /// A 16 byte array containing this UUID + public byte[] GetBytes() + { + byte[] output = new byte[16]; + ToBytes(output, 0); + return output; + } + + /// + /// Writes the raw bytes for this UUID to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 16 bytes before the end of the array + public void ToBytes(byte[] dest, int pos) + { + byte[] bytes = Guid.ToByteArray(); + dest[pos + 0] = bytes[3]; + dest[pos + 1] = bytes[2]; + dest[pos + 2] = bytes[1]; + dest[pos + 3] = bytes[0]; + dest[pos + 4] = bytes[5]; + dest[pos + 5] = bytes[4]; + dest[pos + 6] = bytes[7]; + dest[pos + 7] = bytes[6]; + Buffer.BlockCopy(bytes, 8, dest, pos + 8, 8); + } + + /// + /// Calculate an LLCRC (cyclic redundancy check) for this UUID + /// + /// The CRC checksum for this UUID + public uint CRC() + { + uint retval = 0; + byte[] bytes = GetBytes(); + + retval += (uint)((bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]); + retval += (uint)((bytes[7] << 24) + (bytes[6] << 16) + (bytes[5] << 8) + bytes[4]); + retval += (uint)((bytes[11] << 24) + (bytes[10] << 16) + (bytes[9] << 8) + bytes[8]); + retval += (uint)((bytes[15] << 24) + (bytes[14] << 16) + (bytes[13] << 8) + bytes[12]); + + return retval; + } + + /// + /// Create a 64-bit integer representation from the second half of this UUID + /// + /// An integer created from the last eight bytes of this UUID + public ulong GetULong() + { + byte[] bytes = Guid.ToByteArray(); + + return (ulong) + ((ulong)bytes[8] + + ((ulong)bytes[9] << 8) + + ((ulong)bytes[10] << 16) + + ((ulong)bytes[12] << 24) + + ((ulong)bytes[13] << 32) + + ((ulong)bytes[13] << 40) + + ((ulong)bytes[14] << 48) + + ((ulong)bytes[15] << 56)); + } + + #endregion Public Methods + + #region Static Methods + + /// + /// Generate a UUID from a string + /// + /// A string representation of a UUID, case + /// insensitive and can either be hyphenated or non-hyphenated + /// UUID.Parse("11f8aa9c-b071-4242-836b-13b7abe0d489") + public static UUID Parse(string val) + { + return new UUID(val); + } + + /// + /// Generate a UUID from a string + /// + /// A string representation of a UUID, case + /// insensitive and can either be hyphenated or non-hyphenated + /// Will contain the parsed UUID if successful, + /// otherwise null + /// True if the string was successfully parse, otherwise false + /// UUID.TryParse("11f8aa9c-b071-4242-836b-13b7abe0d489", result) + public static bool TryParse(string val, out UUID result) + { + if (String.IsNullOrEmpty(val) || + (val[0] == '{' && val.Length != 38) || + (val.Length != 36 && val.Length != 32)) + { + result = UUID.Zero; + return false; + } + + try + { + result = Parse(val); + return true; + } + catch (Exception) + { + result = UUID.Zero; + return false; + } + } + + /// + /// Combine two UUIDs together by taking the MD5 hash of a byte array + /// containing both UUIDs + /// + /// First UUID to combine + /// Second UUID to combine + /// The UUID product of the combination + public static UUID Combine(UUID first, UUID second) + { + // Construct the buffer that MD5ed + byte[] input = new byte[32]; + Buffer.BlockCopy(first.GetBytes(), 0, input, 0, 16); + Buffer.BlockCopy(second.GetBytes(), 0, input, 16, 16); + + return new UUID(Utils.MD5(input), 0); + } + + /// + /// + /// + /// + public static UUID Random() + { + return new UUID(Guid.NewGuid()); + } + + #endregion Static Methods + + #region Overrides + + /// + /// Return a hash code for this UUID, used by .NET for hash tables + /// + /// An integer composed of all the UUID bytes XORed together + public override int GetHashCode() + { + return Guid.GetHashCode(); + } + + /// + /// Comparison function + /// + /// An object to compare to this UUID + /// True if the object is a UUID and both UUIDs are equal + public override bool Equals(object o) + { + if (!(o is UUID)) return false; + + UUID uuid = (UUID)o; + return Guid == uuid.Guid; + } + + /// + /// Comparison function + /// + /// UUID to compare to + /// True if the UUIDs are equal, otherwise false + public bool Equals(UUID uuid) + { + return Guid == uuid.Guid; + } + + /// + /// Get a hyphenated string representation of this UUID + /// + /// A string representation of this UUID, lowercase and + /// with hyphens + /// 11f8aa9c-b071-4242-836b-13b7abe0d489 + public override string ToString() + { + if (Guid == Guid.Empty) + return ZeroString; + else + return Guid.ToString(); + } + + #endregion Overrides + + #region Operators + + /// + /// Equals operator + /// + /// First UUID for comparison + /// Second UUID for comparison + /// True if the UUIDs are byte for byte equal, otherwise false + public static bool operator ==(UUID lhs, UUID rhs) + { + return lhs.Guid == rhs.Guid; + } + + /// + /// Not equals operator + /// + /// First UUID for comparison + /// Second UUID for comparison + /// True if the UUIDs are not equal, otherwise true + public static bool operator !=(UUID lhs, UUID rhs) + { + return !(lhs == rhs); + } + + /// + /// XOR operator + /// + /// First UUID + /// Second UUID + /// A UUID that is a XOR combination of the two input UUIDs + public static UUID operator ^(UUID lhs, UUID rhs) + { + byte[] lhsbytes = lhs.GetBytes(); + byte[] rhsbytes = rhs.GetBytes(); + byte[] output = new byte[16]; + + for (int i = 0; i < 16; i++) + { + output[i] = (byte)(lhsbytes[i] ^ rhsbytes[i]); + } + + return new UUID(output, 0); + } + + /// + /// String typecasting operator + /// + /// A UUID in string form. Case insensitive, + /// hyphenated or non-hyphenated + /// A UUID built from the string representation + public static explicit operator UUID(string val) + { + return new UUID(val); + } + + #endregion Operators + + /// An UUID with a value of all zeroes + public static readonly UUID Zero = new UUID(); + + /// A cache of UUID.Zero as a string to optimize a common path + private static readonly string ZeroString = Guid.Empty.ToString(); + } +} diff --git a/OpenMetaverseTypes/Utils.cs b/OpenMetaverseTypes/Utils.cs new file mode 100644 index 0000000..0109381 --- /dev/null +++ b/OpenMetaverseTypes/Utils.cs @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Text; + +namespace OpenMetaverse +{ + public static partial class Utils + { + /// + /// Operating system + /// + public enum Platform + { + /// Unknown + Unknown, + /// Microsoft Windows + Windows, + /// Microsoft Windows CE + WindowsCE, + /// Linux + Linux, + /// Apple OSX + OSX + } + + /// + /// Runtime platform + /// + public enum Runtime + { + /// .NET runtime + Windows, + /// Mono runtime: http://www.mono-project.com/ + Mono + } + + public const float E = (float)Math.E; + public const float LOG10E = 0.4342945f; + public const float LOG2E = 1.442695f; + public const float PI = (float)Math.PI; + public const float TWO_PI = (float)(Math.PI * 2.0d); + public const float PI_OVER_TWO = (float)(Math.PI / 2.0d); + public const float PI_OVER_FOUR = (float)(Math.PI / 4.0d); + /// Used for converting degrees to radians + public const float DEG_TO_RAD = (float)(Math.PI / 180.0d); + /// Used for converting radians to degrees + public const float RAD_TO_DEG = (float)(180.0d / Math.PI); + + /// Provide a single instance of the CultureInfo class to + /// help parsing in situations where the grid assumes an en-us + /// culture + public static readonly System.Globalization.CultureInfo EnUsCulture = + new System.Globalization.CultureInfo("en-us"); + + /// UNIX epoch in DateTime format + public static readonly DateTime Epoch = new DateTime(1970, 1, 1); + + public static readonly byte[] EmptyBytes = new byte[0]; + + /// Provide a single instance of the MD5 class to avoid making + /// duplicate copies and handle thread safety + private static readonly System.Security.Cryptography.MD5 MD5Builder = + new System.Security.Cryptography.MD5CryptoServiceProvider(); + + /// Provide a single instance of the SHA-1 class to avoid + /// making duplicate copies and handle thread safety + private static readonly System.Security.Cryptography.SHA1 SHA1Builder = + new System.Security.Cryptography.SHA1CryptoServiceProvider(); + + private static readonly System.Security.Cryptography.SHA256 SHA256Builder = + new System.Security.Cryptography.SHA256Managed(); + + /// Provide a single instance of a random number generator + /// to avoid making duplicate copies and handle thread safety + private static readonly Random RNG = new Random(); + + #region Math + + /// + /// Clamp a given value between a range + /// + /// Value to clamp + /// Minimum allowable value + /// Maximum allowable value + /// A value inclusively between lower and upper + public static float Clamp(float value, float min, float max) + { + // First we check to see if we're greater than the max + value = (value > max) ? max : value; + + // Then we check to see if we're less than the min. + value = (value < min) ? min : value; + + // There's no check to see if min > max. + return value; + } + + /// + /// Clamp a given value between a range + /// + /// Value to clamp + /// Minimum allowable value + /// Maximum allowable value + /// A value inclusively between lower and upper + public static double Clamp(double value, double min, double max) + { + // First we check to see if we're greater than the max + value = (value > max) ? max : value; + + // Then we check to see if we're less than the min. + value = (value < min) ? min : value; + + // There's no check to see if min > max. + return value; + } + + /// + /// Clamp a given value between a range + /// + /// Value to clamp + /// Minimum allowable value + /// Maximum allowable value + /// A value inclusively between lower and upper + public static int Clamp(int value, int min, int max) + { + // First we check to see if we're greater than the max + value = (value > max) ? max : value; + + // Then we check to see if we're less than the min. + value = (value < min) ? min : value; + + // There's no check to see if min > max. + return value; + } + + /// + /// Round a floating-point value to the nearest integer + /// + /// Floating point number to round + /// Integer + public static int Round(float val) + { + return (int)Math.Floor(val + 0.5f); + } + + /// + /// Test if a single precision float is a finite number + /// + public static bool IsFinite(float value) + { + return !(Single.IsNaN(value) || Single.IsInfinity(value)); + } + + /// + /// Test if a double precision float is a finite number + /// + public static bool IsFinite(double value) + { + return !(Double.IsNaN(value) || Double.IsInfinity(value)); + } + + /// + /// Get the distance between two floating-point values + /// + /// First value + /// Second value + /// The distance between the two values + public static float Distance(float value1, float value2) + { + return Math.Abs(value1 - value2); + } + + public static float Hermite(float value1, float tangent1, float value2, float tangent2, float amount) + { + // All transformed to double not to lose precission + // Otherwise, for high numbers of param:amount the result is NaN instead of Infinity + double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result; + double sCubed = s * s * s; + double sSquared = s * s; + + if (amount == 0f) + result = value1; + else if (amount == 1f) + result = value2; + else + result = (2d * v1 - 2d * v2 + t2 + t1) * sCubed + + (3d * v2 - 3d * v1 - 2d * t1 - t2) * sSquared + + t1 * s + v1; + return (float)result; + } + + public static double Hermite(double value1, double tangent1, double value2, double tangent2, double amount) + { + // All transformed to double not to lose precission + // Otherwise, for high numbers of param:amount the result is NaN instead of Infinity + double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result; + double sCubed = s * s * s; + double sSquared = s * s; + + if (amount == 0d) + result = value1; + else if (amount == 1f) + result = value2; + else + result = (2d * v1 - 2d * v2 + t2 + t1) * sCubed + + (3d * v2 - 3d * v1 - 2d * t1 - t2) * sSquared + + t1 * s + v1; + return result; + } + + public static float Lerp(float value1, float value2, float amount) + { + return value1 + (value2 - value1) * amount; + } + + public static double Lerp(double value1, double value2, double amount) + { + return value1 + (value2 - value1) * amount; + } + + public static float SmoothStep(float value1, float value2, float amount) + { + // It is expected that 0 < amount < 1 + // If amount < 0, return value1 + // If amount > 1, return value2 + float result = Utils.Clamp(amount, 0f, 1f); + return Utils.Hermite(value1, 0f, value2, 0f, result); + } + + public static double SmoothStep(double value1, double value2, double amount) + { + // It is expected that 0 < amount < 1 + // If amount < 0, return value1 + // If amount > 1, return value2 + double result = Utils.Clamp(amount, 0f, 1f); + return Utils.Hermite(value1, 0f, value2, 0f, result); + } + + public static float ToDegrees(float radians) + { + // This method uses double precission internally, + // though it returns single float + // Factor = 180 / pi + return (float)(radians * 57.295779513082320876798154814105); + } + + public static float ToRadians(float degrees) + { + // This method uses double precission internally, + // though it returns single float + // Factor = pi / 180 + return (float)(degrees * 0.017453292519943295769236907684886); + } + + /// + /// Compute the MD5 hash for a byte array + /// + /// Byte array to compute the hash for + /// MD5 hash of the input data + public static byte[] MD5(byte[] data) + { + lock (MD5Builder) + return MD5Builder.ComputeHash(data); + } + + /// + /// Compute the SHA1 hash for a byte array + /// + /// Byte array to compute the hash for + /// SHA1 hash of the input data + public static byte[] SHA1(byte[] data) + { + lock (SHA1Builder) + return SHA1Builder.ComputeHash(data); + } + + /// + /// Calculate the SHA1 hash of a given string + /// + /// The string to hash + /// The SHA1 hash as a string + public static string SHA1String(string value) + { + StringBuilder digest = new StringBuilder(40); + byte[] hash = SHA1(Encoding.UTF8.GetBytes(value)); + + // Convert the hash to a hex string + foreach (byte b in hash) + digest.AppendFormat(Utils.EnUsCulture, "{0:x2}", b); + + return digest.ToString(); + } + + /// + /// Compute the SHA256 hash for a byte array + /// + /// Byte array to compute the hash for + /// SHA256 hash of the input data + public static byte[] SHA256(byte[] data) + { + lock (SHA256Builder) + return SHA256Builder.ComputeHash(data); + } + + /// + /// Calculate the SHA256 hash of a given string + /// + /// The string to hash + /// The SHA256 hash as a string + public static string SHA256String(string value) + { + StringBuilder digest = new StringBuilder(64); + byte[] hash = SHA256(Encoding.UTF8.GetBytes(value)); + + // Convert the hash to a hex string + foreach (byte b in hash) + digest.AppendFormat(Utils.EnUsCulture, "{0:x2}", b); + + return digest.ToString(); + } + + /// + /// Calculate the MD5 hash of a given string + /// + /// The password to hash + /// An MD5 hash in string format, with $1$ prepended + public static string MD5(string password) + { + StringBuilder digest = new StringBuilder(32); + byte[] hash = MD5(ASCIIEncoding.Default.GetBytes(password)); + + // Convert the hash to a hex string + foreach (byte b in hash) + digest.AppendFormat(Utils.EnUsCulture, "{0:x2}", b); + + return "$1$" + digest.ToString(); + } + + /// + /// Calculate the MD5 hash of a given string + /// + /// The string to hash + /// The MD5 hash as a string + public static string MD5String(string value) + { + StringBuilder digest = new StringBuilder(32); + byte[] hash = MD5(Encoding.UTF8.GetBytes(value)); + + // Convert the hash to a hex string + foreach (byte b in hash) + digest.AppendFormat(Utils.EnUsCulture, "{0:x2}", b); + + return digest.ToString(); + } + + /// + /// Generate a random double precision floating point value + /// + /// Random value of type double + public static double RandomDouble() + { + lock (RNG) + return RNG.NextDouble(); + } + + #endregion Math + + #region Platform + + /// + /// Get the current running platform + /// + /// Enumeration of the current platform we are running on + public static Platform GetRunningPlatform() + { + const string OSX_CHECK_FILE = "/Library/Extensions.kextcache"; + + if (Environment.OSVersion.Platform == PlatformID.WinCE) + { + return Platform.WindowsCE; + } + else + { + int plat = (int)Environment.OSVersion.Platform; + + if ((plat != 4) && (plat != 128)) + { + return Platform.Windows; + } + else + { + if (System.IO.File.Exists(OSX_CHECK_FILE)) + return Platform.OSX; + else + return Platform.Linux; + } + } + } + + /// + /// Get the current running runtime + /// + /// Enumeration of the current runtime we are running on + public static Runtime GetRunningRuntime() + { + Type t = Type.GetType("Mono.Runtime"); + if (t != null) + return Runtime.Mono; + else + return Runtime.Windows; + } + + #endregion Platform + } +} diff --git a/OpenMetaverseTypes/UtilsConversions.cs b/OpenMetaverseTypes/UtilsConversions.cs new file mode 100644 index 0000000..1e658fe --- /dev/null +++ b/OpenMetaverseTypes/UtilsConversions.cs @@ -0,0 +1,1206 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Text; +using System.Reflection; + +namespace OpenMetaverse +{ + public static partial class Utils + { + #region String Arrays + + private static readonly string[] _AssetTypeNames = new string[] + { + "texture", // 0 + "sound", // 1 + "callcard", // 2 + "landmark", // 3 + "script", // 4 + "clothing", // 5 + "object", // 6 + "notecard", // 7 + "category", // 8 + "root", // 9 + "lsltext", // 10 + "lslbyte", // 11 + "txtr_tga", // 12 + "bodypart", // 13 + "trash", // 14 + "snapshot", // 15 + "lstndfnd", // 16 + "snd_wav", // 17 + "img_tga", // 18 + "jpeg", // 19 + "animatn", // 20 + "gesture", // 21 + "simstate", // 22 + "favorite", // 23 + "link", // 24 + "linkfolder", // 25 + String.Empty, // 26 + String.Empty, // 27 + String.Empty, // 28 + String.Empty, // 29 + String.Empty, // 30 + String.Empty, // 31 + String.Empty, // 32 + String.Empty, // 33 + String.Empty, // 34 + String.Empty, // 35 + String.Empty, // 36 + String.Empty, // 37 + String.Empty, // 38 + String.Empty, // 39 + String.Empty, // 40 + String.Empty, // 41 + String.Empty, // 42 + String.Empty, // 43 + String.Empty, // 44 + String.Empty, // 45 + "curoutfit", // 46 + "outfit", // 47 + "myoutfits", // 48 + "mesh", // 49 + }; + + private static readonly string[] _InventoryTypeNames = new string[] + { + "texture", // 0 + "sound", // 1 + "callcard", // 2 + "landmark", // 3 + String.Empty, // 4 + String.Empty, // 5 + "object", // 6 + "notecard", // 7 + "category", // 8 + "root", // 9 + "script", // 10 + String.Empty, // 11 + String.Empty, // 12 + String.Empty, // 13 + String.Empty, // 14 + "snapshot", // 15 + String.Empty, // 16 + "attach", // 17 + "wearable", // 18 + "animation", // 19 + "gesture", // 20 + String.Empty, // 21 + "mesh" // 22 + }; + + private static readonly string[] _SaleTypeNames = new string[] + { + "not", + "orig", + "copy", + "cntn" + }; + + private static readonly string[] _AttachmentPointNames = new string[] + { + string.Empty, + "ATTACH_CHEST", + "ATTACH_HEAD", + "ATTACH_LSHOULDER", + "ATTACH_RSHOULDER", + "ATTACH_LHAND", + "ATTACH_RHAND", + "ATTACH_LFOOT", + "ATTACH_RFOOT", + "ATTACH_BACK", + "ATTACH_PELVIS", + "ATTACH_MOUTH", + "ATTACH_CHIN", + "ATTACH_LEAR", + "ATTACH_REAR", + "ATTACH_LEYE", + "ATTACH_REYE", + "ATTACH_NOSE", + "ATTACH_RUARM", + "ATTACH_RLARM", + "ATTACH_LUARM", + "ATTACH_LLARM", + "ATTACH_RHIP", + "ATTACH_RULEG", + "ATTACH_RLLEG", + "ATTACH_LHIP", + "ATTACH_LULEG", + "ATTACH_LLLEG", + "ATTACH_BELLY", + "ATTACH_RPEC", + "ATTACH_LPEC", + "ATTACH_HUD_CENTER_2", + "ATTACH_HUD_TOP_RIGHT", + "ATTACH_HUD_TOP_CENTER", + "ATTACH_HUD_TOP_LEFT", + "ATTACH_HUD_CENTER_1", + "ATTACH_HUD_BOTTOM_LEFT", + "ATTACH_HUD_BOTTOM", + "ATTACH_HUD_BOTTOM_RIGHT" + }; + + public static bool InternStrings = false; + + #endregion String Arrays + + #region BytesTo + + /// + /// Convert the first two bytes starting in the byte array in + /// little endian ordering to a signed short integer + /// + /// An array two bytes or longer + /// A signed short integer, will be zero if a short can't be + /// read at the given position + public static short BytesToInt16(byte[] bytes) + { + return BytesToInt16(bytes, 0); + } + + /// + /// Convert the first two bytes starting at the given position in + /// little endian ordering to a signed short integer + /// + /// An array two bytes or longer + /// Position in the array to start reading + /// A signed short integer, will be zero if a short can't be + /// read at the given position + public static short BytesToInt16(byte[] bytes, int pos) + { + if (bytes.Length <= pos + 1) return 0; + return (short)(bytes[pos] + (bytes[pos + 1] << 8)); + } + + /// + /// Convert the first four bytes starting at the given position in + /// little endian ordering to a signed integer + /// + /// An array four bytes or longer + /// Position to start reading the int from + /// A signed integer, will be zero if an int can't be read + /// at the given position + public static int BytesToInt(byte[] bytes, int pos) + { + if (bytes.Length < pos + 4) return 0; + return (int)(bytes[pos + 0] + (bytes[pos + 1] << 8) + (bytes[pos + 2] << 16) + (bytes[pos + 3] << 24)); + } + + /// + /// Convert the first four bytes of the given array in little endian + /// ordering to a signed integer + /// + /// An array four bytes or longer + /// A signed integer, will be zero if the array contains + /// less than four bytes + public static int BytesToInt(byte[] bytes) + { + return BytesToInt(bytes, 0); + } + + /// + /// Convert the first eight bytes of the given array in little endian + /// ordering to a signed long integer + /// + /// An array eight bytes or longer + /// A signed long integer, will be zero if the array contains + /// less than eight bytes + public static long BytesToInt64(byte[] bytes) + { + return BytesToInt64(bytes, 0); + } + + /// + /// Convert the first eight bytes starting at the given position in + /// little endian ordering to a signed long integer + /// + /// An array eight bytes or longer + /// Position to start reading the long from + /// A signed long integer, will be zero if a long can't be read + /// at the given position + public static long BytesToInt64(byte[] bytes, int pos) + { + if (bytes.Length < pos + 8) return 0; + return (long) + ((long)bytes[pos + 0] + + ((long)bytes[pos + 1] << 8) + + ((long)bytes[pos + 2] << 16) + + ((long)bytes[pos + 3] << 24) + + ((long)bytes[pos + 4] << 32) + + ((long)bytes[pos + 5] << 40) + + ((long)bytes[pos + 6] << 48) + + ((long)bytes[pos + 7] << 56)); + } + + /// + /// Convert the first two bytes starting at the given position in + /// little endian ordering to an unsigned short + /// + /// Byte array containing the ushort + /// Position to start reading the ushort from + /// An unsigned short, will be zero if a ushort can't be read + /// at the given position + public static ushort BytesToUInt16(byte[] bytes, int pos) + { + if (bytes.Length <= pos + 1) return 0; + return (ushort)(bytes[pos] + (bytes[pos + 1] << 8)); + } + + /// + /// Convert two bytes in little endian ordering to an unsigned short + /// + /// Byte array containing the ushort + /// An unsigned short, will be zero if a ushort can't be + /// read + public static ushort BytesToUInt16(byte[] bytes) + { + return BytesToUInt16(bytes, 0); + } + + /// + /// Convert the first four bytes starting at the given position in + /// little endian ordering to an unsigned integer + /// + /// Byte array containing the uint + /// Position to start reading the uint from + /// An unsigned integer, will be zero if a uint can't be read + /// at the given position + public static uint BytesToUInt(byte[] bytes, int pos) + { + if (bytes.Length < pos + 4) return 0; + return (uint)(bytes[pos + 0] + (bytes[pos + 1] << 8) + (bytes[pos + 2] << 16) + (bytes[pos + 3] << 24)); + } + + /// + /// Convert the first four bytes of the given array in little endian + /// ordering to an unsigned integer + /// + /// An array four bytes or longer + /// An unsigned integer, will be zero if the array contains + /// less than four bytes + public static uint BytesToUInt(byte[] bytes) + { + return BytesToUInt(bytes, 0); + } + + /// + /// Convert the first eight bytes of the given array in little endian + /// ordering to an unsigned 64-bit integer + /// + /// An array eight bytes or longer + /// An unsigned 64-bit integer, will be zero if the array + /// contains less than eight bytes + public static ulong BytesToUInt64(byte[] bytes) + { + if (bytes.Length < 8) return 0; + return (ulong) + ((ulong)bytes[0] + + ((ulong)bytes[1] << 8) + + ((ulong)bytes[2] << 16) + + ((ulong)bytes[3] << 24) + + ((ulong)bytes[4] << 32) + + ((ulong)bytes[5] << 40) + + ((ulong)bytes[6] << 48) + + ((ulong)bytes[7] << 56)); + } + + /// + /// Convert four bytes in little endian ordering to a floating point + /// value + /// + /// Byte array containing a little ending floating + /// point value + /// Starting position of the floating point value in + /// the byte array + /// Single precision value + public static float BytesToFloat(byte[] bytes, int pos) + { + if (!BitConverter.IsLittleEndian) + { + byte[] newBytes = new byte[4]; + Buffer.BlockCopy(bytes, pos, newBytes, 0, 4); + Array.Reverse(newBytes, 0, 4); + return BitConverter.ToSingle(newBytes, 0); + } + else + { + return BitConverter.ToSingle(bytes, pos); + } + } + + public static double BytesToDouble(byte[] bytes, int pos) + { + if (!BitConverter.IsLittleEndian) + { + byte[] newBytes = new byte[8]; + Buffer.BlockCopy(bytes, pos, newBytes, 0, 8); + Array.Reverse(newBytes, 0, 8); + return BitConverter.ToDouble(newBytes, 0); + } + else + { + return BitConverter.ToDouble(bytes, pos); + } + } + + #endregion BytesTo + + #region ToBytes + + public static byte[] Int16ToBytes(short value) + { + byte[] bytes = new byte[2]; + bytes[0] = (byte)(value % 256); + bytes[1] = (byte)((value >> 8) % 256); + return bytes; + } + + public static void Int16ToBytes(short value, byte[] dest, int pos) + { + dest[pos] = (byte)(value % 256); + dest[pos + 1] = (byte)((value >> 8) % 256); + } + + public static byte[] UInt16ToBytes(ushort value) + { + byte[] bytes = new byte[2]; + bytes[0] = (byte)(value % 256); + bytes[1] = (byte)((value >> 8) % 256); + return bytes; + } + + public static void UInt16ToBytes(ushort value, byte[] dest, int pos) + { + dest[pos] = (byte)(value % 256); + dest[pos + 1] = (byte)((value >> 8) % 256); + } + + public static void UInt16ToBytesBig(ushort value, byte[] dest, int pos) + { + dest[pos] = (byte)((value >> 8) % 256); + dest[pos + 1] = (byte)(value % 256); + } + + /// + /// Convert an integer to a byte array in little endian format + /// + /// The integer to convert + /// A four byte little endian array + public static byte[] IntToBytes(int value) + { + byte[] bytes = new byte[4]; + + bytes[0] = (byte)(value % 256); + bytes[1] = (byte)((value >> 8) % 256); + bytes[2] = (byte)((value >> 16) % 256); + bytes[3] = (byte)((value >> 24) % 256); + + return bytes; + } + + /// + /// Convert an integer to a byte array in big endian format + /// + /// The integer to convert + /// A four byte big endian array + public static byte[] IntToBytesBig(int value) + { + byte[] bytes = new byte[4]; + + bytes[0] = (byte)((value >> 24) % 256); + bytes[1] = (byte)((value >> 16) % 256); + bytes[2] = (byte)((value >> 8) % 256); + bytes[3] = (byte)(value % 256); + + return bytes; + } + + public static void IntToBytes(int value, byte[] dest, int pos) + { + dest[pos] = (byte)(value % 256); + dest[pos + 1] = (byte)((value >> 8) % 256); + dest[pos + 2] = (byte)((value >> 16) % 256); + dest[pos + 3] = (byte)((value >> 24) % 256); + } + + public static byte[] UIntToBytes(uint value) + { + byte[] bytes = new byte[4]; + bytes[0] = (byte)(value % 256); + bytes[1] = (byte)((value >> 8) % 256); + bytes[2] = (byte)((value >> 16) % 256); + bytes[3] = (byte)((value >> 24) % 256); + return bytes; + } + + public static void UIntToBytes(uint value, byte[] dest, int pos) + { + dest[pos] = (byte)(value % 256); + dest[pos + 1] = (byte)((value >> 8) % 256); + dest[pos + 2] = (byte)((value >> 16) % 256); + dest[pos + 3] = (byte)((value >> 24) % 256); + } + + public static void UIntToBytesBig(uint value, byte[] dest, int pos) + { + dest[pos] = (byte)((value >> 24) % 256); + dest[pos + 1] = (byte)((value >> 16) % 256); + dest[pos + 2] = (byte)((value >> 8) % 256); + dest[pos + 3] = (byte)(value % 256); + } + + /// + /// Convert a 64-bit integer to a byte array in little endian format + /// + /// The value to convert + /// An 8 byte little endian array + public static byte[] Int64ToBytes(long value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!BitConverter.IsLittleEndian) + Array.Reverse(bytes); + + return bytes; + } + + public static void Int64ToBytes(long value, byte[] dest, int pos) + { + byte[] bytes = Int64ToBytes(value); + Buffer.BlockCopy(bytes, 0, dest, pos, 8); + } + + /// + /// Convert a 64-bit unsigned integer to a byte array in little endian + /// format + /// + /// The value to convert + /// An 8 byte little endian array + public static byte[] UInt64ToBytes(ulong value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!BitConverter.IsLittleEndian) + Array.Reverse(bytes); + + return bytes; + } + + public static byte[] UInt64ToBytesBig(ulong value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian) + Array.Reverse(bytes); + + return bytes; + } + + public static void UInt64ToBytes(ulong value, byte[] dest, int pos) + { + byte[] bytes = UInt64ToBytes(value); + Buffer.BlockCopy(bytes, 0, dest, pos, 8); + } + + public static void UInt64ToBytesBig(ulong value, byte[] dest, int pos) + { + byte[] bytes = UInt64ToBytesBig(value); + Buffer.BlockCopy(bytes, 0, dest, pos, 8); + } + + /// + /// Convert a floating point value to four bytes in little endian + /// ordering + /// + /// A floating point value + /// A four byte array containing the value in little endian + /// ordering + public static byte[] FloatToBytes(float value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!BitConverter.IsLittleEndian) + Array.Reverse(bytes); + return bytes; + } + + public static void FloatToBytes(float value, byte[] dest, int pos) + { + byte[] bytes = FloatToBytes(value); + Buffer.BlockCopy(bytes, 0, dest, pos, 4); + } + + public static byte[] DoubleToBytes(double value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!BitConverter.IsLittleEndian) + Array.Reverse(bytes); + return bytes; + } + + public static byte[] DoubleToBytesBig(double value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian) + Array.Reverse(bytes); + return bytes; + } + + public static void DoubleToBytes(double value, byte[] dest, int pos) + { + byte[] bytes = DoubleToBytes(value); + Buffer.BlockCopy(bytes, 0, dest, pos, 8); + } + + #endregion ToBytes + + #region Strings + + /// + /// Converts an unsigned integer to a hexadecimal string + /// + /// An unsigned integer to convert to a string + /// A hexadecimal string 10 characters long + /// 0x7fffffff + public static string UIntToHexString(uint i) + { + return string.Format("{0:x8}", i); + } + + /// + /// Convert a variable length UTF8 byte array to a string + /// + /// The UTF8 encoded byte array to convert + /// The decoded string + public static string BytesToString(byte[] bytes) + { + if (bytes.Length > 0 && bytes[bytes.Length - 1] == 0x00) + return GetString(bytes, 0, bytes.Length - 1); + else + return GetString(bytes, 0, bytes.Length); + } + + public static string BytesToString(byte[] bytes, int index, int count) + { + if (bytes.Length > index + count && bytes[index + count - 1] == 0x00) + return GetString(bytes, index, count - 1); + else + return GetString(bytes, index, count); + } + + private static string GetString(byte[] bytes, int index, int count) + { + string cnv = UTF8Encoding.UTF8.GetString(bytes, index, count); + return InternStrings ? string.Intern(cnv) : cnv; + } + + /// + /// Converts a byte array to a string containing hexadecimal characters + /// + /// The byte array to convert to a string + /// The name of the field to prepend to each + /// line of the string + /// A string containing hexadecimal characters on multiple + /// lines. Each line is prepended with the field name + public static string BytesToHexString(byte[] bytes, string fieldName) + { + string cnv = BytesToHexString(bytes, bytes.Length, fieldName); + return InternStrings ? string.Intern(cnv) : cnv; + } + + /// + /// Converts a byte array to a string containing hexadecimal characters + /// + /// The byte array to convert to a string + /// Number of bytes in the array to parse + /// A string to prepend to each line of the hex + /// dump + /// A string containing hexadecimal characters on multiple + /// lines. Each line is prepended with the field name + public static string BytesToHexString(byte[] bytes, int length, string fieldName) + { + StringBuilder output = new StringBuilder(); + + for (int i = 0; i < length; i += 16) + { + if (i != 0) + output.Append('\n'); + + if (!String.IsNullOrEmpty(fieldName)) + { + output.Append(fieldName); + output.Append(": "); + } + + for (int j = 0; j < 16; j++) + { + if ((i + j) < length) + { + if (j != 0) + output.Append(' '); + + output.Append(String.Format("{0:X2}", bytes[i + j])); + } + } + } + + return output.ToString(); + } + + /// + /// Convert a string to a UTF8 encoded byte array + /// + /// The string to convert + /// A null-terminated UTF8 byte array + public static byte[] StringToBytes(string str) + { + if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } + if (!str.EndsWith("\0")) { str += "\0"; } + return System.Text.UTF8Encoding.UTF8.GetBytes(str); + } + + /// + /// Converts a string containing hexadecimal characters to a byte array + /// + /// String containing hexadecimal characters + /// If true, gracefully handles null, empty and + /// uneven strings as well as stripping unconvertable characters + /// The converted byte array + public static byte[] HexStringToBytes(string hexString, bool handleDirty) + { + if (handleDirty) + { + if (String.IsNullOrEmpty(hexString)) + return Utils.EmptyBytes; + + StringBuilder stripped = new StringBuilder(hexString.Length); + char c; + + // remove all non A-F, 0-9, characters + for (int i = 0; i < hexString.Length; i++) + { + c = hexString[i]; + if (IsHexDigit(c)) + stripped.Append(c); + } + + hexString = stripped.ToString(); + + // if odd number of characters, discard last character + if (hexString.Length % 2 != 0) + { + hexString = hexString.Substring(0, hexString.Length - 1); + } + } + + int byteLength = hexString.Length / 2; + byte[] bytes = new byte[byteLength]; + int j = 0; + + for (int i = 0; i < bytes.Length; i++) + { + bytes[i] = HexToByte(hexString.Substring(j, 2)); + j += 2; + } + + return bytes; + } + + /// + /// Returns true is c is a hexadecimal digit (A-F, a-f, 0-9) + /// + /// Character to test + /// true if hex digit, false if not + private static bool IsHexDigit(Char c) + { + const int numA = 65; + const int num0 = 48; + + int numChar; + + c = Char.ToUpper(c); + numChar = Convert.ToInt32(c); + + if (numChar >= numA && numChar < (numA + 6)) + return true; + else if (numChar >= num0 && numChar < (num0 + 10)) + return true; + else + return false; + } + + /// + /// Converts 1 or 2 character string into equivalant byte value + /// + /// 1 or 2 character string + /// byte + private static byte HexToByte(string hex) + { + if (hex.Length > 2 || hex.Length <= 0) + throw new ArgumentException("hex must be 1 or 2 characters in length"); + byte newByte = Byte.Parse(hex, System.Globalization.NumberStyles.HexNumber); + return newByte; + } + + #endregion Strings + + #region Packed Values + + /// + /// Convert a float value to a byte given a minimum and maximum range + /// + /// Value to convert to a byte + /// Minimum value range + /// Maximum value range + /// A single byte representing the original float value + public static byte FloatToByte(float val, float lower, float upper) + { + val = Utils.Clamp(val, lower, upper); + // Normalize the value + val -= lower; + val /= (upper - lower); + + return (byte)Math.Floor(val * (float)byte.MaxValue); + } + + /// + /// Convert a byte to a float value given a minimum and maximum range + /// + /// Byte array to get the byte from + /// Position in the byte array the desired byte is at + /// Minimum value range + /// Maximum value range + /// A float value inclusively between lower and upper + public static float ByteToFloat(byte[] bytes, int pos, float lower, float upper) + { + if (bytes.Length <= pos) return 0; + return ByteToFloat(bytes[pos], lower, upper); + } + + /// + /// Convert a byte to a float value given a minimum and maximum range + /// + /// Byte to convert to a float value + /// Minimum value range + /// Maximum value range + /// A float value inclusively between lower and upper + public static float ByteToFloat(byte val, float lower, float upper) + { + const float ONE_OVER_BYTEMAX = 1.0f / (float)byte.MaxValue; + + float fval = (float)val * ONE_OVER_BYTEMAX; + float delta = (upper - lower); + fval *= delta; + fval += lower; + + // Test for values very close to zero + float error = delta * ONE_OVER_BYTEMAX; + if (Math.Abs(fval) < error) + fval = 0.0f; + + return fval; + } + + public static float UInt16ToFloat(byte[] bytes, int pos, float lower, float upper) + { + ushort val = BytesToUInt16(bytes, pos); + return UInt16ToFloat(val, lower, upper); + } + + public static float UInt16ToFloat(ushort val, float lower, float upper) + { + const float ONE_OVER_U16_MAX = 1.0f / (float)UInt16.MaxValue; + + float fval = (float)val * ONE_OVER_U16_MAX; + float delta = upper - lower; + fval *= delta; + fval += lower; + + // Make sure zeroes come through as zero + float maxError = delta * ONE_OVER_U16_MAX; + if (Math.Abs(fval) < maxError) + fval = 0.0f; + + return fval; + } + + public static ushort FloatToUInt16(float value, float lower, float upper) + { + float delta = upper - lower; + value -= lower; + value /= delta; + value *= (float)UInt16.MaxValue; + + return (ushort)value; + } + + #endregion Packed Values + + #region TryParse + + /// + /// Attempts to parse a floating point value from a string, using an + /// EN-US number format + /// + /// String to parse + /// Resulting floating point number + /// True if the parse was successful, otherwise false + public static bool TryParseSingle(string s, out float result) + { + return Single.TryParse(s, System.Globalization.NumberStyles.Float, EnUsCulture.NumberFormat, out result); + } + + /// + /// Attempts to parse a floating point value from a string, using an + /// EN-US number format + /// + /// String to parse + /// Resulting floating point number + /// True if the parse was successful, otherwise false + public static bool TryParseDouble(string s, out double result) + { + // NOTE: Double.TryParse can't parse Double.[Min/Max]Value.ToString(), see: + // http://blogs.msdn.com/bclteam/archive/2006/05/24/598169.aspx + return Double.TryParse(s, System.Globalization.NumberStyles.Float, EnUsCulture.NumberFormat, out result); + } + + /// + /// Tries to parse an unsigned 32-bit integer from a hexadecimal string + /// + /// String to parse + /// Resulting integer + /// True if the parse was successful, otherwise false + public static bool TryParseHex(string s, out uint result) + { + return UInt32.TryParse(s, System.Globalization.NumberStyles.HexNumber, EnUsCulture.NumberFormat, out result); + } + + #endregion TryParse + + #region Enum String Conversion + + /// + /// Returns text specified in EnumInfo attribute of the enumerator + /// To add the text use [EnumInfo(Text = "Some nice text here")] before declaration + /// of enum values + /// + /// Enum value + /// Text representation of the enum + public static string EnumToText(Enum value) + { + // Get the type + Type type = value.GetType(); + + // Get fieldinfo for this type + FieldInfo fieldInfo = type.GetField(value.ToString()); + + // Find extended attributes, if any + EnumInfoAttribute[] attribs = (EnumInfoAttribute[])fieldInfo.GetCustomAttributes(typeof(EnumInfoAttribute), false); + + return attribs.Length > 0 ? attribs[0].Text : value.ToString(); + } + + /// + /// Takes an AssetType and returns the string representation + /// + /// The source + /// The string version of the AssetType + public static string AssetTypeToString(AssetType type) + { + return _AssetTypeNames[(int)type]; + } + + /// + /// Translate a string name of an AssetType into the proper Type + /// + /// A string containing the AssetType name + /// The AssetType which matches the string name, or AssetType.Unknown if no match was found + public static AssetType StringToAssetType(string type) + { + for (int i = 0; i < _AssetTypeNames.Length; i++) + { + if (_AssetTypeNames[i] == type) + return (AssetType)i; + } + + return AssetType.Unknown; + } + + /// + /// Convert an InventoryType to a string + /// + /// The to convert + /// A string representation of the source + public static string InventoryTypeToString(InventoryType type) + { + return _InventoryTypeNames[(int)type]; + } + + /// + /// Convert a string into a valid InventoryType + /// + /// A string representation of the InventoryType to convert + /// A InventoryType object which matched the type + public static InventoryType StringToInventoryType(string type) + { + for (int i = 0; i < _InventoryTypeNames.Length; i++) + { + if (_InventoryTypeNames[i] == type) + return (InventoryType)i; + } + + return InventoryType.Unknown; + } + + /// + /// Convert a SaleType to a string + /// + /// The to convert + /// A string representation of the source + public static string SaleTypeToString(SaleType type) + { + return _SaleTypeNames[(int)type]; + } + + /// + /// Convert a string into a valid SaleType + /// + /// A string representation of the SaleType to convert + /// A SaleType object which matched the type + public static SaleType StringToSaleType(string value) + { + for (int i = 0; i < _SaleTypeNames.Length; i++) + { + if (value == _SaleTypeNames[i]) + return (SaleType)i; + } + + return SaleType.Not; + } + + /// + /// Converts a string used in LLSD to AttachmentPoint type + /// + /// String representation of AttachmentPoint to convert + /// AttachmentPoint enum + public static AttachmentPoint StringToAttachmentPoint(string value) + { + for (int i = 0; i < _AttachmentPointNames.Length; i++) + { + if (value == _AttachmentPointNames[i]) + return (AttachmentPoint)i; + } + + return AttachmentPoint.Default; + } + + #endregion Enum String Conversion + + #region Miscellaneous + + /// + /// Copy a byte array + /// + /// Byte array to copy + /// A copy of the given byte array + public static byte[] CopyBytes(byte[] bytes) + { + if (bytes == null) + return null; + + byte[] newBytes = new byte[bytes.Length]; + Buffer.BlockCopy(bytes, 0, newBytes, 0, bytes.Length); + return newBytes; + } + + /// + /// Packs to 32-bit unsigned integers in to a 64-bit unsigned integer + /// + /// The left-hand (or X) value + /// The right-hand (or Y) value + /// A 64-bit integer containing the two 32-bit input values + public static ulong UIntsToLong(uint a, uint b) + { + return ((ulong)a << 32) | (ulong)b; + } + + /// + /// Unpacks two 32-bit unsigned integers from a 64-bit unsigned integer + /// + /// The 64-bit input integer + /// The left-hand (or X) output value + /// The right-hand (or Y) output value + public static void LongToUInts(ulong a, out uint b, out uint c) + { + b = (uint)(a >> 32); + c = (uint)(a & 0x00000000FFFFFFFF); + } + + /// + /// Convert an IP address object to an unsigned 32-bit integer + /// + /// IP address to convert + /// 32-bit unsigned integer holding the IP address bits + public static uint IPToUInt(System.Net.IPAddress address) + { + byte[] bytes = address.GetAddressBytes(); + return (uint)((bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]); + } + + /// + /// Gets a unix timestamp for the current time + /// + /// An unsigned integer representing a unix timestamp for now + public static uint GetUnixTime() + { + return (uint)(DateTime.UtcNow - Epoch).TotalSeconds; + } + + /// + /// Convert a UNIX timestamp to a native DateTime object + /// + /// An unsigned integer representing a UNIX + /// timestamp + /// A DateTime object containing the same time specified in + /// the given timestamp + public static DateTime UnixTimeToDateTime(uint timestamp) + { + DateTime dateTime = Epoch; + + // Add the number of seconds in our UNIX timestamp + dateTime = dateTime.AddSeconds(timestamp); + + return dateTime; + } + + /// + /// Convert a UNIX timestamp to a native DateTime object + /// + /// A signed integer representing a UNIX + /// timestamp + /// A DateTime object containing the same time specified in + /// the given timestamp + public static DateTime UnixTimeToDateTime(int timestamp) + { + return UnixTimeToDateTime((uint)timestamp); + } + + /// + /// Convert a native DateTime object to a UNIX timestamp + /// + /// A DateTime object you want to convert to a + /// timestamp + /// An unsigned integer representing a UNIX timestamp + public static uint DateTimeToUnixTime(DateTime time) + { + TimeSpan ts = (time - new DateTime(1970, 1, 1, 0, 0, 0)); + return (uint)ts.TotalSeconds; + } + + /// + /// Swap two values + /// + /// Type of the values to swap + /// First value + /// Second value + public static void Swap(ref T lhs, ref T rhs) + { + T temp = lhs; + lhs = rhs; + rhs = temp; + } + + /// + /// Try to parse an enumeration value from a string + /// + /// Enumeration type + /// String value to parse + /// Enumeration value on success + /// True if the parsing succeeded, otherwise false + public static bool EnumTryParse(string strType, out T result) + { + Type t = typeof(T); + + if (Enum.IsDefined(t, strType)) + { + result = (T)Enum.Parse(t, strType, true); + return true; + } + else + { + foreach (string value in Enum.GetNames(typeof(T))) + { + if (value.Equals(strType, StringComparison.OrdinalIgnoreCase)) + { + result = (T)Enum.Parse(typeof(T), value); + return true; + } + } + result = default(T); + return false; + } + } + + /// + /// Swaps the high and low words in a byte. Converts aaaabbbb to bbbbaaaa + /// + /// Byte to swap the words in + /// Byte value with the words swapped + public static byte SwapWords(byte value) + { + return (byte)(((value & 0xF0) >> 4) | ((value & 0x0F) << 4)); + } + + /// + /// Attempts to convert a string representation of a hostname or IP + /// address to a + /// + /// Hostname to convert to an IPAddress + /// Converted IP address object, or null if the conversion + /// failed + public static IPAddress HostnameToIPv4(string hostname) + { + // Is it already a valid IP? + IPAddress ip; + if (IPAddress.TryParse(hostname, out ip)) + return ip; + + IPAddress[] hosts = Dns.GetHostEntry(hostname).AddressList; + + for (int i = 0; i < hosts.Length; i++) + { + IPAddress host = hosts[i]; + + if (host.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + return host; + } + + return null; + } + + #endregion Miscellaneous + } +} diff --git a/OpenMetaverseTypes/Vector2.cs b/OpenMetaverseTypes/Vector2.cs new file mode 100644 index 0000000..f2330bf --- /dev/null +++ b/OpenMetaverseTypes/Vector2.cs @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.InteropServices; +using System.Globalization; + +namespace OpenMetaverse +{ + /// + /// A two-dimensional vector with floating-point values + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector2 : IComparable, IEquatable + { + /// X value + public float X; + /// Y value + public float Y; + + #region Constructors + + public Vector2(float x, float y) + { + X = x; + Y = y; + } + + public Vector2(float value) + { + X = value; + Y = value; + } + + public Vector2(Vector2 vector) + { + X = vector.X; + Y = vector.Y; + } + + #endregion Constructors + + #region Public Methods + + /// + /// Test if this vector is equal to another vector, within a given + /// tolerance range + /// + /// Vector to test against + /// The acceptable magnitude of difference + /// between the two vectors + /// True if the magnitude of difference between the two vectors + /// is less than the given tolerance, otherwise false + public bool ApproxEquals(Vector2 vec, float tolerance) + { + Vector2 diff = this - vec; + return (diff.LengthSquared() <= tolerance * tolerance); + } + + /// + /// Test if this vector is composed of all finite numbers + /// + public bool IsFinite() + { + return Utils.IsFinite(X) && Utils.IsFinite(Y); + } + + /// + /// IComparable.CompareTo implementation + /// + public int CompareTo(Vector2 vector) + { + return Length().CompareTo(vector.Length()); + } + + /// + /// Builds a vector from a byte array + /// + /// Byte array containing two four-byte floats + /// Beginning position in the byte array + public void FromBytes(byte[] byteArray, int pos) + { + if (!BitConverter.IsLittleEndian) + { + // Big endian architecture + byte[] conversionBuffer = new byte[8]; + + Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 8); + + Array.Reverse(conversionBuffer, 0, 4); + Array.Reverse(conversionBuffer, 4, 4); + + X = BitConverter.ToSingle(conversionBuffer, 0); + Y = BitConverter.ToSingle(conversionBuffer, 4); + } + else + { + // Little endian architecture + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + } + } + + /// + /// Returns the raw bytes for this vector + /// + /// An eight-byte array containing X and Y + public byte[] GetBytes() + { + byte[] byteArray = new byte[8]; + ToBytes(byteArray, 0); + return byteArray; + } + + /// + /// Writes the raw bytes for this vector to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 8 bytes before the end of the array + public void ToBytes(byte[] dest, int pos) + { + Buffer.BlockCopy(BitConverter.GetBytes(X), 0, dest, pos + 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, dest, pos + 4, 4); + + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(dest, pos + 0, 4); + Array.Reverse(dest, pos + 4, 4); + } + } + + public float Length() + { + return (float)Math.Sqrt(DistanceSquared(this, Zero)); + } + + public float LengthSquared() + { + return DistanceSquared(this, Zero); + } + + public void Normalize() + { + this = Normalize(this); + } + + #endregion Public Methods + + #region Static Methods + + public static Vector2 Add(Vector2 value1, Vector2 value2) + { + value1.X += value2.X; + value1.Y += value2.Y; + return value1; + } + + public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) + { + return new Vector2( + Utils.Clamp(value1.X, min.X, max.X), + Utils.Clamp(value1.Y, min.Y, max.Y)); + } + + public static float Distance(Vector2 value1, Vector2 value2) + { + return (float)Math.Sqrt(DistanceSquared(value1, value2)); + } + + public static float DistanceSquared(Vector2 value1, Vector2 value2) + { + return + (value1.X - value2.X) * (value1.X - value2.X) + + (value1.Y - value2.Y) * (value1.Y - value2.Y); + } + + public static Vector2 Divide(Vector2 value1, Vector2 value2) + { + value1.X /= value2.X; + value1.Y /= value2.Y; + return value1; + } + + public static Vector2 Divide(Vector2 value1, float divider) + { + float factor = 1 / divider; + value1.X *= factor; + value1.Y *= factor; + return value1; + } + + public static float Dot(Vector2 value1, Vector2 value2) + { + return value1.X * value2.X + value1.Y * value2.Y; + } + + public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) + { + return new Vector2( + Utils.Lerp(value1.X, value2.X, amount), + Utils.Lerp(value1.Y, value2.Y, amount)); + } + + public static Vector2 Max(Vector2 value1, Vector2 value2) + { + return new Vector2( + Math.Max(value1.X, value2.X), + Math.Max(value1.Y, value2.Y)); + } + + public static Vector2 Min(Vector2 value1, Vector2 value2) + { + return new Vector2( + Math.Min(value1.X, value2.X), + Math.Min(value1.Y, value2.Y)); + } + + public static Vector2 Multiply(Vector2 value1, Vector2 value2) + { + value1.X *= value2.X; + value1.Y *= value2.Y; + return value1; + } + + public static Vector2 Multiply(Vector2 value1, float scaleFactor) + { + value1.X *= scaleFactor; + value1.Y *= scaleFactor; + return value1; + } + + public static Vector2 Negate(Vector2 value) + { + value.X = -value.X; + value.Y = -value.Y; + return value; + } + + public static Vector2 Normalize(Vector2 value) + { + const float MAG_THRESHOLD = 0.0000001f; + float factor = DistanceSquared(value, Zero); + if (factor > MAG_THRESHOLD) + { + factor = 1f / (float)Math.Sqrt(factor); + value.X *= factor; + value.Y *= factor; + } + else + { + value.X = 0f; + value.Y = 0f; + } + return value; + } + + /// + /// Parse a vector from a string + /// + /// A string representation of a 2D vector, enclosed + /// in arrow brackets and separated by commas + public static Vector3 Parse(string val) + { + char[] splitChar = { ',' }; + string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); + return new Vector3( + float.Parse(split[0].Trim(), Utils.EnUsCulture), + float.Parse(split[1].Trim(), Utils.EnUsCulture), + float.Parse(split[2].Trim(), Utils.EnUsCulture)); + } + + public static bool TryParse(string val, out Vector3 result) + { + try + { + result = Parse(val); + return true; + } + catch (Exception) + { + result = Vector3.Zero; + return false; + } + } + + /// + /// Interpolates between two vectors using a cubic equation + /// + public static Vector2 SmoothStep(Vector2 value1, Vector2 value2, float amount) + { + return new Vector2( + Utils.SmoothStep(value1.X, value2.X, amount), + Utils.SmoothStep(value1.Y, value2.Y, amount)); + } + + public static Vector2 Subtract(Vector2 value1, Vector2 value2) + { + value1.X -= value2.X; + value1.Y -= value2.Y; + return value1; + } + + public static Vector2 Transform(Vector2 position, Matrix4 matrix) + { + position.X = (position.X * matrix.M11) + (position.Y * matrix.M21) + matrix.M41; + position.Y = (position.X * matrix.M12) + (position.Y * matrix.M22) + matrix.M42; + return position; + } + + public static Vector2 TransformNormal(Vector2 position, Matrix4 matrix) + { + position.X = (position.X * matrix.M11) + (position.Y * matrix.M21); + position.Y = (position.X * matrix.M12) + (position.Y * matrix.M22); + return position; + } + + #endregion Static Methods + + #region Overrides + + public override bool Equals(object obj) + { + return (obj is Vector2) ? this == ((Vector2)obj) : false; + } + + public bool Equals(Vector2 other) + { + return this == other; + } + + public override int GetHashCode() + { + int hash = X.GetHashCode(); + hash = hash * 31 + Y.GetHashCode(); + return hash; + } + + /// + /// Get a formatted string representation of the vector + /// + /// A string representation of the vector + public override string ToString() + { + return String.Format(Utils.EnUsCulture, "<{0}, {1}>", X, Y); + } + + /// + /// Get a string representation of the vector elements with up to three + /// decimal digits and separated by spaces only + /// + /// Raw string representation of the vector + public string ToRawString() + { + CultureInfo enUs = new CultureInfo("en-us"); + enUs.NumberFormat.NumberDecimalDigits = 3; + + return String.Format(enUs, "{0} {1}", X, Y); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Vector2 value1, Vector2 value2) + { + return value1.X == value2.X && value1.Y == value2.Y; + } + + public static bool operator !=(Vector2 value1, Vector2 value2) + { + return value1.X != value2.X || value1.Y != value2.Y; + } + + public static Vector2 operator +(Vector2 value1, Vector2 value2) + { + value1.X += value2.X; + value1.Y += value2.Y; + return value1; + } + + public static Vector2 operator -(Vector2 value) + { + value.X = -value.X; + value.Y = -value.Y; + return value; + } + + public static Vector2 operator -(Vector2 value1, Vector2 value2) + { + value1.X -= value2.X; + value1.Y -= value2.Y; + return value1; + } + + public static Vector2 operator *(Vector2 value1, Vector2 value2) + { + value1.X *= value2.X; + value1.Y *= value2.Y; + return value1; + } + + + public static Vector2 operator *(Vector2 value, float scaleFactor) + { + value.X *= scaleFactor; + value.Y *= scaleFactor; + return value; + } + + public static Vector2 operator /(Vector2 value1, Vector2 value2) + { + value1.X /= value2.X; + value1.Y /= value2.Y; + return value1; + } + + + public static Vector2 operator /(Vector2 value1, float divider) + { + float factor = 1 / divider; + value1.X *= factor; + value1.Y *= factor; + return value1; + } + + #endregion Operators + + /// A vector with a value of 0,0 + public readonly static Vector2 Zero = new Vector2(); + /// A vector with a value of 1,1 + public readonly static Vector2 One = new Vector2(1f, 1f); + /// A vector with a value of 1,0 + public readonly static Vector2 UnitX = new Vector2(1f, 0f); + /// A vector with a value of 0,1 + public readonly static Vector2 UnitY = new Vector2(0f, 1f); + } +} diff --git a/OpenMetaverseTypes/Vector3.cs b/OpenMetaverseTypes/Vector3.cs new file mode 100644 index 0000000..0628559 --- /dev/null +++ b/OpenMetaverseTypes/Vector3.cs @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.InteropServices; +using System.Globalization; + +namespace OpenMetaverse +{ + /// + /// A three-dimensional vector with floating-point values + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector3 : IComparable, IEquatable + { + /// X value + public float X; + /// Y value + public float Y; + /// Z value + public float Z; + + #region Constructors + + public Vector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public Vector3(float value) + { + X = value; + Y = value; + Z = value; + } + + public Vector3(Vector2 value, float z) + { + X = value.X; + Y = value.Y; + Z = z; + } + + public Vector3(Vector3d vector) + { + X = (float)vector.X; + Y = (float)vector.Y; + Z = (float)vector.Z; + } + + /// + /// Constructor, builds a vector from a byte array + /// + /// Byte array containing three four-byte floats + /// Beginning position in the byte array + public Vector3(byte[] byteArray, int pos) + { + X = Y = Z = 0f; + FromBytes(byteArray, pos); + } + + public Vector3(Vector3 vector) + { + X = vector.X; + Y = vector.Y; + Z = vector.Z; + } + + #endregion Constructors + + #region Public Methods + + public float Length() + { + return (float)Math.Sqrt(DistanceSquared(this, Zero)); + } + + public float LengthSquared() + { + return DistanceSquared(this, Zero); + } + + public void Normalize() + { + this = Normalize(this); + } + + /// + /// Test if this vector is equal to another vector, within a given + /// tolerance range + /// + /// Vector to test against + /// The acceptable magnitude of difference + /// between the two vectors + /// True if the magnitude of difference between the two vectors + /// is less than the given tolerance, otherwise false + public bool ApproxEquals(Vector3 vec, float tolerance) + { + Vector3 diff = this - vec; + return (diff.LengthSquared() <= tolerance * tolerance); + } + + /// + /// IComparable.CompareTo implementation + /// + public int CompareTo(Vector3 vector) + { + return Length().CompareTo(vector.Length()); + } + + /// + /// Test if this vector is composed of all finite numbers + /// + public bool IsFinite() + { + return (Utils.IsFinite(X) && Utils.IsFinite(Y) && Utils.IsFinite(Z)); + } + + /// + /// Builds a vector from a byte array + /// + /// Byte array containing a 12 byte vector + /// Beginning position in the byte array + public void FromBytes(byte[] byteArray, int pos) + { + if (!BitConverter.IsLittleEndian) + { + // Big endian architecture + byte[] conversionBuffer = new byte[12]; + + Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 12); + + Array.Reverse(conversionBuffer, 0, 4); + Array.Reverse(conversionBuffer, 4, 4); + Array.Reverse(conversionBuffer, 8, 4); + + X = BitConverter.ToSingle(conversionBuffer, 0); + Y = BitConverter.ToSingle(conversionBuffer, 4); + Z = BitConverter.ToSingle(conversionBuffer, 8); + } + else + { + // Little endian architecture + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + } + } + + /// + /// Returns the raw bytes for this vector + /// + /// A 12 byte array containing X, Y, and Z + public byte[] GetBytes() + { + byte[] byteArray = new byte[12]; + ToBytes(byteArray, 0); + return byteArray; + } + + /// + /// Writes the raw bytes for this vector to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 12 bytes before the end of the array + public void ToBytes(byte[] dest, int pos) + { + Buffer.BlockCopy(BitConverter.GetBytes(X), 0, dest, pos + 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, dest, pos + 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Z), 0, dest, pos + 8, 4); + + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(dest, pos + 0, 4); + Array.Reverse(dest, pos + 4, 4); + Array.Reverse(dest, pos + 8, 4); + } + } + + #endregion Public Methods + + #region Static Methods + + public static Vector3 Add(Vector3 value1, Vector3 value2) + { + value1.X += value2.X; + value1.Y += value2.Y; + value1.Z += value2.Z; + return value1; + } + + public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) + { + return new Vector3( + Utils.Clamp(value1.X, min.X, max.X), + Utils.Clamp(value1.Y, min.Y, max.Y), + Utils.Clamp(value1.Z, min.Z, max.Z)); + } + + public static Vector3 Cross(Vector3 value1, Vector3 value2) + { + return new Vector3( + value1.Y * value2.Z - value2.Y * value1.Z, + value1.Z * value2.X - value2.Z * value1.X, + value1.X * value2.Y - value2.X * value1.Y); + } + + public static float Distance(Vector3 value1, Vector3 value2) + { + return (float)Math.Sqrt(DistanceSquared(value1, value2)); + } + + public static float DistanceSquared(Vector3 value1, Vector3 value2) + { + return + (value1.X - value2.X) * (value1.X - value2.X) + + (value1.Y - value2.Y) * (value1.Y - value2.Y) + + (value1.Z - value2.Z) * (value1.Z - value2.Z); + } + + public static Vector3 Divide(Vector3 value1, Vector3 value2) + { + value1.X /= value2.X; + value1.Y /= value2.Y; + value1.Z /= value2.Z; + return value1; + } + + public static Vector3 Divide(Vector3 value1, float value2) + { + float factor = 1f / value2; + value1.X *= factor; + value1.Y *= factor; + value1.Z *= factor; + return value1; + } + + public static float Dot(Vector3 value1, Vector3 value2) + { + return value1.X * value2.X + value1.Y * value2.Y + value1.Z * value2.Z; + } + + public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) + { + return new Vector3( + Utils.Lerp(value1.X, value2.X, amount), + Utils.Lerp(value1.Y, value2.Y, amount), + Utils.Lerp(value1.Z, value2.Z, amount)); + } + + public static float Mag(Vector3 value) + { + return (float)Math.Sqrt((value.X * value.X) + (value.Y * value.Y) + (value.Z * value.Z)); + } + + public static Vector3 Max(Vector3 value1, Vector3 value2) + { + return new Vector3( + Math.Max(value1.X, value2.X), + Math.Max(value1.Y, value2.Y), + Math.Max(value1.Z, value2.Z)); + } + + public static Vector3 Min(Vector3 value1, Vector3 value2) + { + return new Vector3( + Math.Min(value1.X, value2.X), + Math.Min(value1.Y, value2.Y), + Math.Min(value1.Z, value2.Z)); + } + + public static Vector3 Multiply(Vector3 value1, Vector3 value2) + { + value1.X *= value2.X; + value1.Y *= value2.Y; + value1.Z *= value2.Z; + return value1; + } + + public static Vector3 Multiply(Vector3 value1, float scaleFactor) + { + value1.X *= scaleFactor; + value1.Y *= scaleFactor; + value1.Z *= scaleFactor; + return value1; + } + + public static Vector3 Negate(Vector3 value) + { + value.X = -value.X; + value.Y = -value.Y; + value.Z = -value.Z; + return value; + } + + public static Vector3 Normalize(Vector3 value) + { + const float MAG_THRESHOLD = 0.0000001f; + float factor = Distance(value, Zero); + if (factor > MAG_THRESHOLD) + { + factor = 1f / factor; + value.X *= factor; + value.Y *= factor; + value.Z *= factor; + } + else + { + value.X = 0f; + value.Y = 0f; + value.Z = 0f; + } + return value; + } + + /// + /// Parse a vector from a string + /// + /// A string representation of a 3D vector, enclosed + /// in arrow brackets and separated by commas + public static Vector3 Parse(string val) + { + char[] splitChar = { ',' }; + string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); + return new Vector3( + Single.Parse(split[0].Trim(), Utils.EnUsCulture), + Single.Parse(split[1].Trim(), Utils.EnUsCulture), + Single.Parse(split[2].Trim(), Utils.EnUsCulture)); + } + + public static bool TryParse(string val, out Vector3 result) + { + try + { + result = Parse(val); + return true; + } + catch (Exception) + { + result = Vector3.Zero; + return false; + } + } + + /// + /// Calculate the rotation between two vectors + /// + /// Normalized directional vector (such as 1,0,0 for forward facing) + /// Normalized target vector + public static Quaternion RotationBetween(Vector3 a, Vector3 b) + { + float dotProduct = Dot(a, b); + Vector3 crossProduct = Cross(a, b); + float magProduct = a.Length() * b.Length(); + double angle = Math.Acos(dotProduct / magProduct); + Vector3 axis = Normalize(crossProduct); + float s = (float)Math.Sin(angle / 2d); + + return new Quaternion( + axis.X * s, + axis.Y * s, + axis.Z * s, + (float)Math.Cos(angle / 2d)); + } + + /// + /// Interpolates between two vectors using a cubic equation + /// + public static Vector3 SmoothStep(Vector3 value1, Vector3 value2, float amount) + { + return new Vector3( + Utils.SmoothStep(value1.X, value2.X, amount), + Utils.SmoothStep(value1.Y, value2.Y, amount), + Utils.SmoothStep(value1.Z, value2.Z, amount)); + } + + public static Vector3 Subtract(Vector3 value1, Vector3 value2) + { + value1.X -= value2.X; + value1.Y -= value2.Y; + value1.Z -= value2.Z; + return value1; + } + + public static Vector3 Transform(Vector3 position, Matrix4 matrix) + { + return new Vector3( + (position.X * matrix.M11) + (position.Y * matrix.M21) + (position.Z * matrix.M31) + matrix.M41, + (position.X * matrix.M12) + (position.Y * matrix.M22) + (position.Z * matrix.M32) + matrix.M42, + (position.X * matrix.M13) + (position.Y * matrix.M23) + (position.Z * matrix.M33) + matrix.M43); + } + + public static Vector3 TransformNormal(Vector3 position, Matrix4 matrix) + { + return new Vector3( + (position.X * matrix.M11) + (position.Y * matrix.M21) + (position.Z * matrix.M31), + (position.X * matrix.M12) + (position.Y * matrix.M22) + (position.Z * matrix.M32), + (position.X * matrix.M13) + (position.Y * matrix.M23) + (position.Z * matrix.M33)); + } + + #endregion Static Methods + + #region Overrides + + public override bool Equals(object obj) + { + return (obj is Vector3) ? this == (Vector3)obj : false; + } + + public bool Equals(Vector3 other) + { + return this == other; + } + + public override int GetHashCode() + { + int hash = X.GetHashCode(); + hash = hash * 31 + Y.GetHashCode(); + hash = hash * 31 + Z.GetHashCode(); + return hash; + } + + /// + /// Get a formatted string representation of the vector + /// + /// A string representation of the vector + public override string ToString() + { + return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}>", X, Y, Z); + } + + /// + /// Get a string representation of the vector elements with up to three + /// decimal digits and separated by spaces only + /// + /// Raw string representation of the vector + public string ToRawString() + { + CultureInfo enUs = new CultureInfo("en-us"); + enUs.NumberFormat.NumberDecimalDigits = 3; + + return String.Format(enUs, "{0} {1} {2}", X, Y, Z); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Vector3 value1, Vector3 value2) + { + return value1.X == value2.X + && value1.Y == value2.Y + && value1.Z == value2.Z; + } + + public static bool operator !=(Vector3 value1, Vector3 value2) + { + return !(value1 == value2); + } + + public static Vector3 operator +(Vector3 value1, Vector3 value2) + { + value1.X += value2.X; + value1.Y += value2.Y; + value1.Z += value2.Z; + return value1; + } + + public static Vector3 operator -(Vector3 value) + { + value.X = -value.X; + value.Y = -value.Y; + value.Z = -value.Z; + return value; + } + + public static Vector3 operator -(Vector3 value1, Vector3 value2) + { + value1.X -= value2.X; + value1.Y -= value2.Y; + value1.Z -= value2.Z; + return value1; + } + + public static Vector3 operator *(Vector3 value1, Vector3 value2) + { + value1.X *= value2.X; + value1.Y *= value2.Y; + value1.Z *= value2.Z; + return value1; + } + + public static Vector3 operator *(Vector3 value, float scaleFactor) + { + value.X *= scaleFactor; + value.Y *= scaleFactor; + value.Z *= scaleFactor; + return value; + } + + public static Vector3 operator *(Vector3 vec, Quaternion rot) + { + float rw = -rot.X * vec.X - rot.Y * vec.Y - rot.Z * vec.Z; + float rx = rot.W * vec.X + rot.Y * vec.Z - rot.Z * vec.Y; + float ry = rot.W * vec.Y + rot.Z * vec.X - rot.X * vec.Z; + float rz = rot.W * vec.Z + rot.X * vec.Y - rot.Y * vec.X; + + vec.X = -rw * rot.X + rx * rot.W - ry * rot.Z + rz * rot.Y; + vec.Y = -rw * rot.Y + ry * rot.W - rz * rot.X + rx * rot.Z; + vec.Z = -rw * rot.Z + rz * rot.W - rx * rot.Y + ry * rot.X; + + return vec; + } + + public static Vector3 operator *(Vector3 vector, Matrix4 matrix) + { + return Transform(vector, matrix); + } + + public static Vector3 operator /(Vector3 value1, Vector3 value2) + { + value1.X /= value2.X; + value1.Y /= value2.Y; + value1.Z /= value2.Z; + return value1; + } + + public static Vector3 operator /(Vector3 value, float divider) + { + float factor = 1f / divider; + value.X *= factor; + value.Y *= factor; + value.Z *= factor; + return value; + } + + /// + /// Cross product between two vectors + /// + public static Vector3 operator %(Vector3 value1, Vector3 value2) + { + return Cross(value1, value2); + } + + /// + /// Explicit casting for Vector3d > Vector3 + /// + /// + /// + public static explicit operator Vector3(Vector3d value) + { + Vector3d foo = (Vector3d)Vector3.Zero; + return new Vector3(value); + } + + #endregion Operators + + /// A vector with a value of 0,0,0 + public readonly static Vector3 Zero = new Vector3(); + /// A vector with a value of 1,1,1 + public readonly static Vector3 One = new Vector3(1f, 1f, 1f); + /// A unit vector facing forward (X axis), value 1,0,0 + public readonly static Vector3 UnitX = new Vector3(1f, 0f, 0f); + /// A unit vector facing left (Y axis), value 0,1,0 + public readonly static Vector3 UnitY = new Vector3(0f, 1f, 0f); + /// A unit vector facing up (Z axis), value 0,0,1 + public readonly static Vector3 UnitZ = new Vector3(0f, 0f, 1f); + } +} diff --git a/OpenMetaverseTypes/Vector3d.cs b/OpenMetaverseTypes/Vector3d.cs new file mode 100644 index 0000000..6c7d380 --- /dev/null +++ b/OpenMetaverseTypes/Vector3d.cs @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.InteropServices; +using System.Globalization; + +namespace OpenMetaverse +{ + /// + /// A three-dimensional vector with doubleing-point values + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector3d : IComparable, IEquatable + { + /// X value + public double X; + /// Y value + public double Y; + /// Z value + public double Z; + + #region Constructors + + public Vector3d(double x, double y, double z) + { + X = x; + Y = y; + Z = z; + } + + public Vector3d(double value) + { + X = value; + Y = value; + Z = value; + } + + /// + /// Constructor, builds a vector from a byte array + /// + /// Byte array containing three eight-byte doubles + /// Beginning position in the byte array + public Vector3d(byte[] byteArray, int pos) + { + X = Y = Z = 0d; + FromBytes(byteArray, pos); + } + + public Vector3d(Vector3 vector) + { + X = vector.X; + Y = vector.Y; + Z = vector.Z; + } + + public Vector3d(Vector3d vector) + { + X = vector.X; + Y = vector.Y; + Z = vector.Z; + } + + #endregion Constructors + + #region Public Methods + + public double Length() + { + return Math.Sqrt(DistanceSquared(this, Zero)); + } + + public double LengthSquared() + { + return DistanceSquared(this, Zero); + } + + public void Normalize() + { + this = Normalize(this); + } + + /// + /// Test if this vector is equal to another vector, within a given + /// tolerance range + /// + /// Vector to test against + /// The acceptable magnitude of difference + /// between the two vectors + /// True if the magnitude of difference between the two vectors + /// is less than the given tolerance, otherwise false + public bool ApproxEquals(Vector3d vec, double tolerance) + { + Vector3d diff = this - vec; + return (diff.LengthSquared() <= tolerance * tolerance); + } + + /// + /// IComparable.CompareTo implementation + /// + public int CompareTo(Vector3d vector) + { + return this.Length().CompareTo(vector.Length()); + } + + /// + /// Test if this vector is composed of all finite numbers + /// + public bool IsFinite() + { + return (Utils.IsFinite(X) && Utils.IsFinite(Y) && Utils.IsFinite(Z)); + } + + /// + /// Builds a vector from a byte array + /// + /// Byte array containing a 24 byte vector + /// Beginning position in the byte array + public void FromBytes(byte[] byteArray, int pos) + { + if (!BitConverter.IsLittleEndian) + { + // Big endian architecture + byte[] conversionBuffer = new byte[24]; + + Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 24); + + Array.Reverse(conversionBuffer, 0, 8); + Array.Reverse(conversionBuffer, 8, 8); + Array.Reverse(conversionBuffer, 16, 8); + + X = BitConverter.ToDouble(conversionBuffer, 0); + Y = BitConverter.ToDouble(conversionBuffer, 8); + Z = BitConverter.ToDouble(conversionBuffer, 16); + } + else + { + // Little endian architecture + X = BitConverter.ToDouble(byteArray, pos); + Y = BitConverter.ToDouble(byteArray, pos + 8); + Z = BitConverter.ToDouble(byteArray, pos + 16); + } + } + + /// + /// Returns the raw bytes for this vector + /// + /// A 24 byte array containing X, Y, and Z + public byte[] GetBytes() + { + byte[] byteArray = new byte[24]; + ToBytes(byteArray, 0); + return byteArray; + } + + /// + /// Writes the raw bytes for this vector to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 24 bytes before the end of the array + public void ToBytes(byte[] dest, int pos) + { + Buffer.BlockCopy(BitConverter.GetBytes(X), 0, dest, pos + 0, 8); + Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, dest, pos + 8, 8); + Buffer.BlockCopy(BitConverter.GetBytes(Z), 0, dest, pos + 16, 8); + + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(dest, pos + 0, 8); + Array.Reverse(dest, pos + 8, 8); + Array.Reverse(dest, pos + 16, 8); + } + } + + #endregion Public Methods + + #region Static Methods + + public static Vector3d Add(Vector3d value1, Vector3d value2) + { + value1.X += value2.X; + value1.Y += value2.Y; + value1.Z += value2.Z; + return value1; + } + + public static Vector3d Clamp(Vector3d value1, Vector3d min, Vector3d max) + { + return new Vector3d( + Utils.Clamp(value1.X, min.X, max.X), + Utils.Clamp(value1.Y, min.Y, max.Y), + Utils.Clamp(value1.Z, min.Z, max.Z)); + } + + public static Vector3d Cross(Vector3d value1, Vector3d value2) + { + return new Vector3d( + value1.Y * value2.Z - value2.Y * value1.Z, + value1.Z * value2.X - value2.Z * value1.X, + value1.X * value2.Y - value2.X * value1.Y); + } + + public static double Distance(Vector3d value1, Vector3d value2) + { + return Math.Sqrt(DistanceSquared(value1, value2)); + } + + public static double DistanceSquared(Vector3d value1, Vector3d value2) + { + return + (value1.X - value2.X) * (value1.X - value2.X) + + (value1.Y - value2.Y) * (value1.Y - value2.Y) + + (value1.Z - value2.Z) * (value1.Z - value2.Z); + } + + public static Vector3d Divide(Vector3d value1, Vector3d value2) + { + value1.X /= value2.X; + value1.Y /= value2.Y; + value1.Z /= value2.Z; + return value1; + } + + public static Vector3d Divide(Vector3d value1, double value2) + { + double factor = 1d / value2; + value1.X *= factor; + value1.Y *= factor; + value1.Z *= factor; + return value1; + } + + public static double Dot(Vector3d value1, Vector3d value2) + { + return value1.X * value2.X + value1.Y * value2.Y + value1.Z * value2.Z; + } + + public static Vector3d Lerp(Vector3d value1, Vector3d value2, double amount) + { + return new Vector3d( + Utils.Lerp(value1.X, value2.X, amount), + Utils.Lerp(value1.Y, value2.Y, amount), + Utils.Lerp(value1.Z, value2.Z, amount)); + } + + public static Vector3d Max(Vector3d value1, Vector3d value2) + { + return new Vector3d( + Math.Max(value1.X, value2.X), + Math.Max(value1.Y, value2.Y), + Math.Max(value1.Z, value2.Z)); + } + + public static Vector3d Min(Vector3d value1, Vector3d value2) + { + return new Vector3d( + Math.Min(value1.X, value2.X), + Math.Min(value1.Y, value2.Y), + Math.Min(value1.Z, value2.Z)); + } + + public static Vector3d Multiply(Vector3d value1, Vector3d value2) + { + value1.X *= value2.X; + value1.Y *= value2.Y; + value1.Z *= value2.Z; + return value1; + } + + public static Vector3d Multiply(Vector3d value1, double scaleFactor) + { + value1.X *= scaleFactor; + value1.Y *= scaleFactor; + value1.Z *= scaleFactor; + return value1; + } + + public static Vector3d Negate(Vector3d value) + { + value.X = -value.X; + value.Y = -value.Y; + value.Z = -value.Z; + return value; + } + + public static Vector3d Normalize(Vector3d value) + { + double factor = Distance(value, Zero); + if (factor > Double.Epsilon) + { + factor = 1d / factor; + value.X *= factor; + value.Y *= factor; + value.Z *= factor; + } + else + { + value.X = 0d; + value.Y = 0d; + value.Z = 0d; + } + return value; + } + + /// + /// Parse a vector from a string + /// + /// A string representation of a 3D vector, enclosed + /// in arrow brackets and separated by commas + public static Vector3d Parse(string val) + { + char[] splitChar = { ',' }; + string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); + return new Vector3d( + Double.Parse(split[0].Trim(), Utils.EnUsCulture), + Double.Parse(split[1].Trim(), Utils.EnUsCulture), + Double.Parse(split[2].Trim(), Utils.EnUsCulture)); + } + + public static bool TryParse(string val, out Vector3d result) + { + try + { + result = Parse(val); + return true; + } + catch (Exception) + { + result = Vector3d.Zero; + return false; + } + } + + /// + /// Interpolates between two vectors using a cubic equation + /// + public static Vector3d SmoothStep(Vector3d value1, Vector3d value2, double amount) + { + return new Vector3d( + Utils.SmoothStep(value1.X, value2.X, amount), + Utils.SmoothStep(value1.Y, value2.Y, amount), + Utils.SmoothStep(value1.Z, value2.Z, amount)); + } + + public static Vector3d Subtract(Vector3d value1, Vector3d value2) + { + value1.X -= value2.X; + value1.Y -= value2.Y; + value1.Z -= value2.Z; + return value1; + } + + #endregion Static Methods + + #region Overrides + + public override bool Equals(object obj) + { + return (obj is Vector3d) ? this == (Vector3d)obj : false; + } + + public bool Equals(Vector3d other) + { + return this == other; + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); + } + + /// + /// Get a formatted string representation of the vector + /// + /// A string representation of the vector + public override string ToString() + { + return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}>", X, Y, Z); + } + + /// + /// Get a string representation of the vector elements with up to three + /// decimal digits and separated by spaces only + /// + /// Raw string representation of the vector + public string ToRawString() + { + CultureInfo enUs = new CultureInfo("en-us"); + enUs.NumberFormat.NumberDecimalDigits = 3; + + return String.Format(enUs, "{0} {1} {2}", X, Y, Z); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Vector3d value1, Vector3d value2) + { + return value1.X == value2.X + && value1.Y == value2.Y + && value1.Z == value2.Z; + } + + public static bool operator !=(Vector3d value1, Vector3d value2) + { + return !(value1 == value2); + } + + public static Vector3d operator +(Vector3d value1, Vector3d value2) + { + value1.X += value2.X; + value1.Y += value2.Y; + value1.Z += value2.Z; + return value1; + } + + public static Vector3d operator -(Vector3d value) + { + value.X = -value.X; + value.Y = -value.Y; + value.Z = -value.Z; + return value; + } + + public static Vector3d operator -(Vector3d value1, Vector3d value2) + { + value1.X -= value2.X; + value1.Y -= value2.Y; + value1.Z -= value2.Z; + return value1; + } + + public static Vector3d operator *(Vector3d value1, Vector3d value2) + { + value1.X *= value2.X; + value1.Y *= value2.Y; + value1.Z *= value2.Z; + return value1; + } + + public static Vector3d operator *(Vector3d value, double scaleFactor) + { + value.X *= scaleFactor; + value.Y *= scaleFactor; + value.Z *= scaleFactor; + return value; + } + + public static Vector3d operator /(Vector3d value1, Vector3d value2) + { + value1.X /= value2.X; + value1.Y /= value2.Y; + value1.Z /= value2.Z; + return value1; + } + + public static Vector3d operator /(Vector3d value, double divider) + { + double factor = 1d / divider; + value.X *= factor; + value.Y *= factor; + value.Z *= factor; + return value; + } + + /// + /// Cross product between two vectors + /// + public static Vector3d operator %(Vector3d value1, Vector3d value2) + { + return Cross(value1, value2); + } + + /// + /// Implicit casting for Vector3 > Vector3d + /// + /// + /// + public static implicit operator Vector3d(Vector3 value) + { + return new Vector3d(value); + } + + #endregion Operators + + /// A vector with a value of 0,0,0 + public readonly static Vector3d Zero = new Vector3d(); + /// A vector with a value of 1,1,1 + public readonly static Vector3d One = new Vector3d(); + /// A unit vector facing forward (X axis), value of 1,0,0 + public readonly static Vector3d UnitX = new Vector3d(1d, 0d, 0d); + /// A unit vector facing left (Y axis), value of 0,1,0 + public readonly static Vector3d UnitY = new Vector3d(0d, 1d, 0d); + /// A unit vector facing up (Z axis), value of 0,0,1 + public readonly static Vector3d UnitZ = new Vector3d(0d, 0d, 1d); + } +} diff --git a/OpenMetaverseTypes/Vector4.cs b/OpenMetaverseTypes/Vector4.cs new file mode 100644 index 0000000..86a1aa5 --- /dev/null +++ b/OpenMetaverseTypes/Vector4.cs @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.InteropServices; +using System.Globalization; + +namespace OpenMetaverse +{ + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector4 : IComparable, IEquatable + { + /// X value + public float X; + /// Y value + public float Y; + /// Z value + public float Z; + /// W value + public float W; + + #region Constructors + + public Vector4(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public Vector4(Vector2 value, float z, float w) + { + X = value.X; + Y = value.Y; + Z = z; + W = w; + } + + public Vector4(Vector3 value, float w) + { + X = value.X; + Y = value.Y; + Z = value.Z; + W = w; + } + + public Vector4(float value) + { + X = value; + Y = value; + Z = value; + W = value; + } + + /// + /// Constructor, builds a vector from a byte array + /// + /// Byte array containing four four-byte floats + /// Beginning position in the byte array + public Vector4(byte[] byteArray, int pos) + { + X = Y = Z = W = 0f; + FromBytes(byteArray, pos); + } + + public Vector4(Vector4 value) + { + X = value.X; + Y = value.Y; + Z = value.Z; + W = value.W; + } + + #endregion Constructors + + #region Public Methods + + public float Length() + { + return (float)Math.Sqrt(DistanceSquared(this, Zero)); + } + + public float LengthSquared() + { + return DistanceSquared(this, Zero); + } + + public void Normalize() + { + this = Normalize(this); + } + + /// + /// Test if this vector is equal to another vector, within a given + /// tolerance range + /// + /// Vector to test against + /// The acceptable magnitude of difference + /// between the two vectors + /// True if the magnitude of difference between the two vectors + /// is less than the given tolerance, otherwise false + public bool ApproxEquals(Vector4 vec, float tolerance) + { + Vector4 diff = this - vec; + return (diff.LengthSquared() <= tolerance * tolerance); + } + + /// + /// IComparable.CompareTo implementation + /// + public int CompareTo(Vector4 vector) + { + return Length().CompareTo(vector.Length()); + } + + /// + /// Test if this vector is composed of all finite numbers + /// + public bool IsFinite() + { + return (Utils.IsFinite(X) && Utils.IsFinite(Y) && Utils.IsFinite(Z) && Utils.IsFinite(W)); + } + + /// + /// Builds a vector from a byte array + /// + /// Byte array containing a 16 byte vector + /// Beginning position in the byte array + public void FromBytes(byte[] byteArray, int pos) + { + if (!BitConverter.IsLittleEndian) + { + // Big endian architecture + byte[] conversionBuffer = new byte[16]; + + Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 16); + + Array.Reverse(conversionBuffer, 0, 4); + Array.Reverse(conversionBuffer, 4, 4); + Array.Reverse(conversionBuffer, 8, 4); + Array.Reverse(conversionBuffer, 12, 4); + + X = BitConverter.ToSingle(conversionBuffer, 0); + Y = BitConverter.ToSingle(conversionBuffer, 4); + Z = BitConverter.ToSingle(conversionBuffer, 8); + W = BitConverter.ToSingle(conversionBuffer, 12); + } + else + { + // Little endian architecture + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + W = BitConverter.ToSingle(byteArray, pos + 12); + } + } + + /// + /// Returns the raw bytes for this vector + /// + /// A 16 byte array containing X, Y, Z, and W + public byte[] GetBytes() + { + byte[] byteArray = new byte[16]; + ToBytes(byteArray, 0); + return byteArray; + } + + /// + /// Writes the raw bytes for this vector to a byte array + /// + /// Destination byte array + /// Position in the destination array to start + /// writing. Must be at least 16 bytes before the end of the array + public void ToBytes(byte[] dest, int pos) + { + Buffer.BlockCopy(BitConverter.GetBytes(X), 0, dest, pos + 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, dest, pos + 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Z), 0, dest, pos + 8, 4); + Buffer.BlockCopy(BitConverter.GetBytes(W), 0, dest, pos + 12, 4); + + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(dest, pos + 0, 4); + Array.Reverse(dest, pos + 4, 4); + Array.Reverse(dest, pos + 8, 4); + Array.Reverse(dest, pos + 12, 4); + } + } + + #endregion Public Methods + + #region Static Methods + + public static Vector4 Add(Vector4 value1, Vector4 value2) + { + value1.W += value2.W; + value1.X += value2.X; + value1.Y += value2.Y; + value1.Z += value2.Z; + return value1; + } + + public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max) + { + return new Vector4( + Utils.Clamp(value1.X, min.X, max.X), + Utils.Clamp(value1.Y, min.Y, max.Y), + Utils.Clamp(value1.Z, min.Z, max.Z), + Utils.Clamp(value1.W, min.W, max.W)); + } + + public static float Distance(Vector4 value1, Vector4 value2) + { + return (float)Math.Sqrt(DistanceSquared(value1, value2)); + } + + public static float DistanceSquared(Vector4 value1, Vector4 value2) + { + return + (value1.W - value2.W) * (value1.W - value2.W) + + (value1.X - value2.X) * (value1.X - value2.X) + + (value1.Y - value2.Y) * (value1.Y - value2.Y) + + (value1.Z - value2.Z) * (value1.Z - value2.Z); + } + + public static Vector4 Divide(Vector4 value1, Vector4 value2) + { + value1.W /= value2.W; + value1.X /= value2.X; + value1.Y /= value2.Y; + value1.Z /= value2.Z; + return value1; + } + + public static Vector4 Divide(Vector4 value1, float divider) + { + float factor = 1f / divider; + value1.W *= factor; + value1.X *= factor; + value1.Y *= factor; + value1.Z *= factor; + return value1; + } + + public static float Dot(Vector4 vector1, Vector4 vector2) + { + return vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z + vector1.W * vector2.W; + } + + public static Vector4 Lerp(Vector4 value1, Vector4 value2, float amount) + { + return new Vector4( + Utils.Lerp(value1.X, value2.X, amount), + Utils.Lerp(value1.Y, value2.Y, amount), + Utils.Lerp(value1.Z, value2.Z, amount), + Utils.Lerp(value1.W, value2.W, amount)); + } + + public static Vector4 Max(Vector4 value1, Vector4 value2) + { + return new Vector4( + Math.Max(value1.X, value2.X), + Math.Max(value1.Y, value2.Y), + Math.Max(value1.Z, value2.Z), + Math.Max(value1.W, value2.W)); + } + + public static Vector4 Min(Vector4 value1, Vector4 value2) + { + return new Vector4( + Math.Min(value1.X, value2.X), + Math.Min(value1.Y, value2.Y), + Math.Min(value1.Z, value2.Z), + Math.Min(value1.W, value2.W)); + } + + public static Vector4 Multiply(Vector4 value1, Vector4 value2) + { + value1.W *= value2.W; + value1.X *= value2.X; + value1.Y *= value2.Y; + value1.Z *= value2.Z; + return value1; + } + + public static Vector4 Multiply(Vector4 value1, float scaleFactor) + { + value1.W *= scaleFactor; + value1.X *= scaleFactor; + value1.Y *= scaleFactor; + value1.Z *= scaleFactor; + return value1; + } + + public static Vector4 Negate(Vector4 value) + { + value.X = -value.X; + value.Y = -value.Y; + value.Z = -value.Z; + value.W = -value.W; + return value; + } + + public static Vector4 Normalize(Vector4 vector) + { + const float MAG_THRESHOLD = 0.0000001f; + float factor = DistanceSquared(vector, Zero); + if (factor > MAG_THRESHOLD) + { + factor = 1f / (float)Math.Sqrt(factor); + vector.X *= factor; + vector.Y *= factor; + vector.Z *= factor; + vector.W *= factor; + } + else + { + vector.X = 0f; + vector.Y = 0f; + vector.Z = 0f; + vector.W = 0f; + } + return vector; + } + + public static Vector4 SmoothStep(Vector4 value1, Vector4 value2, float amount) + { + return new Vector4( + Utils.SmoothStep(value1.X, value2.X, amount), + Utils.SmoothStep(value1.Y, value2.Y, amount), + Utils.SmoothStep(value1.Z, value2.Z, amount), + Utils.SmoothStep(value1.W, value2.W, amount)); + } + + public static Vector4 Subtract(Vector4 value1, Vector4 value2) + { + value1.W -= value2.W; + value1.X -= value2.X; + value1.Y -= value2.Y; + value1.Z -= value2.Z; + return value1; + } + + public static Vector4 Transform(Vector2 position, Matrix4 matrix) + { + return new Vector4( + (position.X * matrix.M11) + (position.Y * matrix.M21) + matrix.M41, + (position.X * matrix.M12) + (position.Y * matrix.M22) + matrix.M42, + (position.X * matrix.M13) + (position.Y * matrix.M23) + matrix.M43, + (position.X * matrix.M14) + (position.Y * matrix.M24) + matrix.M44); + } + + public static Vector4 Transform(Vector3 position, Matrix4 matrix) + { + return new Vector4( + (position.X * matrix.M11) + (position.Y * matrix.M21) + (position.Z * matrix.M31) + matrix.M41, + (position.X * matrix.M12) + (position.Y * matrix.M22) + (position.Z * matrix.M32) + matrix.M42, + (position.X * matrix.M13) + (position.Y * matrix.M23) + (position.Z * matrix.M33) + matrix.M43, + (position.X * matrix.M14) + (position.Y * matrix.M24) + (position.Z * matrix.M34) + matrix.M44); + } + + public static Vector4 Transform(Vector4 vector, Matrix4 matrix) + { + return new Vector4( + (vector.X * matrix.M11) + (vector.Y * matrix.M21) + (vector.Z * matrix.M31) + (vector.W * matrix.M41), + (vector.X * matrix.M12) + (vector.Y * matrix.M22) + (vector.Z * matrix.M32) + (vector.W * matrix.M42), + (vector.X * matrix.M13) + (vector.Y * matrix.M23) + (vector.Z * matrix.M33) + (vector.W * matrix.M43), + (vector.X * matrix.M14) + (vector.Y * matrix.M24) + (vector.Z * matrix.M34) + (vector.W * matrix.M44)); + } + + public static Vector4 Parse(string val) + { + char[] splitChar = { ',' }; + string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); + return new Vector4( + float.Parse(split[0].Trim(), Utils.EnUsCulture), + float.Parse(split[1].Trim(), Utils.EnUsCulture), + float.Parse(split[2].Trim(), Utils.EnUsCulture), + float.Parse(split[3].Trim(), Utils.EnUsCulture)); + } + + public static bool TryParse(string val, out Vector4 result) + { + try + { + result = Parse(val); + return true; + } + catch (Exception) + { + result = new Vector4(); + return false; + } + } + + #endregion Static Methods + + #region Overrides + + public override bool Equals(object obj) + { + return (obj is Vector4) ? this == (Vector4)obj : false; + } + + public bool Equals(Vector4 other) + { + return W == other.W + && X == other.X + && Y == other.Y + && Z == other.Z; + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode(); + } + + public override string ToString() + { + return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}, {3}>", X, Y, Z, W); + } + + /// + /// Get a string representation of the vector elements with up to three + /// decimal digits and separated by spaces only + /// + /// Raw string representation of the vector + public string ToRawString() + { + CultureInfo enUs = new CultureInfo("en-us"); + enUs.NumberFormat.NumberDecimalDigits = 3; + + return String.Format(enUs, "{0} {1} {2} {3}", X, Y, Z, W); + } + + #endregion Overrides + + #region Operators + + public static bool operator ==(Vector4 value1, Vector4 value2) + { + return value1.W == value2.W + && value1.X == value2.X + && value1.Y == value2.Y + && value1.Z == value2.Z; + } + + public static bool operator !=(Vector4 value1, Vector4 value2) + { + return !(value1 == value2); + } + + public static Vector4 operator +(Vector4 value1, Vector4 value2) + { + value1.W += value2.W; + value1.X += value2.X; + value1.Y += value2.Y; + value1.Z += value2.Z; + return value1; + } + + public static Vector4 operator -(Vector4 value) + { + return new Vector4(-value.X, -value.Y, -value.Z, -value.W); + } + + public static Vector4 operator -(Vector4 value1, Vector4 value2) + { + value1.W -= value2.W; + value1.X -= value2.X; + value1.Y -= value2.Y; + value1.Z -= value2.Z; + return value1; + } + + public static Vector4 operator *(Vector4 value1, Vector4 value2) + { + value1.W *= value2.W; + value1.X *= value2.X; + value1.Y *= value2.Y; + value1.Z *= value2.Z; + return value1; + } + + public static Vector4 operator *(Vector4 value1, float scaleFactor) + { + value1.W *= scaleFactor; + value1.X *= scaleFactor; + value1.Y *= scaleFactor; + value1.Z *= scaleFactor; + return value1; + } + + public static Vector4 operator /(Vector4 value1, Vector4 value2) + { + value1.W /= value2.W; + value1.X /= value2.X; + value1.Y /= value2.Y; + value1.Z /= value2.Z; + return value1; + } + + public static Vector4 operator /(Vector4 value1, float divider) + { + float factor = 1f / divider; + value1.W *= factor; + value1.X *= factor; + value1.Y *= factor; + value1.Z *= factor; + return value1; + } + + #endregion Operators + + /// A vector with a value of 0,0,0,0 + public readonly static Vector4 Zero = new Vector4(); + /// A vector with a value of 1,1,1,1 + public readonly static Vector4 One = new Vector4(1f, 1f, 1f, 1f); + /// A vector with a value of 1,0,0,0 + public readonly static Vector4 UnitX = new Vector4(1f, 0f, 0f, 0f); + /// A vector with a value of 0,1,0,0 + public readonly static Vector4 UnitY = new Vector4(0f, 1f, 0f, 0f); + /// A vector with a value of 0,0,1,0 + public readonly static Vector4 UnitZ = new Vector4(0f, 0f, 1f, 0f); + /// A vector with a value of 0,0,0,1 + public readonly static Vector4 UnitW = new Vector4(0f, 0f, 0f, 1f); + } +} diff --git a/PlexView.build b/PlexView.build new file mode 100644 index 0000000..a24d4c7 --- /dev/null +++ b/PlexView.build @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PlexView.mds b/PlexView.mds new file mode 100644 index 0000000..fc8c768 --- /dev/null +++ b/PlexView.mds @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Programs/examples/PlexView/PlexView.cs b/Programs/examples/PlexView/PlexView.cs new file mode 100644 index 0000000..4acc028 --- /dev/null +++ b/Programs/examples/PlexView/PlexView.cs @@ -0,0 +1,33 @@ +using System; +using OpenMetaverse; + +namespace PlexView +{ + public class PlexView + { + public PlexView (string[] args) + { + GridClient client = new GridClient(); + client.Settings.LOGIN_SERVER = "http://login.osgrid.org/"; + if (client.Network.Login("", "", "", "FirstBot", "1.0")) + { + // Yay we made it! let's print out the message of the day + Console.WriteLine("You have successfully logged into Second Life!\n The Message of the day is {0}\nPress any Key to Logout", + client.Network.LoginMessage); + + Console.ReadLine(); // Wait for user to press a key before we continue + + client.Network.Logout(); // Lets logout since we're done here + } + else + { + // tell the user why the login failed + Console.WriteLine("We were unable to login to Second Life, The Login Server said: {0}", + client.Network.LoginMessage); + } + Console.WriteLine("Press Any Key to Exit"); + Console.ReadLine(); // Wait for user to press a key before we exit + } + } +} + diff --git a/Programs/examples/PlexView/PlexView.exe.build b/Programs/examples/PlexView/PlexView.exe.build new file mode 100644 index 0000000..50d3bde --- /dev/null +++ b/Programs/examples/PlexView/PlexView.exe.build @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Programs/examples/PlexView/PlexView.mdp b/Programs/examples/PlexView/PlexView.mdp new file mode 100644 index 0000000..7449bd0 --- /dev/null +++ b/Programs/examples/PlexView/PlexView.mdp @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Programs/examples/PlexView/Program.cs b/Programs/examples/PlexView/Program.cs new file mode 100644 index 0000000..7b5083d --- /dev/null +++ b/Programs/examples/PlexView/Program.cs @@ -0,0 +1,13 @@ +using System; + +namespace PlexView +{ + public class Program + { + public static void Main (string[] args) + { + new PlexView(args); + } + } +} + diff --git a/Programs/examples/PlexView/Properties/AssemblyInfo.cs b/Programs/examples/PlexView/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6be8932 --- /dev/null +++ b/Programs/examples/PlexView/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PlexView")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PlexView")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("83715687-9058-4d2a-8090-d8726dd5cd74")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Programs/examples/PlexView/copy2bin/PlexView.exe.config b/Programs/examples/PlexView/copy2bin/PlexView.exe.config new file mode 100644 index 0000000..fd879d8 --- /dev/null +++ b/Programs/examples/PlexView/copy2bin/PlexView.exe.config @@ -0,0 +1,21 @@ + + + +
+ + + + + + + + + + + + + + + + + diff --git a/Programs/examples/TestClient/Arguments.cs b/Programs/examples/TestClient/Arguments.cs new file mode 100644 index 0000000..7e3bf4b --- /dev/null +++ b/Programs/examples/TestClient/Arguments.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Specialized; +using System.Text.RegularExpressions; + +namespace CommandLine.Utility +{ + /// + /// Arguments class + /// + public class Arguments + { + // Variables + private StringDictionary Parameters; + + // Constructor + public Arguments(string[] Args) + { + Parameters = new StringDictionary(); + Regex Splitter = new Regex(@"^-{1,2}|=", + RegexOptions.IgnoreCase | RegexOptions.Compiled); + + Regex Remover = new Regex(@"^['""]?(.*?)['""]?$", + RegexOptions.IgnoreCase | RegexOptions.Compiled); + + string Parameter = null; + string[] Parts; + + // Valid parameters forms: + // {-,/,--}param{ ,=,:}((",')value(",')) + // Examples: + // -param1 value1 --param2 + // /param4=happy -param5 '--=nice=--' + foreach (string Txt in Args) + { + // Look for new parameters (-,/ or --) and a + // possible enclosed value (=,:) + Parts = Splitter.Split(Txt, 3); + + switch (Parts.Length) + { + // Found a value (for the last parameter + // found (space separator)) + case 1: + if (Parameter != null) + { + if (!Parameters.ContainsKey(Parameter)) + { + Parts[0] = + Remover.Replace(Parts[0], "$1"); + + Parameters.Add(Parameter, Parts[0]); + } + Parameter = null; + } + // else Error: no parameter waiting for a value (skipped) + break; + + // Found just a parameter + case 2: + // The last parameter is still waiting. + // With no value, set it to true. + if (Parameter != null) + { + if (!Parameters.ContainsKey(Parameter)) + Parameters.Add(Parameter, "true"); + } + Parameter = Parts[1]; + break; + + // Parameter with enclosed value + case 3: + // The last parameter is still waiting. + // With no value, set it to true. + if (Parameter != null) + { + if (!Parameters.ContainsKey(Parameter)) + Parameters.Add(Parameter, "true"); + } + + Parameter = Parts[1]; + + // Remove possible enclosing characters (",') + if (!Parameters.ContainsKey(Parameter)) + { + Parts[2] = Remover.Replace(Parts[2], "$1"); + Parameters.Add(Parameter, Parts[2]); + } + + Parameter = null; + break; + } + } + // In case a parameter is still waiting + if (Parameter != null) + { + if (!Parameters.ContainsKey(Parameter)) + Parameters.Add(Parameter, "true"); + } + } + + // Retrieve a parameter value if it exists + // (overriding C# indexer property) + public string this[string Param] + { + get + { + return (Parameters[Param]); + } + } + } +} diff --git a/Programs/examples/TestClient/ClientManager.cs b/Programs/examples/TestClient/ClientManager.cs new file mode 100644 index 0000000..6382cf1 --- /dev/null +++ b/Programs/examples/TestClient/ClientManager.cs @@ -0,0 +1,387 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Xml; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class LoginDetails + { + public string FirstName; + public string LastName; + public string Password; + public string StartLocation; + public bool GroupCommands; + public string MasterName; + public UUID MasterKey; + public string URI; + } + + public class StartPosition + { + public string sim; + public int x; + public int y; + public int z; + + public StartPosition() + { + this.sim = null; + this.x = 0; + this.y = 0; + this.z = 0; + } + } + + public sealed class ClientManager + { + const string VERSION = "1.0.0"; + + class Singleton { internal static readonly ClientManager Instance = new ClientManager(); } + public static ClientManager Instance { get { return Singleton.Instance; } } + + public Dictionary Clients = new Dictionary(); + public Dictionary> SimPrims = new Dictionary>(); + + public bool Running = true; + public bool GetTextures = false; + public volatile int PendingLogins = 0; + public string onlyAvatar = String.Empty; + + ClientManager() + { + } + + public void Start(List accounts, bool getTextures) + { + GetTextures = getTextures; + + foreach (LoginDetails account in accounts) + Login(account); + } + + public TestClient Login(string[] args) + { + if (args.Length < 3) + { + Console.WriteLine("Usage: login firstname lastname password [simname] [login server url]"); + return null; + } + LoginDetails account = new LoginDetails(); + account.FirstName = args[0]; + account.LastName = args[1]; + account.Password = args[2]; + + if (args.Length > 3) + { + // If it looks like a full starting position was specified, parse it + if (args[3].StartsWith("http")) + { + account.URI = args[3]; + } + else + { + if (args[3].IndexOf('/') >= 0) + { + char sep = '/'; + string[] startbits = args[3].Split(sep); + try + { + account.StartLocation = NetworkManager.StartLocation(startbits[0], Int32.Parse(startbits[1]), + Int32.Parse(startbits[2]), Int32.Parse(startbits[3])); + } + catch (FormatException) { } + } + + // Otherwise, use the center of the named region + if (account.StartLocation == null) + account.StartLocation = NetworkManager.StartLocation(args[3], 128, 128, 40); + } + } + + if (args.Length > 4) + if (args[4].StartsWith("http")) + account.URI = args[4]; + + if (string.IsNullOrEmpty(account.URI)) + account.URI = Program.LoginURI; + Logger.Log("Using login URI " + account.URI, Helpers.LogLevel.Info); + + return Login(account); + } + + public TestClient Login(LoginDetails account) + { + // Check if this client is already logged in + foreach (TestClient c in Clients.Values) + { + if (c.Self.FirstName == account.FirstName && c.Self.LastName == account.LastName) + { + Logout(c); + break; + } + } + + ++PendingLogins; + + TestClient client = new TestClient(this); + client.Network.LoginProgress += + delegate(object sender, LoginProgressEventArgs e) + { + Logger.Log(String.Format("Login {0}: {1}", e.Status, e.Message), Helpers.LogLevel.Info, client); + + if (e.Status == LoginStatus.Success) + { + Clients[client.Self.AgentID] = client; + + if (client.MasterKey == UUID.Zero) + { + UUID query = UUID.Zero; + EventHandler peopleDirCallback = + delegate(object sender2, DirPeopleReplyEventArgs dpe) + { + if (dpe.QueryID == query) + { + if (dpe.MatchedPeople.Count != 1) + { + Logger.Log("Unable to resolve master key from " + client.MasterName, Helpers.LogLevel.Warning); + } + else + { + client.MasterKey = dpe.MatchedPeople[0].AgentID; + Logger.Log("Master key resolved to " + client.MasterKey, Helpers.LogLevel.Info); + } + } + }; + + client.Directory.DirPeopleReply += peopleDirCallback; + query = client.Directory.StartPeopleSearch(client.MasterName, 0); + } + + Logger.Log("Logged in " + client.ToString(), Helpers.LogLevel.Info); + --PendingLogins; + } + else if (e.Status == LoginStatus.Failed) + { + Logger.Log("Failed to login " + account.FirstName + " " + account.LastName + ": " + + client.Network.LoginMessage, Helpers.LogLevel.Warning); + --PendingLogins; + } + }; + + // Optimize the throttle + client.Throttle.Wind = 0; + client.Throttle.Cloud = 0; + client.Throttle.Land = 1000000; + client.Throttle.Task = 1000000; + + client.GroupCommands = account.GroupCommands; + client.MasterName = account.MasterName; + client.MasterKey = account.MasterKey; + client.AllowObjectMaster = client.MasterKey != UUID.Zero; // Require UUID for object master. + + LoginParams loginParams = client.Network.DefaultLoginParams( + account.FirstName, account.LastName, account.Password, "TestClient", VERSION); + + if (!String.IsNullOrEmpty(account.StartLocation)) + loginParams.Start = account.StartLocation; + + if (!String.IsNullOrEmpty(account.URI)) + loginParams.URI = account.URI; + + client.Network.BeginLogin(loginParams); + return client; + } + + /// + /// + /// + public void Run(bool noGUI) + { + if (noGUI) + { + while (Running) + { + Thread.Sleep(2 * 1000); + } + } + else { + Console.WriteLine("Type quit to exit. Type help for a command list."); + + while (Running) + { + PrintPrompt(); + string input = Console.ReadLine(); + DoCommandAll(input, UUID.Zero); + } + } + + foreach (GridClient client in Clients.Values) + { + if (client.Network.Connected) + client.Network.Logout(); + } + } + + private void PrintPrompt() + { + int online = 0; + + foreach (GridClient client in Clients.Values) + { + if (client.Network.Connected) online++; + } + + Console.Write(online + " avatars online> "); + } + + /// + /// + /// + /// + /// + /// + public void DoCommandAll(string cmd, UUID fromAgentID) + { + string[] tokens = cmd.Trim().Split(new char[] { ' ', '\t' }); + if (tokens.Length == 0) + return; + + string firstToken = tokens[0].ToLower(); + if (String.IsNullOrEmpty(firstToken)) + return; + + // Allow for comments when cmdline begins with ';' or '#' + if (firstToken[0] == ';' || firstToken[0] == '#') + return; + + if ('@' == firstToken[0]) { + onlyAvatar = String.Empty; + if (tokens.Length == 3) { + bool found = false; + onlyAvatar = tokens[1]+" "+tokens[2]; + foreach (TestClient client in Clients.Values) { + if ((client.ToString() == onlyAvatar) && (client.Network.Connected)) { + found = true; + break; + } + } + if (found) { + Logger.Log("Commanding only "+onlyAvatar+" now", Helpers.LogLevel.Info); + } else { + Logger.Log("Commanding nobody now. Avatar "+onlyAvatar+" is offline", Helpers.LogLevel.Info); + } + } else { + Logger.Log("Commanding all avatars now", Helpers.LogLevel.Info); + } + return; + } + + string[] args = new string[tokens.Length - 1]; + if (args.Length > 0) + Array.Copy(tokens, 1, args, 0, args.Length); + + if (firstToken == "login") + { + Login(args); + } + else if (firstToken == "quit") + { + Quit(); + Logger.Log("All clients logged out and program finished running.", Helpers.LogLevel.Info); + } + else if (firstToken == "help") + { + if (Clients.Count > 0) + { + foreach (TestClient client in Clients.Values) + { + Console.WriteLine(client.Commands["help"].Execute(args, UUID.Zero)); + break; + } + } + else + { + Console.WriteLine("You must login at least one bot to use the help command"); + } + } + else if (firstToken == "script") + { + // No reason to pass this to all bots, and we also want to allow it when there are no bots + ScriptCommand command = new ScriptCommand(null); + Logger.Log(command.Execute(args, UUID.Zero), Helpers.LogLevel.Info); + } + else if (firstToken == "waitforlogin") + { + // Special exception to allow this to run before any bots have logged in + if (ClientManager.Instance.PendingLogins > 0) + { + WaitForLoginCommand command = new WaitForLoginCommand(null); + Logger.Log(command.Execute(args, UUID.Zero), Helpers.LogLevel.Info); + } + else + { + Logger.Log("No pending logins", Helpers.LogLevel.Info); + } + } + else + { + // Make an immutable copy of the Clients dictionary to safely iterate over + Dictionary clientsCopy = new Dictionary(Clients); + + int completed = 0; + + foreach (TestClient client in clientsCopy.Values) + { + ThreadPool.QueueUserWorkItem((WaitCallback) + delegate(object state) + { + TestClient testClient = (TestClient)state; + if ((String.Empty == onlyAvatar) || (testClient.ToString() == onlyAvatar)) { + if (testClient.Commands.ContainsKey(firstToken)) { + string result; + try { + result = testClient.Commands[firstToken].Execute(args, fromAgentID); + Logger.Log(result, Helpers.LogLevel.Info, testClient); + } catch(Exception e) { + Logger.Log(String.Format("{0} raised exception {1}", firstToken, e), + Helpers.LogLevel.Error, + testClient); + } + } else + Logger.Log("Unknown command " + firstToken, Helpers.LogLevel.Warning); + } + + ++completed; + }, + client); + } + + while (completed < clientsCopy.Count) + Thread.Sleep(50); + } + } + + /// + /// + /// + /// + public void Logout(TestClient client) + { + Clients.Remove(client.Self.AgentID); + client.Network.Logout(); + } + + /// + /// + /// + public void Quit() + { + Running = false; + // TODO: It would be really nice if we could figure out a way to abort the ReadLine here in so that Run() will exit. + } + } +} diff --git a/Programs/examples/TestClient/Command.cs b/Programs/examples/TestClient/Command.cs new file mode 100644 index 0000000..be13c2d --- /dev/null +++ b/Programs/examples/TestClient/Command.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public enum CommandCategory : int + { + Parcel, + Appearance, + Movement, + Simulator, + Communication, + Inventory, + Objects, + Voice, + TestClient, + Friends, + Groups, + Other, + Unknown, + Search + } + + public abstract class Command : IComparable + { + public string Name; + public string Description; + public CommandCategory Category; + + public TestClient Client; + + public abstract string Execute(string[] args, UUID fromAgentID); + + /// + /// When set to true, think will be called. + /// + public bool Active; + + /// + /// Called twice per second, when Command.Active is set to true. + /// + public virtual void Think() + { + } + + public int CompareTo(object obj) + { + if (obj is Command) + { + Command c2 = (Command)obj; + return Category.CompareTo(c2.Category); + } + else + throw new ArgumentException("Object is not of type Command."); + } + + } +} diff --git a/Programs/examples/TestClient/Commands/Agent/BotsCommand.cs b/Programs/examples/TestClient/Commands/Agent/BotsCommand.cs new file mode 100644 index 0000000..ab673d9 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Agent/BotsCommand.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class BotsCommand : Command + { + private Dictionary m_AgentList = new Dictionary(); + + public BotsCommand(TestClient testClient) + { + Name = "bots"; + Description = "detects avatars that appear to be bots."; + Category = CommandCategory.Other; + testClient.Avatars.ViewerEffect += new EventHandler(Avatars_ViewerEffect); + testClient.Avatars.ViewerEffectLookAt += new EventHandler(Avatars_ViewerEffectLookAt); + testClient.Avatars.ViewerEffectPointAt += new EventHandler(Avatars_ViewerEffectPointAt); + } + + private void Avatars_ViewerEffectPointAt(object sender, ViewerEffectPointAtEventArgs e) + { + lock (m_AgentList) + { + if (m_AgentList.ContainsKey(e.SourceID)) + m_AgentList[e.SourceID] = true; + else + m_AgentList.Add(e.SourceID, true); + } + } + + private void Avatars_ViewerEffectLookAt(object sender, ViewerEffectLookAtEventArgs e) + { + lock (m_AgentList) + { + if (m_AgentList.ContainsKey(e.SourceID)) + m_AgentList[e.SourceID] = true; + else + m_AgentList.Add(e.SourceID, true); + } + } + + private void Avatars_ViewerEffect(object sender, ViewerEffectEventArgs e) + { + lock (m_AgentList) + { + if (m_AgentList.ContainsKey(e.SourceID)) + m_AgentList[e.SourceID] = true; + else + m_AgentList.Add(e.SourceID, true); + } + } + + public override string Execute(string[] args, UUID fromAgentID) + { + StringBuilder result = new StringBuilder(); + + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Client.Network.Simulators[i].ObjectsAvatars.ForEach( + delegate(Avatar av) + { + lock (m_AgentList) + { + if (!m_AgentList.ContainsKey(av.ID)) + { + result.AppendLine(); + result.AppendFormat("{0} (Group: {1}, Location: {2}, UUID: {3} LocalID: {4}) Is Probably a bot", + av.Name, av.GroupName, av.Position, av.ID, av.LocalID); + } + } + } + ); + } + } + + return result.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Agent/CloneProfileCommand.cs b/Programs/examples/TestClient/Commands/Agent/CloneProfileCommand.cs new file mode 100644 index 0000000..9a2e00c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Agent/CloneProfileCommand.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class CloneProfileCommand : Command + { + Avatar.AvatarProperties Properties; + Avatar.Interests Interests; + List Groups = new List(); + bool ReceivedProperties = false; + bool ReceivedInterests = false; + bool ReceivedGroups = false; + ManualResetEvent ReceivedProfileEvent = new ManualResetEvent(false); + + public CloneProfileCommand(TestClient testClient) + { + testClient.Avatars.AvatarInterestsReply += new EventHandler(Avatars_AvatarInterestsReply); + testClient.Avatars.AvatarPropertiesReply += new EventHandler(Avatars_AvatarPropertiesReply); + testClient.Avatars.AvatarGroupsReply += new EventHandler(Avatars_AvatarGroupsReply); + testClient.Groups.GroupJoinedReply += new EventHandler(Groups_OnGroupJoined); + testClient.Avatars.AvatarPicksReply += new EventHandler(Avatars_AvatarPicksReply); + testClient.Avatars.PickInfoReply += new EventHandler(Avatars_PickInfoReply); + + Name = "cloneprofile"; + Description = "Clones another avatars profile as closely as possible. WARNING: This command will " + + "destroy your existing profile! Usage: cloneprofile [targetuuid]"; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return Description; + + UUID targetID; + ReceivedProperties = false; + ReceivedInterests = false; + ReceivedGroups = false; + + try + { + targetID = new UUID(args[0]); + } + catch (Exception) + { + return Description; + } + + // Request all of the packets that make up an avatar profile + Client.Avatars.RequestAvatarProperties(targetID); + + //Request all of the avatars pics + Client.Avatars.RequestAvatarPicks(Client.Self.AgentID); + Client.Avatars.RequestAvatarPicks(targetID); + + // Wait for all the packets to arrive + ReceivedProfileEvent.Reset(); + ReceivedProfileEvent.WaitOne(5000, false); + + // Check if everything showed up + if (!ReceivedInterests || !ReceivedProperties || !ReceivedGroups) + return "Failed to retrieve a complete profile for that UUID"; + + // Synchronize our profile + Client.Self.UpdateInterests(Interests); + Client.Self.UpdateProfile(Properties); + + // TODO: Leave all the groups we're currently a member of? This could + // break TestClient connectivity that might be relying on group authentication + + // Attempt to join all the groups + foreach (UUID groupID in Groups) + { + Client.Groups.RequestJoinGroup(groupID); + } + + return "Synchronized our profile to the profile of " + targetID.ToString(); + } + + void Groups_OnGroupJoined(object sender, GroupOperationEventArgs e) + { + Console.WriteLine(Client.ToString() + (e.Success ? " joined " : " failed to join ") + + e.GroupID.ToString()); + + if (e.Success) + { + Console.WriteLine(Client.ToString() + " setting " + e.GroupID.ToString() + + " as the active group"); + Client.Groups.ActivateGroup(e.GroupID); + } + } + + void Avatars_PickInfoReply(object sender, PickInfoReplyEventArgs e) + { + Client.Self.PickInfoUpdate(e.PickID, e.Pick.TopPick, e.Pick.ParcelID, e.Pick.Name, e.Pick.PosGlobal, e.Pick.SnapshotID, e.Pick.Desc); + } + + void Avatars_AvatarPicksReply(object sender, AvatarPicksReplyEventArgs e) + { + foreach (KeyValuePair kvp in e.Picks) + { + if (e.AvatarID == Client.Self.AgentID) + { + Client.Self.PickDelete(kvp.Key); + } + else + { + Client.Avatars.RequestPickInfo(e.AvatarID, kvp.Key); + } + } + } + + void Avatars_AvatarGroupsReply(object sender, AvatarGroupsReplyEventArgs e) + { + lock (ReceivedProfileEvent) + { + foreach (AvatarGroup group in e.Groups) + { + Groups.Add(group.GroupID); + } + + ReceivedGroups = true; + + if (ReceivedInterests && ReceivedProperties && ReceivedGroups) + ReceivedProfileEvent.Set(); + } + } + + void Avatars_AvatarPropertiesReply(object sender, AvatarPropertiesReplyEventArgs e) + { + lock (ReceivedProfileEvent) + { + Properties = e.Properties; + ReceivedProperties = true; + + if (ReceivedInterests && ReceivedProperties && ReceivedGroups) + ReceivedProfileEvent.Set(); + } + } + + void Avatars_AvatarInterestsReply(object sender, AvatarInterestsReplyEventArgs e) + { + lock (ReceivedProfileEvent) + { + Interests = e.Interests; + ReceivedInterests = true; + + if (ReceivedInterests && ReceivedProperties && ReceivedGroups) + ReceivedProfileEvent.Set(); + } + } + + + } +} diff --git a/Programs/examples/TestClient/Commands/Agent/GenericMessageCommand.cs b/Programs/examples/TestClient/Commands/Agent/GenericMessageCommand.cs new file mode 100644 index 0000000..035ea34 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Agent/GenericMessageCommand.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + /// + /// Sends a packet of type GenericMessage to the simulator. + /// + public class GenericMessageCommand : Command + { + public GenericMessageCommand(TestClient testClient) + { + Name = "sendgeneric"; + Description = "send a generic UDP message to the simulator."; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + UUID target; + + if (args.Length < 1) + return "Usage: sendgeneric method_name [value1 value2 ...]"; + + string methodName = args[0]; + + GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = Client.Self.AgentID; + gmp.AgentData.SessionID = Client.Self.SessionID; + gmp.AgentData.TransactionID = UUID.Zero; + + gmp.MethodData.Method = Utils.StringToBytes(methodName); + gmp.MethodData.Invoice = UUID.Zero; + + gmp.ParamList = new GenericMessagePacket.ParamListBlock[args.Length - 1]; + + StringBuilder sb = new StringBuilder(); + + for (int i = 1; i < args.Length; i++) + { + GenericMessagePacket.ParamListBlock paramBlock = new GenericMessagePacket.ParamListBlock(); + paramBlock.Parameter = Utils.StringToBytes(args[i]); + gmp.ParamList[i - 1] = paramBlock; + sb.AppendFormat(" {0}", args[i]); + } + + Client.Network.SendPacket(gmp); + + return string.Format("Sent generic message with method {0}, params{1}", methodName, sb); + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Agent/PlayAnimationCommand.cs b/Programs/examples/TestClient/Commands/Agent/PlayAnimationCommand.cs new file mode 100644 index 0000000..454ed95 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Agent/PlayAnimationCommand.cs @@ -0,0 +1,82 @@ +using System; +using System.Text; +using System.Reflection; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class PlayAnimationCommand : Command + { + private Dictionary m_BuiltInAnimations = new Dictionary(Animations.ToDictionary()); + public PlayAnimationCommand(TestClient testClient) + { + Name = "play"; + Description = "Attempts to play an animation"; + Category = CommandCategory.Appearance; + } + + private string Usage() + { + String usage = "Usage:\n" + + "\tplay list - list the built in animations\n" + + "\tplay show - show any currently playing animations\n" + + "\tplay UUID - play an animation asset\n" + + "\tplay ANIMATION - where ANIMATION is one of the values returned from \"play list\"\n"; + return usage; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + StringBuilder result = new StringBuilder(); + if (args.Length != 1) + return Usage(); + + UUID animationID; + string arg = args[0].Trim(); + + if (UUID.TryParse(args[0], out animationID)) + { + Client.Self.AnimationStart(animationID, true); + } + else if (arg.ToLower().Equals("list")) + { + foreach (string key in m_BuiltInAnimations.Values) + { + result.AppendLine(key); + } + } + else if (arg.ToLower().Equals("show")) + { + Client.Self.SignaledAnimations.ForEach(delegate(KeyValuePair kvp) { + if (m_BuiltInAnimations.ContainsKey(kvp.Key)) + { + result.AppendFormat("The {0} System Animation is being played, sequence is {1}", m_BuiltInAnimations[kvp.Key], kvp.Value); + } + else + { + result.AppendFormat("The {0} Asset Animation is being played, sequence is {0}", kvp.Key, kvp.Value); + } + }); + } + else if (m_BuiltInAnimations.ContainsValue(args[0].Trim().ToUpper())) + { + foreach (var kvp in m_BuiltInAnimations) + { + if (kvp.Value.Equals(arg.ToUpper())) + { + Client.Self.AnimationStart(kvp.Key, true); + break; + } + } + } + else + { + return Usage(); + } + + return result.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Agent/TouchCommand.cs b/Programs/examples/TestClient/Commands/Agent/TouchCommand.cs new file mode 100644 index 0000000..9b3fad3 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Agent/TouchCommand.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class TouchCommand: Command + { + public TouchCommand(TestClient testClient) + { + Name = "touch"; + Description = "Attempt to touch a prim with specified UUID"; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + UUID target; + + if (args.Length != 1) + return "Usage: touch UUID"; + + if (UUID.TryParse(args[0], out target)) + { + Primitive targetPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find( + delegate(Primitive prim) + { + return prim.ID == target; + } + ); + + if (targetPrim != null) + { + Client.Self.Touch(targetPrim.LocalID); + return "Touched prim " + targetPrim.LocalID; + } + } + + return "Couldn't find a prim to touch with UUID " + args[0]; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Agent/WhoCommand.cs b/Programs/examples/TestClient/Commands/Agent/WhoCommand.cs new file mode 100644 index 0000000..dc5615e --- /dev/null +++ b/Programs/examples/TestClient/Commands/Agent/WhoCommand.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class WhoCommand: Command + { + public WhoCommand(TestClient testClient) + { + Name = "who"; + Description = "Lists seen avatars."; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + StringBuilder result = new StringBuilder(); + + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Client.Network.Simulators[i].ObjectsAvatars.ForEach( + delegate(Avatar av) + { + result.AppendLine(); + result.AppendFormat("{0} (Group: {1}, Location: {2}, UUID: {3} LocalID: {4})", + av.Name, av.GroupName, av.Position, av.ID, av.LocalID); + } + ); + } + } + + return result.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Appearance/AppearanceCommand.cs b/Programs/examples/TestClient/Commands/Appearance/AppearanceCommand.cs new file mode 100644 index 0000000..84f47c9 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Appearance/AppearanceCommand.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + /// + /// Set avatars current appearance to appearance last stored on simulator + /// + public class AppearanceCommand : Command + { + public AppearanceCommand(TestClient testClient) + { + Name = "appearance"; + Description = "Set your current appearance to your last saved appearance. Usage: appearance [rebake]"; + Category = CommandCategory.Appearance; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Client.Appearance.RequestSetAppearance((args.Length > 0 && args[0].Equals("rebake"))); + return "Appearance sequence started"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Appearance/AttachmentsCommand.cs b/Programs/examples/TestClient/Commands/Appearance/AttachmentsCommand.cs new file mode 100644 index 0000000..cb8c11c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Appearance/AttachmentsCommand.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class AttachmentsCommand : Command + { + public AttachmentsCommand(TestClient testClient) + { + Client = testClient; + Name = "attachments"; + Description = "Prints a list of the currently known agent attachments"; + Category = CommandCategory.Appearance; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + List attachments = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( + delegate(Primitive prim) { return prim.ParentID == Client.Self.LocalID; } + ); + + for (int i = 0; i < attachments.Count; i++) + { + Primitive prim = attachments[i]; + AttachmentPoint point = StateToAttachmentPoint(prim.PrimData.State); + + // TODO: Fetch properties for the objects with missing property sets so we can show names + Logger.Log(String.Format("[Attachment @ {0}] LocalID: {1} UUID: {2} Offset: {3}", + point, prim.LocalID, prim.ID, prim.Position), Helpers.LogLevel.Info, Client); + } + + return "Found " + attachments.Count + " attachments"; + } + + public static AttachmentPoint StateToAttachmentPoint(uint state) + { + const uint ATTACHMENT_MASK = 0xF0; + uint fixedState = (((byte)state & ATTACHMENT_MASK) >> 4) | (((byte)state & ~ATTACHMENT_MASK) << 4); + return (AttachmentPoint)fixedState; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Appearance/AvatarInfoCommand.cs b/Programs/examples/TestClient/Commands/Appearance/AvatarInfoCommand.cs new file mode 100644 index 0000000..e3f08d7 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Appearance/AvatarInfoCommand.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient.Commands.Appearance +{ + public class AvatarInfoCommand : Command + { + public AvatarInfoCommand(TestClient testClient) + { + Name = "avatarinfo"; + Description = "Print out information on a nearby avatar. Usage: avatarinfo [firstname] [lastname]"; + Category = CommandCategory.Appearance; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 2) + return "Usage: avatarinfo [firstname] [lastname]"; + + string targetName = String.Format("{0} {1}", args[0], args[1]); + + Avatar foundAv = Client.Network.CurrentSim.ObjectsAvatars.Find( + delegate(Avatar avatar) { return (avatar.Name == targetName); } + ); + + if (foundAv != null) + { + StringBuilder output = new StringBuilder(); + + output.AppendFormat("{0} ({1})", targetName, foundAv.ID); + output.AppendLine(); + + for (int i = 0; i < foundAv.Textures.FaceTextures.Length; i++) + { + if (foundAv.Textures.FaceTextures[i] != null) + { + Primitive.TextureEntryFace face = foundAv.Textures.FaceTextures[i]; + AvatarTextureIndex type = (AvatarTextureIndex)i; + + output.AppendFormat("{0}: {1}", type, face.TextureID); + output.AppendLine(); + } + } + + return output.ToString(); + } + else + { + return "No nearby avatar with the name " + targetName; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Appearance/CloneCommand.cs b/Programs/examples/TestClient/Commands/Appearance/CloneCommand.cs new file mode 100644 index 0000000..557e60e --- /dev/null +++ b/Programs/examples/TestClient/Commands/Appearance/CloneCommand.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class CloneCommand : Command + { + uint SerialNum = 2; + + public CloneCommand(TestClient testClient) + { + Name = "clone"; + Description = "Clone the appearance of a nearby avatar. Usage: clone [name]"; + Category = CommandCategory.Appearance; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + string targetName = String.Empty; + List matches; + + for (int ct = 0; ct < args.Length; ct++) + targetName = targetName + args[ct] + " "; + targetName = targetName.TrimEnd(); + + if (targetName.Length == 0) + return "Usage: clone [name]"; + + if (Client.Directory.PeopleSearch(DirectoryManager.DirFindFlags.People, targetName, 0, 1000 * 10, + out matches) && matches.Count > 0) + { + UUID target = matches[0].AgentID; + targetName += String.Format(" ({0})", target); + + if (Client.Appearances.ContainsKey(target)) + { + #region AvatarAppearance to AgentSetAppearance + + AvatarAppearancePacket appearance = Client.Appearances[target]; + + AgentSetAppearancePacket set = new AgentSetAppearancePacket(); + set.AgentData.AgentID = Client.Self.AgentID; + set.AgentData.SessionID = Client.Self.SessionID; + set.AgentData.SerialNum = SerialNum++; + set.AgentData.Size = new Vector3(2f, 2f, 2f); // HACK + + set.WearableData = new AgentSetAppearancePacket.WearableDataBlock[0]; + set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[appearance.VisualParam.Length]; + + for (int i = 0; i < appearance.VisualParam.Length; i++) + { + set.VisualParam[i] = new AgentSetAppearancePacket.VisualParamBlock(); + set.VisualParam[i].ParamValue = appearance.VisualParam[i].ParamValue; + } + + set.ObjectData.TextureEntry = appearance.ObjectData.TextureEntry; + + #endregion AvatarAppearance to AgentSetAppearance + + // Detach everything we are currently wearing + Client.Appearance.AddAttachments(new List(), true); + + // Send the new appearance packet + Client.Network.SendPacket(set); + + return "Cloned " + targetName; + } + else + { + return "Don't know the appearance of avatar " + targetName; + } + } + else + { + return "Couldn't find avatar " + targetName; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Appearance/WearCommand.cs b/Programs/examples/TestClient/Commands/Appearance/WearCommand.cs new file mode 100644 index 0000000..604340e --- /dev/null +++ b/Programs/examples/TestClient/Commands/Appearance/WearCommand.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class WearCommand : Command + { + public WearCommand(TestClient testClient) + { + Client = testClient; + Name = "wear"; + Description = "Wear an outfit folder from inventory. Usage: wear [outfit name]"; + Category = CommandCategory.Appearance; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: wear [outfit name] eg: 'wear Clothing/My Outfit"; + + string target = String.Empty; + + for (int ct = 0; ct < args.Length; ct++) + { + target += args[ct] + " "; + } + + target = target.TrimEnd(); + + UUID folder = Client.Inventory.FindObjectByPath(Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID, target, 20 * 1000); + + if (folder == UUID.Zero) + { + return "Outfit path " + target + " not found"; + } + + List contents = Client.Inventory.FolderContents(folder, Client.Self.AgentID, true, true, InventorySortOrder.ByName, 20 * 1000); + List items = new List(); + + if (contents == null) + { + return "Failed to get contents of " + target; + } + + foreach (InventoryBase item in contents) + { + if (item is InventoryItem) + items.Add((InventoryItem)item); + } + + Client.Appearance.ReplaceOutfit(items); + + return "Starting to change outfit to " + target; + + } + } +} diff --git a/Programs/examples/TestClient/Commands/Communication/EchoMasterCommand.cs b/Programs/examples/TestClient/Commands/Communication/EchoMasterCommand.cs new file mode 100644 index 0000000..89b619c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Communication/EchoMasterCommand.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class EchoMasterCommand: Command + { + public EchoMasterCommand(TestClient testClient) + { + Name = "echoMaster"; + Description = "Repeat everything that master says."; + Category = CommandCategory.Communication; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (!Active) + { + Active = true; + Client.Self.ChatFromSimulator += Self_ChatFromSimulator; + return "Echoing is now on."; + } + else + { + Active = false; + Client.Self.ChatFromSimulator -= Self_ChatFromSimulator; + return "Echoing is now off."; + } + } + + void Self_ChatFromSimulator(object sender, ChatEventArgs e) + { + if (e.Message.Length > 0 && (Client.MasterKey == e.SourceID || (Client.MasterName == e.FromName && !Client.AllowObjectMaster))) + Client.Self.Chat(e.Message, 0, ChatType.Normal); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Communication/IMCommand.cs b/Programs/examples/TestClient/Commands/Communication/IMCommand.cs new file mode 100644 index 0000000..ab9d3e0 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Communication/IMCommand.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class ImCommand : Command + { + string ToAvatarName = String.Empty; + ManualResetEvent NameSearchEvent = new ManualResetEvent(false); + Dictionary Name2Key = new Dictionary(); + + public ImCommand(TestClient testClient) + { + testClient.Avatars.AvatarPickerReply += Avatars_AvatarPickerReply; + + Name = "im"; + Description = "Instant message someone. Usage: im [firstname] [lastname] [message]"; + Category = CommandCategory.Communication; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 3) + return "Usage: im [firstname] [lastname] [message]"; + + ToAvatarName = args[0] + " " + args[1]; + + // Build the message + string message = String.Empty; + for (int ct = 2; ct < args.Length; ct++) + message += args[ct] + " "; + message = message.TrimEnd(); + if (message.Length > 1023) message = message.Remove(1023); + + if (!Name2Key.ContainsKey(ToAvatarName.ToLower())) + { + // Send the Query + Client.Avatars.RequestAvatarNameSearch(ToAvatarName, UUID.Random()); + + NameSearchEvent.WaitOne(6000, false); + } + + if (Name2Key.ContainsKey(ToAvatarName.ToLower())) + { + UUID id = Name2Key[ToAvatarName.ToLower()]; + + Client.Self.InstantMessage(id, message); + return "Instant Messaged " + id.ToString() + " with message: " + message; + } + else + { + return "Name lookup for " + ToAvatarName + " failed"; + } + } + + void Avatars_AvatarPickerReply(object sender, AvatarPickerReplyEventArgs e) + { + foreach (KeyValuePair kvp in e.Avatars) + { + if (kvp.Value.ToLower() == ToAvatarName.ToLower()) + { + Name2Key[ToAvatarName.ToLower()] = kvp.Key; + NameSearchEvent.Set(); + return; + } + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Communication/IMGroupCommand.cs b/Programs/examples/TestClient/Commands/Communication/IMGroupCommand.cs new file mode 100644 index 0000000..9c7719f --- /dev/null +++ b/Programs/examples/TestClient/Commands/Communication/IMGroupCommand.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class ImGroupCommand : Command + { + UUID ToGroupID = UUID.Zero; + ManualResetEvent WaitForSessionStart = new ManualResetEvent(false); + public ImGroupCommand(TestClient testClient) + { + + Name = "imgroup"; + Description = "Send an instant message to a group. Usage: imgroup [group_uuid] [message]"; + Category = CommandCategory.Communication; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 2) + return "Usage: imgroup [group_uuid] [message]"; + + + + if (UUID.TryParse(args[0], out ToGroupID)) + { + string message = String.Empty; + for (int ct = 1; ct < args.Length; ct++) + message += args[ct] + " "; + + message = message.TrimEnd(); + if (message.Length > 1023) + { + message = message.Remove(1023); + Console.WriteLine("Message truncated at 1024 characters"); + } + + Client.Self.GroupChatJoined += Self_GroupChatJoined; + + if (!Client.Self.GroupChatSessions.ContainsKey(ToGroupID)) + { + WaitForSessionStart.Reset(); + Client.Self.RequestJoinGroupChat(ToGroupID); + } + else + { + WaitForSessionStart.Set(); + } + + if (WaitForSessionStart.WaitOne(20000, false)) + { + Client.Self.InstantMessageGroup(ToGroupID, message); + } + else + { + return "Timeout waiting for group session start"; + } + + Client.Self.GroupChatJoined -= Self_GroupChatJoined; + return "Instant Messaged group " + ToGroupID.ToString() + " with message: " + message; + } + else + { + return "failed to instant message group"; + } + } + + void Self_GroupChatJoined(object sender, GroupChatJoinedEventArgs e) + { + if (e.Success) + { + Console.WriteLine("Joined {0} Group Chat Success!", e.SessionName); + WaitForSessionStart.Set(); + } + else + { + Console.WriteLine("Join Group Chat failed :("); + } + } + + + } +} diff --git a/Programs/examples/TestClient/Commands/Communication/SayCommand.cs b/Programs/examples/TestClient/Commands/Communication/SayCommand.cs new file mode 100644 index 0000000..e8d2176 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Communication/SayCommand.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class SayCommand: Command + { + public SayCommand(TestClient testClient) + { + Name = "say"; + Description = "Say something. (usage: say (optional channel) whatever)"; + Category = CommandCategory.Communication; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + int channel = 0; + int startIndex = 0; + + if (args.Length < 1) + { + return "usage: say (optional channel) whatever"; + } + else if (args.Length > 1) + { + if (Int32.TryParse(args[0], out channel)) + startIndex = 1; + } + + String message = String.Empty; + + for (int i = startIndex; i < args.Length; i++) + { + // Append a space before the next arg + if( i > 0 ) + message += " "; + message += args[i]; + } + + Client.Self.Chat(message, channel, ChatType.Normal); + + return "Said " + message.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Communication/ShoutCommand.cs b/Programs/examples/TestClient/Commands/Communication/ShoutCommand.cs new file mode 100644 index 0000000..c1c9cf7 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Communication/ShoutCommand.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class ShoutCommand : Command + { + public ShoutCommand(TestClient testClient) + { + Name = "shout"; + Description = "Shout something."; + Category = CommandCategory.Communication; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + int channel = 0; + int startIndex = 0; + string message = String.Empty; + if (args.Length < 1) + { + return "usage: shout (optional channel) whatever"; + } + else if (args.Length > 1) + { + try + { + channel = Convert.ToInt32(args[0]); + startIndex = 1; + } + catch (FormatException) + { + channel = 0; + } + } + + for (int i = startIndex; i < args.Length; i++) + { + // Append a space before the next arg + if( i > 0 ) + message += " "; + message += args[i]; + } + + Client.Self.Chat(message, channel, ChatType.Shout); + + return "Shouted " + message; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Communication/WhisperCommand.cs b/Programs/examples/TestClient/Commands/Communication/WhisperCommand.cs new file mode 100644 index 0000000..0a56489 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Communication/WhisperCommand.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class WhisperCommand : Command + { + public WhisperCommand(TestClient testClient) + { + Name = "whisper"; + Description = "Whisper something."; + Category = CommandCategory.Communication; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + int channel = 0; + int startIndex = 0; + string message = String.Empty; + if (args.Length < 1) + { + return "usage: whisper (optional channel) whatever"; + } + else if (args.Length > 1) + { + try + { + channel = Convert.ToInt32(args[0]); + startIndex = 1; + } + catch (FormatException) + { + channel = 0; + } + } + + for (int i = startIndex; i < args.Length; i++) + { + // Append a space before the next arg + if( i > 0 ) + message += " "; + message += args[i]; + } + + Client.Self.Chat(message, channel, ChatType.Whisper); + + return "Whispered " + message; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/Key2NameCommand.cs b/Programs/examples/TestClient/Commands/Directory/Key2NameCommand.cs new file mode 100644 index 0000000..a2839da --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/Key2NameCommand.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class key2nameCommand : Command + { + System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + StringBuilder result = new StringBuilder(); + public key2nameCommand(TestClient testClient) + { + Name = "key2name"; + Description = "resolve a UUID to an avatar or group name. Usage: key2name UUID"; + Category = CommandCategory.Search; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: key2name UUID"; + + UUID key; + if(!UUID.TryParse(args[0].Trim(), out key)) + { + return "UUID " + args[0].Trim() + " appears to be invalid"; + } + result.Remove(0, result.Length); + waitQuery.Reset(); + + Client.Avatars.UUIDNameReply += Avatars_OnAvatarNames; + Client.Groups.GroupProfile += Groups_OnGroupProfile; + Client.Avatars.RequestAvatarName(key); + + Client.Groups.RequestGroupProfile(key); + if (!waitQuery.WaitOne(10000, false)) + { + result.AppendLine("Timeout waiting for reply, this could mean the Key is not an avatar or a group"); + } + + Client.Avatars.UUIDNameReply -= Avatars_OnAvatarNames; + Client.Groups.GroupProfile -= Groups_OnGroupProfile; + return result.ToString(); + } + + void Groups_OnGroupProfile(object sender, GroupProfileEventArgs e) + { + result.AppendLine("Group: " + e.Group.Name + " " + e.Group.ID); + waitQuery.Set(); + } + + void Avatars_OnAvatarNames(object sender, UUIDNameReplyEventArgs e) + { + foreach (KeyValuePair kvp in e.Names) + result.AppendLine("Avatar: " + kvp.Value + " " + kvp.Key); + waitQuery.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/SearchClassifiedsCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchClassifiedsCommand.cs new file mode 100644 index 0000000..fa1b6eb --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/SearchClassifiedsCommand.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class SearchClassifiedsCommand : Command + { + System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + + public SearchClassifiedsCommand(TestClient testClient) + { + Name = "searchclassifieds"; + Description = "Searches Classified Ads. Usage: searchclassifieds [search text]"; + Category = CommandCategory.Search; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: searchclassifieds [search text]"; + + string searchText = string.Empty; + for (int i = 0; i < args.Length; i++) + searchText += args[i] + " "; + searchText = searchText.TrimEnd(); + waitQuery.Reset(); + + StringBuilder result = new StringBuilder(); + + EventHandler callback = delegate(object sender, DirClassifiedsReplyEventArgs e) + { + result.AppendFormat("Your search string '{0}' returned {1} classified ads" + System.Environment.NewLine, + searchText, e.Classifieds.Count); + foreach (DirectoryManager.Classified ad in e.Classifieds) + { + result.AppendLine(ad.ToString()); + } + + // classifieds are sent 16 ads at a time + if (e.Classifieds.Count < 16) + { + waitQuery.Set(); + } + }; + + Client.Directory.DirClassifiedsReply += callback; + + UUID searchID = Client.Directory.StartClassifiedSearch(searchText, DirectoryManager.ClassifiedCategories.Any, DirectoryManager.ClassifiedQueryFlags.Mature | DirectoryManager.ClassifiedQueryFlags.PG); + + if (!waitQuery.WaitOne(20000, false) && Client.Network.Connected) + { + result.AppendLine("Timeout waiting for simulator to respond to query."); + } + + Client.Directory.DirClassifiedsReply -= callback; + + return result.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/SearchEventsCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchEventsCommand.cs new file mode 100644 index 0000000..3029b37 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/SearchEventsCommand.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class SearchEventsCommand : Command + { + System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + int resultCount; + + public SearchEventsCommand(TestClient testClient) + { + Name = "searchevents"; + Description = "Searches Events list. Usage: searchevents [search text]"; + Category = CommandCategory.Search; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // process command line arguments + if (args.Length < 1) + return "Usage: searchevents [search text]"; + + string searchText = string.Empty; + for (int i = 0; i < args.Length; i++) + searchText += args[i] + " "; + searchText = searchText.TrimEnd(); + + waitQuery.Reset(); + + Client.Directory.DirEventsReply += Directory_DirEvents; + + // send the request to the directory manager + Client.Directory.StartEventsSearch(searchText, 0); + string result; + if (waitQuery.WaitOne(20000, false) && Client.Network.Connected) + { + result = "Your query '" + searchText + "' matched " + resultCount + " Events. "; + } + else + { + result = "Timeout waiting for simulator to respond."; + } + + Client.Directory.DirEventsReply -= Directory_DirEvents; + + return result; + } + + void Directory_DirEvents(object sender, DirEventsReplyEventArgs e) + { + if (e.MatchedEvents[0].ID == 0 && e.MatchedEvents.Count == 1) + { + Console.WriteLine("No Results matched your search string"); + } + else + { + foreach (DirectoryManager.EventsSearchData ev in e.MatchedEvents) + { + Console.WriteLine("Event ID: {0} Event Name: {1} Event Date: {2}", ev.ID, ev.Name, ev.Date); + } + } + resultCount = e.MatchedEvents.Count; + waitQuery.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/SearchGroupsCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchGroupsCommand.cs new file mode 100644 index 0000000..c09fb69 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/SearchGroupsCommand.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class SearchGroupsCommand : Command + { + System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + int resultCount = 0; + + public SearchGroupsCommand(TestClient testClient) + { + Name = "searchgroups"; + Description = "Searches groups. Usage: searchgroups [search text]"; + Category = CommandCategory.Groups; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // process command line arguments + if (args.Length < 1) + return "Usage: searchgroups [search text]"; + + string searchText = string.Empty; + for (int i = 0; i < args.Length; i++) + searchText += args[i] + " "; + searchText = searchText.TrimEnd(); + + waitQuery.Reset(); + + Client.Directory.DirGroupsReply += Directory_DirGroups; + + // send the request to the directory manager + Client.Directory.StartGroupSearch(searchText, 0); + + string result; + if (waitQuery.WaitOne(20000, false) && Client.Network.Connected) + { + result = "Your query '" + searchText + "' matched " + resultCount + " Groups. "; + } + else + { + result = "Timeout waiting for simulator to respond."; + } + + Client.Directory.DirGroupsReply -= Directory_DirGroups; + + return result; + } + + void Directory_DirGroups(object sender, DirGroupsReplyEventArgs e) + { + if (e.MatchedGroups.Count > 0) + { + foreach (DirectoryManager.GroupSearchData group in e.MatchedGroups) + { + Console.WriteLine("Group {1} ({0}) has {2} members", group.GroupID, group.GroupName, group.Members); + } + } + else + { + Console.WriteLine("Didn't find any groups that matched your query :("); + } + waitQuery.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/SearchLandCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchLandCommand.cs new file mode 100644 index 0000000..2bc7554 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/SearchLandCommand.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + /// + /// + /// + public class SearchLandCommand : Command + { + private System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + private StringBuilder result = new StringBuilder(); + + /// + /// Construct a new instance of the SearchLandCommand + /// + /// + public SearchLandCommand(TestClient testClient) + { + Name = "searchland"; + Description = "Searches for land for sale. for usage information type: searchland"; + Category = CommandCategory.Search; + } + + /// + /// Show commandusage + /// + /// A string containing the parameter usage instructions + public string ShowUsage() + { + return "Usage: searchland [type] [max price] [min size]\n" + + "\twhere [type] is one of: mainland, auction, estate, all\n" + + "\tif [max price] or [min size] are 0 that parameter will be ignored\n\n" + + "example: \"searchland mainland 0 512\" // shows the lowest priced mainland that is larger than 512/m2\n\n"; + } + + /// + /// + /// + /// + /// + /// + public override string Execute(string[] args, UUID fromAgentID) + { + // process command line arguments + if (args.Length < 3) + return ShowUsage(); + + string searchType = args[0].Trim().ToLower(); + int maxPrice; + int minSize; + + DirectoryManager.SearchTypeFlags searchTypeFlags = DirectoryManager.SearchTypeFlags.Any; + + if (searchType.StartsWith("au")) + searchTypeFlags = DirectoryManager.SearchTypeFlags.Auction; + else if (searchType.StartsWith("m")) + searchTypeFlags = DirectoryManager.SearchTypeFlags.Mainland; + else if (searchType.StartsWith("e")) + searchTypeFlags = DirectoryManager.SearchTypeFlags.Estate; + else if (searchType.StartsWith("al")) + searchTypeFlags = DirectoryManager.SearchTypeFlags.Any; + else + return ShowUsage(); + + // initialize some default flags we'll use in the search + DirectoryManager.DirFindFlags queryFlags = DirectoryManager.DirFindFlags.SortAsc | DirectoryManager.DirFindFlags.PerMeterSort + | DirectoryManager.DirFindFlags.IncludeAdult | DirectoryManager.DirFindFlags.IncludePG | DirectoryManager.DirFindFlags.IncludeMature; + + // validate the parameters passed + if (int.TryParse(args[1], out maxPrice) && int.TryParse(args[2], out minSize)) + { + // if the [max price] parameter is greater than 0, we'll enable the flag to limit by price + if (maxPrice > 0) + queryFlags |= DirectoryManager.DirFindFlags.LimitByPrice; + + // if the [min size] parameter is greater than 0, we'll enable the flag to limit by area + if (minSize > 0) + queryFlags |= DirectoryManager.DirFindFlags.LimitByArea; + } + else + { + return ShowUsage(); + } + + //waitQuery.Reset(); + + // subscribe to the event that returns the search results + Client.Directory.DirLandReply += Directory_DirLand; + + // send the request to the directory manager + Client.Directory.StartLandSearch(queryFlags, searchTypeFlags, maxPrice, minSize, 0); + + if (!waitQuery.WaitOne(20000, false) && Client.Network.Connected) + { + result.AppendLine("Timeout waiting for simulator to respond."); + } + + // unsubscribe to the event that returns the search results + Client.Directory.DirLandReply -= Directory_DirLand; + + // return the results + return result.ToString(); + } + + /// + /// Process the search reply + /// + /// + /// + private void Directory_DirLand(object sender, DirLandReplyEventArgs e) + { + + foreach (DirectoryManager.DirectoryParcel searchResult in e.DirParcels) + { + // add the results to the StringBuilder object that contains the results + result.AppendLine(searchResult.ToString()); + } + result.AppendFormat("{0} results" + System.Environment.NewLine, e.DirParcels.Count); + // let the calling method know we have data + waitQuery.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/SearchPeopleCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchPeopleCommand.cs new file mode 100644 index 0000000..a9efc77 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/SearchPeopleCommand.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class SearchPeopleCommand : Command + { + System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + int resultCount = 0; + + public SearchPeopleCommand(TestClient testClient) + { + Name = "searchpeople"; + Description = "Searches for other avatars. Usage: searchpeople [search text]"; + Category = CommandCategory.Search; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // process command line arguments + if (args.Length < 1) + return "Usage: searchpeople [search text]"; + + string searchText = string.Empty; + for (int i = 0; i < args.Length; i++) + searchText += args[i] + " "; + searchText = searchText.TrimEnd(); + + waitQuery.Reset(); + + + Client.Directory.DirPeopleReply += Directory_DirPeople; + + // send the request to the directory manager + Client.Directory.StartPeopleSearch(searchText, 0); + + string result; + if (waitQuery.WaitOne(20000, false) && Client.Network.Connected) + { + result = "Your query '" + searchText + "' matched " + resultCount + " People. "; + } + else + { + result = "Timeout waiting for simulator to respond."; + } + + Client.Directory.DirPeopleReply -= Directory_DirPeople; + + return result; + } + + void Directory_DirPeople(object sender, DirPeopleReplyEventArgs e) + { + if (e.MatchedPeople.Count > 0) + { + foreach (DirectoryManager.AgentSearchData agent in e.MatchedPeople) + { + Console.WriteLine("{0} {1} ({2})", agent.FirstName, agent.LastName, agent.AgentID); + } + } + else + { + Console.WriteLine("Didn't find any people that matched your query :("); + } + waitQuery.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/SearchPlacesCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchPlacesCommand.cs new file mode 100644 index 0000000..93aafe8 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/SearchPlacesCommand.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class SearchPlacesCommand : Command + { + System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + + public SearchPlacesCommand(TestClient testClient) + { + Name = "searchplaces"; + Description = "Searches Places. Usage: searchplaces [search text]"; + Category = CommandCategory.Search; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: searchplaces [search text]"; + + string searchText = string.Empty; + for (int i = 0; i < args.Length; i++) + searchText += args[i] + " "; + searchText = searchText.TrimEnd(); + waitQuery.Reset(); + + StringBuilder result = new StringBuilder(); + + EventHandler callback = delegate(object sender, PlacesReplyEventArgs e) + { + result.AppendFormat("Your search string '{0}' returned {1} results" + System.Environment.NewLine, + searchText, e.MatchedPlaces.Count); + foreach (DirectoryManager.PlacesSearchData place in e.MatchedPlaces) + { + result.AppendLine(place.ToString()); + } + + waitQuery.Set(); + }; + + Client.Directory.PlacesReply += callback; + Client.Directory.StartPlacesSearch(searchText); + + if (!waitQuery.WaitOne(20000, false) && Client.Network.Connected) + { + result.AppendLine("Timeout waiting for simulator to respond to query."); + } + + Client.Directory.PlacesReply -= callback; + + return result.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Directory/ShowEventDetailsCommand.cs b/Programs/examples/TestClient/Commands/Directory/ShowEventDetailsCommand.cs new file mode 100644 index 0000000..47288a8 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/ShowEventDetailsCommand.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class ShowEventDetailsCommand : Command + { + public ShowEventDetailsCommand(TestClient testClient) + { + Name = "showevent"; + Description = "Shows an Events details. Usage: showevent [eventID]"; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: showevent [eventID] (use searchevents to get ID)"; + + Client.Directory.EventInfoReply += Directory_EventDetails; + uint eventID; + + if (UInt32.TryParse(args[0], out eventID)) + { + Client.Directory.EventInfoRequest(eventID); + return "Sent query for Event " + eventID; + } + else + { + return "Usage: showevent [eventID] (use searchevents to get ID)"; + } + } + + void Directory_EventDetails(object sender, EventInfoReplyEventArgs e) + { + float x, y; + Helpers.GlobalPosToRegionHandle((float)e.MatchedEvent.GlobalPos.X, (float)e.MatchedEvent.GlobalPos.Y, out x, out y); + StringBuilder sb = new StringBuilder("secondlife://" + e.MatchedEvent.SimName + "/" + x + "/" + y + "/0" + System.Environment.NewLine); + sb.AppendLine(e.MatchedEvent.ToString()); + + //sb.AppendFormat(" Name: {0} ({1})" + System.Environment.NewLine, e.MatchedEvent.Name, e.MatchedEvent.ID); + //sb.AppendFormat(" Location: {0}/{1}/{2}" + System.Environment.NewLine, e.MatchedEvent.SimName, x, y); + //sb.AppendFormat(" Date: {0}" + System.Environment.NewLine, e.MatchedEvent.Date); + //sb.AppendFormat("Description: {0}" + System.Environment.NewLine, e.MatchedEvent.Desc); + Console.WriteLine(sb.ToString()); + Client.Directory.EventInfoReply -= Directory_EventDetails; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Estate/DownloadTerrainCommand.cs b/Programs/examples/TestClient/Commands/Estate/DownloadTerrainCommand.cs new file mode 100644 index 0000000..019e210 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Estate/DownloadTerrainCommand.cs @@ -0,0 +1,106 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + /// + /// Request the raw terrain file from the simulator, save it as a file. + /// + /// Can only be used by the Estate Owner + /// + public class DownloadTerrainCommand : Command + { + /// + /// Create a Synchronization event object + /// + private static AutoResetEvent xferTimeout = new AutoResetEvent(false); + + /// A string we use to report the result of the request with. + private static System.Text.StringBuilder result = new System.Text.StringBuilder(); + + private static string fileName; + + /// + /// Download a simulators raw terrain data and save it to a file + /// + /// + public DownloadTerrainCommand(TestClient testClient) + { + Name = "downloadterrain"; + Description = "Download the RAW terrain file for this estate. Usage: downloadterrain [timeout]"; + Category = CommandCategory.Simulator; + } + + /// + /// Execute the application + /// + /// arguments passed to this module + /// The ID of the avatar sending the request + /// + public override string Execute(string[] args, UUID fromAgentID) + { + int timeout = 120000; // default the timeout to 2 minutes + fileName = Client.Network.CurrentSim.Name + ".raw"; + + if (args.Length > 0 && int.TryParse(args[0], out timeout) != true) + return "Usage: downloadterrain [timeout]"; + + // Create a delegate which will be fired when the simulator receives our download request + // Starts the actual transfer request + EventHandler initiateDownloadDelegate = + delegate(object sender, InitiateDownloadEventArgs e) + { + Client.Assets.RequestAssetXfer(e.SimFileName, false, false, UUID.Zero, AssetType.Unknown, false); + }; + + // Subscribe to the event that will tell us the status of the download + Client.Assets.XferReceived += new EventHandler(Assets_XferReceived); + // subscribe to the event which tells us when the simulator has received our request + Client.Assets.InitiateDownload += initiateDownloadDelegate; + + // configure request to tell the simulator to send us the file + List parameters = new List(); + parameters.Add("download filename"); + parameters.Add(fileName); + // send the request + Client.Estate.EstateOwnerMessage("terrain", parameters); + + // wait for (timeout) seconds for the request to complete (defaults 2 minutes) + if (!xferTimeout.WaitOne(timeout, false)) + { + result.Append("Timeout while waiting for terrain data"); + } + + // unsubscribe from events + Client.Assets.InitiateDownload -= initiateDownloadDelegate; + Client.Assets.XferReceived -= new EventHandler(Assets_XferReceived); + + // return the result + return result.ToString(); + } + + /// + /// Handle the reply to the OnXferReceived event + /// + private void Assets_XferReceived(object sender, XferReceivedEventArgs e) + { + if (e.Xfer.Success) + { + // set the result message + result.AppendFormat("Terrain file {0} ({1} bytes) downloaded successfully, written to {2}", e.Xfer.Filename, e.Xfer.Size, fileName); + + // write the file to disk + FileStream stream = new FileStream(fileName, FileMode.Create); + BinaryWriter w = new BinaryWriter(stream); + w.Write(e.Xfer.AssetData); + w.Close(); + + // tell the application we've gotten the file + xferTimeout.Set(); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Estate/UploadRawTerrainCommand.cs b/Programs/examples/TestClient/Commands/Estate/UploadRawTerrainCommand.cs new file mode 100644 index 0000000..7a0be30 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Estate/UploadRawTerrainCommand.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Packets; +namespace OpenMetaverse.TestClient +{ + public class UploadRawTerrainCommand : Command + { + System.Threading.AutoResetEvent WaitForUploadComplete = new System.Threading.AutoResetEvent(false); + + public UploadRawTerrainCommand(TestClient testClient) + { + Name = "uploadterrain"; + Description = "Upload a raw terrain file to a simulator. usage: uploadterrain filename"; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + string fileName = String.Empty; + + if (args.Length != 1) + return "Usage: uploadterrain filename"; + + + fileName = args[0]; + + if (!System.IO.File.Exists(fileName)) + { + return String.Format("File {0} Does not exist", fileName); + } + + // Setup callbacks for upload request reply and progress indicator + // so we can detect when the upload is complete + Client.Assets.UploadProgress += new EventHandler(Assets_UploadProgress); + byte[] fileData = File.ReadAllBytes(fileName); + + Client.Estate.UploadTerrain(fileData, fileName); + + // Wait for upload to complete. Upload request is fired in callback from first request + if (!WaitForUploadComplete.WaitOne(120000, false)) + { + Cleanup(); + return "Timeout waiting for terrain file upload"; + } + else + { + Cleanup(); + return "Terrain raw file uploaded and applied"; + } + } + + /// + /// Unregister previously subscribed event handlers + /// + private void Cleanup() + { + Client.Assets.UploadProgress -= new EventHandler(Assets_UploadProgress); + } + + + void Assets_UploadProgress(object sender, AssetUploadEventArgs e) + { + if (e.Upload.Transferred == e.Upload.Size) + { + WaitForUploadComplete.Set(); + } + else + { + //Console.WriteLine("Progress: {0}/{1} {2}/{3} {4}", upload.XferID, upload.ID, upload.Transferred, upload.Size, upload.Success); + Console.Write("."); + } + } + + + } +} diff --git a/Programs/examples/TestClient/Commands/Friends/FriendsCommand.cs b/Programs/examples/TestClient/Commands/Friends/FriendsCommand.cs new file mode 100644 index 0000000..abc7131 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Friends/FriendsCommand.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +// the Namespace used for all TestClient commands +namespace OpenMetaverse.TestClient +{ + /// + /// Shows a list of friends + /// + public class FriendsCommand : Command + { + /// + /// Constructor for FriendsCommand class + /// + /// A reference to the TestClient object + public FriendsCommand(TestClient testClient) + { + // The name of the command + Name = "friends"; + // A short description of the command with usage instructions + Description = "List avatar friends. Usage: friends"; + Category = CommandCategory.Friends; + } + + /// + /// Get a list of current friends + /// + /// optional testClient command arguments + /// The + /// of the agent making the request + /// + public override string Execute(string[] args, UUID fromAgentID) + { + // initialize a StringBuilder object used to return the results + StringBuilder sb = new StringBuilder(); + + // Only iterate the Friends dictionary if we actually have friends! + if (Client.Friends.FriendList.Count > 0) + { + // iterate over the InternalDictionary using a delegate to populate + // our StringBuilder output string + sb.AppendFormat("has {0} friends:", Client.Friends.FriendList.Count).AppendLine(); + Client.Friends.FriendList.ForEach(delegate(FriendInfo friend) + { + // append the name of the friend to our output + sb.AppendFormat("{0}, {1}", friend.UUID, friend.Name).AppendLine(); + }); + } + else + { + // we have no friends :( + sb.AppendLine("No Friends"); + } + + // return the result + return sb.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Friends/MapFriendCommand.cs b/Programs/examples/TestClient/Commands/Friends/MapFriendCommand.cs new file mode 100644 index 0000000..5ea9bc7 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Friends/MapFriendCommand.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + public class MapFriendCommand : Command + { + ManualResetEvent WaitforFriend = new ManualResetEvent(false); + + public MapFriendCommand(TestClient testClient) + { + Name = "mapfriend"; + Description = "Show a friends location. Usage: mapfriend UUID"; + Category = CommandCategory.Friends; + } + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return Description; + + UUID targetID; + + if (!UUID.TryParse(args[0], out targetID)) + return Description; + + StringBuilder sb = new StringBuilder(); + + EventHandler del = delegate(object sender, FriendFoundReplyEventArgs e) + { + if (!e.RegionHandle.Equals(0)) + sb.AppendFormat("Found Friend {0} in {1} at {2}/{3}", e.AgentID, e.RegionHandle, e.Location.X, e.Location.Y); + else + sb.AppendFormat("Found Friend {0}, But they appear to be offline", e.AgentID); + + WaitforFriend.Set(); + }; + + + + Client.Friends.FriendFoundReply += del; + WaitforFriend.Reset(); + Client.Friends.MapFriend(targetID); + if (!WaitforFriend.WaitOne(10000, false)) + { + sb.AppendFormat("Timeout waiting for reply, Do you have mapping rights on {0}?", targetID); + } + Client.Friends.FriendFoundReply -= del; + return sb.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Groups/ActivateGroupCommand.cs b/Programs/examples/TestClient/Commands/Groups/ActivateGroupCommand.cs new file mode 100644 index 0000000..c58cc01 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Groups/ActivateGroupCommand.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + /// + /// Changes Avatars currently active group + /// + public class ActivateGroupCommand : Command + { + private ManualResetEvent GroupsEvent = new ManualResetEvent(false); + string activeGroup; + + public ActivateGroupCommand(TestClient testClient) + { + Name = "activategroup"; + Description = "Set a group as active. Usage: activategroup GroupName"; + Category = CommandCategory.Groups; + } + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return Description; + + activeGroup = string.Empty; + + string groupName = String.Empty; + for (int i = 0; i < args.Length; i++) + groupName += args[i] + " "; + groupName = groupName.Trim(); + + UUID groupUUID = Client.GroupName2UUID(groupName); + if (UUID.Zero != groupUUID) { + EventHandler pcallback = AgentDataUpdateHandler; + Client.Network.RegisterCallback(PacketType.AgentDataUpdate, pcallback); + + Console.WriteLine("setting " + groupName + " as active group"); + Client.Groups.ActivateGroup(groupUUID); + GroupsEvent.WaitOne(30000, false); + + Client.Network.UnregisterCallback(PacketType.AgentDataUpdate, pcallback); + GroupsEvent.Reset(); + + /* A.Biondi + * TODO: Handle titles choosing. + */ + + if (String.IsNullOrEmpty(activeGroup)) + return Client.ToString() + " failed to activate the group " + groupName; + + return "Active group is now " + activeGroup; + } + return Client.ToString() + " doesn't seem to be member of the group " + groupName; + } + + private void AgentDataUpdateHandler(object sender, PacketReceivedEventArgs e) + { + AgentDataUpdatePacket p = (AgentDataUpdatePacket)e.Packet; + if (p.AgentData.AgentID == Client.Self.AgentID) + { + activeGroup = Utils.BytesToString(p.AgentData.GroupName) + " ( " + Utils.BytesToString(p.AgentData.GroupTitle) + " )"; + GroupsEvent.Set(); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Groups/GroupMembersCommand.cs b/Programs/examples/TestClient/Commands/Groups/GroupMembersCommand.cs new file mode 100644 index 0000000..bf0ef91 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Groups/GroupMembersCommand.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + /// + /// dumps group members to console + /// + public class GroupMembersCommand : Command + { + private ManualResetEvent GroupsEvent = new ManualResetEvent(false); + private string GroupName; + private UUID GroupUUID; + private UUID GroupRequestID; + + public GroupMembersCommand(TestClient testClient) + { + Name = "groupmembers"; + Description = "Dump group members to console. Usage: groupmembers GroupName"; + Category = CommandCategory.Groups; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return Description; + + GroupName = String.Empty; + for (int i = 0; i < args.Length; i++) + GroupName += args[i] + " "; + GroupName = GroupName.Trim(); + + GroupUUID = Client.GroupName2UUID(GroupName); + if (UUID.Zero != GroupUUID) { + Client.Groups.GroupMembersReply += GroupMembersHandler; + GroupRequestID = Client.Groups.RequestGroupMembers(GroupUUID); + GroupsEvent.WaitOne(30000, false); + GroupsEvent.Reset(); + Client.Groups.GroupMembersReply -= GroupMembersHandler; + return Client.ToString() + " got group members"; + } + return Client.ToString() + " doesn't seem to be member of the group " + GroupName; + } + + private void GroupMembersHandler(object sender, GroupMembersReplyEventArgs e) + { + if (e.RequestID == GroupRequestID) { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(); + sb.AppendFormat("GroupMembers: RequestID {0}", e.RequestID).AppendLine(); + sb.AppendFormat("GroupMembers: GroupUUID {0}", GroupUUID).AppendLine(); + sb.AppendFormat("GroupMembers: GroupName {0}", GroupName).AppendLine(); + if (e.Members.Count > 0) + foreach (KeyValuePair member in e.Members) + sb.AppendFormat("GroupMembers: MemberUUID {0}", member.Key.ToString()).AppendLine(); + sb.AppendFormat("GroupMembers: MemberCount {0}", e.Members.Count).AppendLine(); + Console.WriteLine(sb.ToString()); + GroupsEvent.Set(); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Groups/GroupRolesCommand.cs b/Programs/examples/TestClient/Commands/Groups/GroupRolesCommand.cs new file mode 100644 index 0000000..e161854 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Groups/GroupRolesCommand.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + /// + /// dumps group roles to console + /// + public class GroupRolesCommand : Command + { + private ManualResetEvent GroupsEvent = new ManualResetEvent(false); + private string GroupName; + private UUID GroupUUID; + private UUID GroupRequestID; + + public GroupRolesCommand(TestClient testClient) + { + Name = "grouproles"; + Description = "Dump group roles to console. Usage: grouproles GroupName"; + Category = CommandCategory.Groups; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return Description; + + GroupName = String.Empty; + for (int i = 0; i < args.Length; i++) + GroupName += args[i] + " "; + GroupName = GroupName.Trim(); + + GroupUUID = Client.GroupName2UUID(GroupName); + if (UUID.Zero != GroupUUID) { + Client.Groups.GroupRoleDataReply += Groups_GroupRoles; + GroupRequestID = Client.Groups.RequestGroupRoles(GroupUUID); + GroupsEvent.WaitOne(30000, false); + GroupsEvent.Reset(); + Client.Groups.GroupRoleDataReply += Groups_GroupRoles; + return Client.ToString() + " got group roles"; + } + return Client.ToString() + " doesn't seem to have any roles in the group " + GroupName; + } + + void Groups_GroupRoles(object sender, GroupRolesDataReplyEventArgs e) + { + if (e.RequestID == GroupRequestID) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(); + sb.AppendFormat("GroupRole: RequestID {0}", e.RequestID).AppendLine(); + sb.AppendFormat("GroupRole: GroupUUID {0}", GroupUUID).AppendLine(); + sb.AppendFormat("GroupRole: GroupName {0}", GroupName).AppendLine(); + if (e.Roles.Count > 0) + foreach (KeyValuePair role in e.Roles) + sb.AppendFormat("GroupRole: Role {0} {1}|{2}", role.Value.ID, role.Value.Name, role.Value.Title).AppendLine(); + sb.AppendFormat("GroupRole: RoleCount {0}", e.Roles.Count).AppendLine(); + Console.WriteLine(sb.ToString()); + GroupsEvent.Set(); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Groups/GroupsCommand.cs b/Programs/examples/TestClient/Commands/Groups/GroupsCommand.cs new file mode 100644 index 0000000..78ff575 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Groups/GroupsCommand.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + public class GroupsCommand : Command + { + public GroupsCommand(TestClient testClient) + { + Name = "groups"; + Description = "List avatar groups. Usage: groups"; + Category = CommandCategory.Groups; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Client.ReloadGroupsCache(); + return getGroupsString(); + } + + string getGroupsString() + { + if (null == Client.GroupsCache) + return "Groups cache failed."; + if (0 == Client.GroupsCache.Count) + return "No groups"; + StringBuilder sb = new StringBuilder(); + sb.AppendLine("got "+Client.GroupsCache.Count +" groups:"); + foreach (Group group in Client.GroupsCache.Values) + { + sb.AppendLine(group.ID + ", " + group.Name); + + } + + return sb.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Groups/InviteGroupCommand.cs b/Programs/examples/TestClient/Commands/Groups/InviteGroupCommand.cs new file mode 100644 index 0000000..ff1397c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Groups/InviteGroupCommand.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + public class InviteGroupCommand : Command + { + public InviteGroupCommand(TestClient testClient) + { + Name = "invitegroup"; + Description = "invite an avatar into a group. Usage: invitegroup AvatarUUID GroupUUID RoleUUID*"; + Category = CommandCategory.Groups; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 2) + return Description; + + UUID avatar = UUID.Zero; + UUID group = UUID.Zero; + UUID role = UUID.Zero; + List roles = new List(); + + if (!UUID.TryParse(args[0], out avatar)) + return "parse error avatar UUID"; + if (!UUID.TryParse(args[1], out group)) + return "parse error group UUID"; + if (2 == args.Length) + roles.Add(UUID.Zero); + else + for (int i = 2; i < args.Length; i++) + if (UUID.TryParse(args[i], out role)) + roles.Add(role); + + Client.Groups.Invite(group, roles, avatar); + + return "invited "+avatar+" to "+group; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Groups/JoinGroupCommand.cs b/Programs/examples/TestClient/Commands/Groups/JoinGroupCommand.cs new file mode 100644 index 0000000..b83e2fd --- /dev/null +++ b/Programs/examples/TestClient/Commands/Groups/JoinGroupCommand.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + public class JoinGroupCommand : Command + { + ManualResetEvent GetGroupsSearchEvent = new ManualResetEvent(false); + private UUID queryID = UUID.Zero; + private UUID resolvedGroupID; + private string groupName; + private string resolvedGroupName; + private bool joinedGroup; + + public JoinGroupCommand(TestClient testClient) + { + Name = "joingroup"; + Description = "join a group. Usage: joingroup GroupName | joingroup UUID GroupId"; + Category = CommandCategory.Groups; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return Description; + + groupName = String.Empty; + resolvedGroupID = UUID.Zero; + resolvedGroupName = String.Empty; + + if (args[0].ToLower() == "uuid") + { + if (args.Length < 2) + return Description; + + if (!UUID.TryParse((resolvedGroupName = groupName = args[1]), out resolvedGroupID)) + return resolvedGroupName + " doesn't seem a valid UUID"; + } + else + { + for (int i = 0; i < args.Length; i++) + groupName += args[i] + " "; + groupName = groupName.Trim(); + + Client.Directory.DirGroupsReply += Directory_DirGroups; + + queryID = Client.Directory.StartGroupSearch(groupName, 0); + + GetGroupsSearchEvent.WaitOne(60000, false); + + Client.Directory.DirGroupsReply -= Directory_DirGroups; + + GetGroupsSearchEvent.Reset(); + } + + if (resolvedGroupID == UUID.Zero) + { + if (string.IsNullOrEmpty(resolvedGroupName)) + return "Unable to obtain UUID for group " + groupName; + else + return resolvedGroupName; + } + + Client.Groups.GroupJoinedReply += Groups_OnGroupJoined; + Client.Groups.RequestJoinGroup(resolvedGroupID); + + /* A.Biondi + * TODO: implement the pay to join procedure. + */ + + GetGroupsSearchEvent.WaitOne(60000, false); + + Client.Groups.GroupJoinedReply -= Groups_GroupJoined; + GetGroupsSearchEvent.Reset(); + Client.ReloadGroupsCache(); + + if (joinedGroup) + return "Joined the group " + resolvedGroupName; + return "Unable to join the group " + resolvedGroupName; + } + + void Groups_GroupJoined(object sender, GroupOperationEventArgs e) + { + throw new NotImplementedException(); + } + + void Directory_DirGroups(object sender, DirGroupsReplyEventArgs e) + { + if (queryID == e.QueryID) + { + queryID = UUID.Zero; + if (e.MatchedGroups.Count < 1) + { + Console.WriteLine("ERROR: Got an empty reply"); + } + else + { + if (e.MatchedGroups.Count > 1) + { + /* A.Biondi + * The Group search doesn't work as someone could expect... + * It'll give back to you a long list of groups even if the + * searchText (groupName) matches esactly one of the groups + * names present on the server, so we need to check each result. + * UUIDs of the matching groups are written on the console. + */ + Console.WriteLine("Matching groups are:\n"); + foreach (DirectoryManager.GroupSearchData groupRetrieved in e.MatchedGroups) + { + Console.WriteLine(groupRetrieved.GroupName + "\t\t\t(" + + Name + " UUID " + groupRetrieved.GroupID.ToString() + ")"); + + if (groupRetrieved.GroupName.ToLower() == groupName.ToLower()) + { + resolvedGroupID = groupRetrieved.GroupID; + resolvedGroupName = groupRetrieved.GroupName; + break; + } + } + if (string.IsNullOrEmpty(resolvedGroupName)) + resolvedGroupName = "Ambiguous name. Found " + e.MatchedGroups.Count.ToString() + " groups (UUIDs on console)"; + } + + } + GetGroupsSearchEvent.Set(); + } + } + + void Groups_OnGroupJoined(object sender, GroupOperationEventArgs e) + { + Console.WriteLine(Client.ToString() + (e.Success ? " joined " : " failed to join ") + e.GroupID.ToString()); + + /* A.Biondi + * This code is not necessary because it is yet present in the + * GroupCommand.cs as well. So the new group will be activated by + * the mentioned command. If the GroupCommand.cs would change, + * just uncomment the following two lines. + + if (success) + { + Console.WriteLine(Client.ToString() + " setting " + groupID.ToString() + " as the active group"); + Client.Groups.ActivateGroup(groupID); + } + + */ + + joinedGroup = e.Success; + GetGroupsSearchEvent.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Groups/LeaveGroupCommand.cs b/Programs/examples/TestClient/Commands/Groups/LeaveGroupCommand.cs new file mode 100644 index 0000000..f8798a6 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Groups/LeaveGroupCommand.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + public class LeaveGroupCommand : Command + { + ManualResetEvent GroupsEvent = new ManualResetEvent(false); + private bool leftGroup; + + public LeaveGroupCommand(TestClient testClient) + { + Name = "leavegroup"; + Description = "Leave a group. Usage: leavegroup GroupName"; + Category = CommandCategory.Groups; + } + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return Description; + + string groupName = String.Empty; + for (int i = 0; i < args.Length; i++) + groupName += args[i] + " "; + groupName = groupName.Trim(); + + UUID groupUUID = Client.GroupName2UUID(groupName); + if (UUID.Zero != groupUUID) { + Client.Groups.GroupLeaveReply += Groups_GroupLeft; + Client.Groups.LeaveGroup(groupUUID); + + GroupsEvent.WaitOne(30000, false); + Client.Groups.GroupLeaveReply -= Groups_GroupLeft; + + GroupsEvent.Reset(); + Client.ReloadGroupsCache(); + + if (leftGroup) + return Client.ToString() + " has left the group " + groupName; + return "failed to leave the group " + groupName; + } + return Client.ToString() + " doesn't seem to be member of the group " + groupName; + } + + void Groups_GroupLeft(object sender, GroupOperationEventArgs e) + { + Console.WriteLine(Client.ToString() + (e.Success ? " has left group " : " failed to left group ") + e.GroupID.ToString()); + + leftGroup = e.Success; + GroupsEvent.Set(); + } + + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs b/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs new file mode 100644 index 0000000..4e79351 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.ComponentModel; +using System.Xml; +using System.Xml.Serialization; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.TestClient; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class QueuedDownloadInfo + { + public UUID AssetID; + public UUID ItemID; + public UUID TaskID; + public UUID OwnerID; + public AssetType Type; + public string FileName; + public DateTime WhenRequested; + public bool IsRequested; + + public QueuedDownloadInfo(string file, UUID asset, UUID item, UUID task, UUID owner, AssetType type) + { + FileName = file; + AssetID = asset; + ItemID = item; + TaskID = task; + OwnerID = owner; + Type = type; + WhenRequested = DateTime.Now; + IsRequested = false; + } + } + + public class BackupCommand : Command + { + /// Maximum number of transfer requests to send to the server + private const int MAX_TRANSFERS = 10; + + // all items here, fed by the inventory walking thread + private Queue PendingDownloads = new Queue(); + + // items sent to the server here + private List CurrentDownloads = new List(MAX_TRANSFERS); + + // background workers + private BackgroundWorker BackupWorker; + private BackgroundWorker QueueWorker; + + // some stats + private int TextItemsFound; + private int TextItemsTransferred; + private int TextItemErrors; + + #region Properties + + /// + /// true if either of the background threads is running + /// + private bool BackgroundBackupRunning + { + get { return InventoryWalkerRunning || QueueRunnerRunning; } + } + + /// + /// true if the thread walking inventory is running + /// + private bool InventoryWalkerRunning + { + get { return BackupWorker != null; } + } + + /// + /// true if the thread feeding the queue to the server is running + /// + private bool QueueRunnerRunning + { + get { return QueueWorker != null; } + } + + /// + /// returns a string summarizing activity + /// + /// + private string BackgroundBackupStatus + { + get + { + StringBuilder sbResult = new StringBuilder(); + sbResult.AppendFormat("{0} is {1} running.", Name, BoolToNot(BackgroundBackupRunning)); + if (TextItemErrors != 0 || TextItemsFound != 0 || TextItemsTransferred != 0) + { + sbResult.AppendFormat("\r\n{0} : Inventory walker ( {1} running ) has found {2} items.", + Name, BoolToNot(InventoryWalkerRunning), TextItemsFound); + sbResult.AppendFormat("\r\n{0} : Server Transfers ( {1} running ) has transferred {2} items with {3} errors.", + Name, BoolToNot(QueueRunnerRunning), TextItemsTransferred, TextItemErrors); + sbResult.AppendFormat("\r\n{0} : {1} items in Queue, {2} items requested from server.", + Name, PendingDownloads.Count, CurrentDownloads.Count); + } + return sbResult.ToString(); + } + } + + #endregion Properties + + public BackupCommand(TestClient testClient) + { + Name = "backuptext"; + Description = "Backup inventory to a folder on your hard drive. Usage: " + Name + " [to ] | [abort] | [status]"; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + + if (args.Length == 1 && args[0] == "status") + { + return BackgroundBackupStatus; + } + else if (args.Length == 1 && args[0] == "abort") + { + if (!BackgroundBackupRunning) + return BackgroundBackupStatus; + + BackupWorker.CancelAsync(); + QueueWorker.CancelAsync(); + + Thread.Sleep(500); + + // check status + return BackgroundBackupStatus; + } + else if (args.Length != 2) + { + return "Usage: " + Name + " [to ] | [abort] | [status]"; + } + else if (BackgroundBackupRunning) + { + return BackgroundBackupStatus; + } + + QueueWorker = new BackgroundWorker(); + QueueWorker.WorkerSupportsCancellation = true; + QueueWorker.DoWork += new DoWorkEventHandler(bwQueueRunner_DoWork); + QueueWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwQueueRunner_RunWorkerCompleted); + + QueueWorker.RunWorkerAsync(); + + BackupWorker = new BackgroundWorker(); + BackupWorker.WorkerSupportsCancellation = true; + BackupWorker.DoWork += new DoWorkEventHandler(bwBackup_DoWork); + BackupWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwBackup_RunWorkerCompleted); + + BackupWorker.RunWorkerAsync(args); + return "Started background operations."; + } + + void bwQueueRunner_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + QueueWorker = null; + Console.WriteLine(BackgroundBackupStatus); + } + + void bwQueueRunner_DoWork(object sender, DoWorkEventArgs e) + { + TextItemErrors = TextItemsTransferred = 0; + + while (QueueWorker.CancellationPending == false) + { + // have any timed out? + if (CurrentDownloads.Count > 0) + { + foreach (QueuedDownloadInfo qdi in CurrentDownloads) + { + if ((qdi.WhenRequested + TimeSpan.FromSeconds(60)) < DateTime.Now) + { + Logger.DebugLog(Name + ": timeout on asset " + qdi.AssetID.ToString(), Client); + // submit request again + Client.Assets.RequestInventoryAsset( + qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true, Assets_OnAssetReceived); + qdi.WhenRequested = DateTime.Now; + qdi.IsRequested = true; + } + } + } + + if (PendingDownloads.Count != 0) + { + // room in the server queue? + if (CurrentDownloads.Count < MAX_TRANSFERS) + { + // yes + QueuedDownloadInfo qdi = PendingDownloads.Dequeue(); + qdi.WhenRequested = DateTime.Now; + qdi.IsRequested = true; + Client.Assets.RequestInventoryAsset( + qdi.AssetID, qdi.ItemID, qdi.TaskID, qdi.OwnerID, qdi.Type, true, Assets_OnAssetReceived); + + lock (CurrentDownloads) CurrentDownloads.Add(qdi); + } + } + + if (CurrentDownloads.Count == 0 && PendingDownloads.Count == 0 && BackupWorker == null) + { + Logger.DebugLog(Name + ": both transfer queues empty AND inventory walking thread is done", Client); + return; + } + + Thread.Sleep(100); + } + } + + void bwBackup_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + Console.WriteLine(Name + ": Inventory walking thread done."); + BackupWorker = null; + } + + private void bwBackup_DoWork(object sender, DoWorkEventArgs e) + { + string[] args; + + TextItemsFound = 0; + + args = (string[])e.Argument; + + lock (CurrentDownloads) CurrentDownloads.Clear(); + + // FIXME: + //Client.Inventory.RequestFolderContents(Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID, + // true, true, false, InventorySortOrder.ByName); + + DirectoryInfo di = new DirectoryInfo(args[1]); + + // recurse on the root folder into the entire inventory + BackupFolder(Client.Inventory.Store.RootNode, di.FullName); + } + + /// + /// BackupFolder - recurse through the inventory nodes sending scripts and notecards to the transfer queue + /// + /// The current leaf in the inventory tree + /// path so far, in the form @"c:\here" -- this needs to be "clean" for the current filesystem + private void BackupFolder(InventoryNode folder, string sPathSoFar) + { + + // FIXME: + //Client.Inventory.RequestFolderContents(folder.Data.UUID, Client.Self.AgentID, true, true, false, + // InventorySortOrder.ByName); + + // first scan this folder for text + foreach (InventoryNode iNode in folder.Nodes.Values) + { + if (BackupWorker.CancellationPending) + return; + if (iNode.Data is OpenMetaverse.InventoryItem) + { + InventoryItem ii = iNode.Data as InventoryItem; + if (ii.AssetType == AssetType.LSLText || ii.AssetType == AssetType.Notecard) + { + // check permissions on scripts + if (ii.AssetType == AssetType.LSLText) + { + if ((ii.Permissions.OwnerMask & PermissionMask.Modify) == PermissionMask.None) + { + // skip this one + continue; + } + } + + string sExtension = (ii.AssetType == AssetType.LSLText) ? ".lsl" : ".txt"; + // make the output file + string sPath = sPathSoFar + @"\" + MakeValid(ii.Name.Trim()) + sExtension; + + // create the new qdi + QueuedDownloadInfo qdi = new QueuedDownloadInfo(sPath, ii.AssetUUID, iNode.Data.UUID, UUID.Zero, + Client.Self.AgentID, ii.AssetType); + + // add it to the queue + lock (PendingDownloads) + { + TextItemsFound++; + PendingDownloads.Enqueue(qdi); + } + } + } + } + + // now run any subfolders + foreach (InventoryNode i in folder.Nodes.Values) + { + if (BackupWorker.CancellationPending) + return; + else if (i.Data is OpenMetaverse.InventoryFolder) + BackupFolder(i, sPathSoFar + @"\" + MakeValid(i.Data.Name.Trim())); + } + } + + private string MakeValid(string path) + { + // FIXME: We need to strip illegal characters out + return path.Trim().Replace('"', '\''); + } + + private void Assets_OnAssetReceived(AssetDownload asset, Asset blah) + { + lock (CurrentDownloads) + { + // see if we have this in our transfer list + QueuedDownloadInfo r = CurrentDownloads.Find(delegate(QueuedDownloadInfo q) + { + return q.AssetID == asset.AssetID; + }); + + if (r != null && r.AssetID == asset.AssetID) + { + if (asset.Success) + { + // create the directory to put this in + Directory.CreateDirectory(Path.GetDirectoryName(r.FileName)); + + // write out the file + File.WriteAllBytes(r.FileName, asset.AssetData); + Logger.DebugLog(Name + " Wrote: " + r.FileName, Client); + TextItemsTransferred++; + } + else + { + TextItemErrors++; + Console.WriteLine("{0}: Download of asset {1} ({2}) failed with status {3}", Name, r.FileName, + r.AssetID.ToString(), asset.Status.ToString()); + } + + // remove the entry + CurrentDownloads.Remove(r); + } + } + } + + /// + /// returns blank or "not" if false + /// + /// + /// + private static string BoolToNot(bool b) + { + return b ? String.Empty : "not"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/BalanceCommand.cs b/Programs/examples/TestClient/Commands/Inventory/BalanceCommand.cs new file mode 100644 index 0000000..969ffe4 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/BalanceCommand.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class BalanceCommand: Command + { + public BalanceCommand(TestClient testClient) + { + Name = "balance"; + Description = "Shows the amount of L$."; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + System.Threading.AutoResetEvent waitBalance = new System.Threading.AutoResetEvent(false); + + EventHandler del = delegate(object sender, BalanceEventArgs e) { waitBalance.Set(); }; + Client.Self.MoneyBalance += del; + Client.Self.RequestBalance(); + String result = "Timeout waiting for balance reply"; + if (waitBalance.WaitOne(10000, false)) + { + result = Client.ToString() + " has L$: " + Client.Self.Balance; + } + Client.Self.MoneyBalance -= del; + return result; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/ChangeDirectoryCommand.cs b/Programs/examples/TestClient/Commands/Inventory/ChangeDirectoryCommand.cs new file mode 100644 index 0000000..3029910 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/ChangeDirectoryCommand.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient.Commands.Inventory.Shell +{ + public class ChangeDirectoryCommand : Command + { + private OpenMetaverse.Inventory Inventory; + + public ChangeDirectoryCommand(TestClient client) + { + Name = "cd"; + Description = "Changes the current working inventory folder."; + Category = CommandCategory.Inventory; + } + public override string Execute(string[] args, UUID fromAgentID) + { + Inventory = Client.Inventory.Store; + + if (args.Length > 1) + return "Usage: cd [path-to-folder]"; + string pathStr = ""; + string[] path = null; + if (args.Length == 0) + { + path = new string[] { "" }; + // cd without any arguments doesn't do anything. + } + else if (args.Length == 1) + { + pathStr = args[0]; + path = pathStr.Split(new char[] { '/' }); + // Use '/' as a path seperator. + } + InventoryFolder currentFolder = Client.CurrentDirectory; + if (pathStr.StartsWith("/")) + currentFolder = Inventory.RootFolder; + + if (currentFolder == null) // We need this to be set to something. + return "Error: Client not logged in."; + + // Traverse the path, looking for the + for (int i = 0; i < path.Length; ++i) + { + string nextName = path[i]; + if (string.IsNullOrEmpty(nextName) || nextName == ".") + continue; // Ignore '.' and blanks, stay in the current directory. + if (nextName == ".." && currentFolder != Inventory.RootFolder) + { + // If we encounter .., move to the parent folder. + currentFolder = Inventory[currentFolder.ParentUUID] as InventoryFolder; + } + else + { + List currentContents = Inventory.GetContents(currentFolder); + // Try and find an InventoryBase with the corresponding name. + bool found = false; + foreach (InventoryBase item in currentContents) + { + // Allow lookup by UUID as well as name: + if (item.Name == nextName || item.UUID.ToString() == nextName) + { + found = true; + if (item is InventoryFolder) + { + currentFolder = item as InventoryFolder; + } + else + { + return item.Name + " is not a folder."; + } + } + } + if (!found) + return nextName + " not found in " + currentFolder.Name; + } + } + Client.CurrentDirectory = currentFolder; + return "Current folder: " + currentFolder.Name; + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs b/Programs/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs new file mode 100644 index 0000000..77d5a58 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class CreateNotecardCommand : Command + { + const int NOTECARD_CREATE_TIMEOUT = 1000 * 10; + const int NOTECARD_FETCH_TIMEOUT = 1000 * 10; + const int INVENTORY_FETCH_TIMEOUT = 1000 * 10; + + public CreateNotecardCommand(TestClient testClient) + { + Name = "createnotecard"; + Description = "Creates a notecard from a local text file and optionally embed an inventory item. Usage: createnotecard filename.txt [itemid]"; + Category = CommandCategory.Inventory; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + UUID embedItemID = UUID.Zero, notecardItemID = UUID.Zero, notecardAssetID = UUID.Zero; + string filename, fileData; + bool success = false, finalUploadSuccess = false; + string message = String.Empty; + AutoResetEvent notecardEvent = new AutoResetEvent(false); + + if (args.Length == 1) + { + filename = args[0]; + } + else if (args.Length == 2) + { + filename = args[0]; + UUID.TryParse(args[1], out embedItemID); + } + else + { + return "Usage: createnotecard filename.txt"; + } + + if (!File.Exists(filename)) + return "File \"" + filename + "\" does not exist"; + + try { fileData = File.ReadAllText(filename); } + catch (Exception ex) { return "Failed to open " + filename + ": " + ex.Message; } + + #region Notecard asset data + + AssetNotecard notecard = new AssetNotecard(); + notecard.BodyText = fileData; + + // Item embedding + if (embedItemID != UUID.Zero) + { + // Try to fetch the inventory item + InventoryItem item = FetchItem(embedItemID); + if (item != null) + { + notecard.EmbeddedItems = new List { item }; + notecard.BodyText += (char)0xdbc0 + (char)0xdc00; + } + else + { + return "Failed to fetch inventory item " + embedItemID; + } + } + + notecard.Encode(); + + #endregion Notecard asset data + + Client.Inventory.RequestCreateItem(Client.Inventory.FindFolderForType(AssetType.Notecard), + filename, filename + " created by OpenMetaverse TestClient " + DateTime.Now, AssetType.Notecard, + UUID.Random(), InventoryType.Notecard, PermissionMask.All, + delegate(bool createSuccess, InventoryItem item) + { + if (createSuccess) + { + #region Upload an empty notecard asset first + + AutoResetEvent emptyNoteEvent = new AutoResetEvent(false); + AssetNotecard empty = new AssetNotecard(); + empty.BodyText = "\n"; + empty.Encode(); + + Client.Inventory.RequestUploadNotecardAsset(empty.AssetData, item.UUID, + delegate(bool uploadSuccess, string status, UUID itemID, UUID assetID) + { + notecardItemID = itemID; + notecardAssetID = assetID; + success = uploadSuccess; + message = status ?? "Unknown error uploading notecard asset"; + emptyNoteEvent.Set(); + }); + + emptyNoteEvent.WaitOne(NOTECARD_CREATE_TIMEOUT, false); + + #endregion Upload an empty notecard asset first + + if (success) + { + // Upload the actual notecard asset + Client.Inventory.RequestUploadNotecardAsset(notecard.AssetData, item.UUID, + delegate(bool uploadSuccess, string status, UUID itemID, UUID assetID) + { + notecardItemID = itemID; + notecardAssetID = assetID; + finalUploadSuccess = uploadSuccess; + message = status ?? "Unknown error uploading notecard asset"; + notecardEvent.Set(); + }); + } + else + { + notecardEvent.Set(); + } + } + else + { + message = "Notecard item creation failed"; + notecardEvent.Set(); + } + } + ); + + notecardEvent.WaitOne(NOTECARD_CREATE_TIMEOUT, false); + + if (finalUploadSuccess) + { + Logger.Log("Notecard successfully created, ItemID " + notecardItemID + " AssetID " + notecardAssetID, Helpers.LogLevel.Info); + return DownloadNotecard(notecardItemID, notecardAssetID); + } + else + return "Notecard creation failed: " + message; + } + + private InventoryItem FetchItem(UUID itemID) + { + InventoryItem fetchItem = null; + AutoResetEvent fetchItemEvent = new AutoResetEvent(false); + + EventHandler itemReceivedCallback = + delegate(object sender, ItemReceivedEventArgs e) + { + if (e.Item.UUID == itemID) + { + fetchItem = e.Item; + fetchItemEvent.Set(); + } + }; + + Client.Inventory.ItemReceived += itemReceivedCallback; + + Client.Inventory.RequestFetchInventory(itemID, Client.Self.AgentID); + + fetchItemEvent.WaitOne(INVENTORY_FETCH_TIMEOUT, false); + + Client.Inventory.ItemReceived -= itemReceivedCallback; + + return fetchItem; + } + + private string DownloadNotecard(UUID itemID, UUID assetID) + { + AutoResetEvent assetDownloadEvent = new AutoResetEvent(false); + byte[] notecardData = null; + string error = "Timeout"; + + Client.Assets.RequestInventoryAsset(assetID, itemID, UUID.Zero, Client.Self.AgentID, AssetType.Notecard, true, + delegate(AssetDownload transfer, Asset asset) + { + if (transfer.Success) + notecardData = transfer.AssetData; + else + error = transfer.Status.ToString(); + assetDownloadEvent.Set(); + } + ); + + assetDownloadEvent.WaitOne(NOTECARD_FETCH_TIMEOUT, false); + + if (notecardData != null) + return Encoding.UTF8.GetString(notecardData); + else + return "Error downloading notecard asset: " + error; + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Inventory/DeleteFolderCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DeleteFolderCommand.cs new file mode 100644 index 0000000..ad3c82f --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/DeleteFolderCommand.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Xml; +using System.Xml.Serialization; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + /// + /// Inventory Example, Moves a folder to the Trash folder + /// + public class DeleteFolderCommand : Command + { + public DeleteFolderCommand(TestClient testClient) + { + Name = "deleteFolder"; + Description = "Moves a folder to the Trash Folder"; + Category = CommandCategory.Inventory; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // parse the command line + string target = String.Empty; + for (int ct = 0; ct < args.Length; ct++) + target = target + args[ct] + " "; + target = target.TrimEnd(); + + // initialize results list + List found = new List(); + + // find the folder + found = Client.Inventory.LocalFind(Client.Inventory.Store.RootFolder.UUID, target.Split('/'), 0, true); + + if (found.Count.Equals(1)) + { + // move the folder to the trash folder + Client.Inventory.MoveFolder(found[0].UUID, Client.Inventory.FindFolderForType(AssetType.TrashFolder)); + + return String.Format("Moved folder {0} to Trash", found[0].Name); + } + + return String.Empty; + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs new file mode 100644 index 0000000..52ea5a8 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class DownloadCommand : Command + { + UUID AssetID; + AssetType assetType; + AutoResetEvent DownloadHandle = new AutoResetEvent(false); + bool Success; + string usage = "Usage: download [uuid] [assetType]"; + + public DownloadCommand(TestClient testClient) + { + Name = "download"; + Description = "Downloads the specified asset. Usage: download [uuid] [assetType]"; + Category = CommandCategory.Inventory; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 2) + return usage; + + Success = false; + AssetID = UUID.Zero; + assetType = AssetType.Unknown; + DownloadHandle.Reset(); + + if (!UUID.TryParse(args[0], out AssetID)) + return usage; + + try { + assetType = (AssetType)Enum.Parse(typeof(AssetType), args[1], true); + } catch (ArgumentException) { + return usage; + } + if (!Enum.IsDefined(typeof(AssetType), assetType)) + return usage; + + // Start the asset download + Client.Assets.RequestAsset(AssetID, assetType, true, Assets_OnAssetReceived); + + if (DownloadHandle.WaitOne(120 * 1000, false)) + { + if (Success) + return String.Format("Saved {0}.{1}", AssetID, assetType.ToString().ToLower()); + else + return String.Format("Failed to download asset {0}, perhaps {1} is the incorrect asset type?", + AssetID, assetType); + } + else + { + return "Timed out waiting for texture download"; + } + } + + private void Assets_OnAssetReceived(AssetDownload transfer, Asset asset) + { + if (transfer.AssetID == AssetID) + { + if (transfer.Success) + { + try + { + File.WriteAllBytes(String.Format("{0}.{1}", AssetID, + assetType.ToString().ToLower()), asset.AssetData); + Success = true; + } + catch (Exception ex) + { + Logger.Log(ex.Message, Helpers.LogLevel.Error, ex); + } + } + + DownloadHandle.Set(); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs new file mode 100644 index 0000000..3853b77 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs @@ -0,0 +1,118 @@ +using System; +using System.Text; +using System.IO; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Imaging; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class DumpOutfitCommand : Command + { + List OutfitAssets = new List(); + + public DumpOutfitCommand(TestClient testClient) + { + Name = "dumpoutfit"; + Description = "Dumps all of the textures from an avatars outfit to the hard drive. Usage: dumpoutfit [avatar-uuid]"; + Category = CommandCategory.Inventory; + + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: dumpoutfit [avatar-uuid]"; + + UUID target; + + if (!UUID.TryParse(args[0], out target)) + return "Usage: dumpoutfit [avatar-uuid]"; + + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Avatar targetAv = Client.Network.Simulators[i].ObjectsAvatars.Find( + delegate(Avatar avatar) + { + return avatar.ID == target; + } + ); + + if (targetAv != null) + { + StringBuilder output = new StringBuilder("Downloading "); + + lock (OutfitAssets) OutfitAssets.Clear(); + + for (int j = 0; j < targetAv.Textures.FaceTextures.Length; j++) + { + Primitive.TextureEntryFace face = targetAv.Textures.FaceTextures[j]; + + if (face != null) + { + ImageType type = ImageType.Normal; + + switch ((AvatarTextureIndex)j) + { + case AvatarTextureIndex.HeadBaked: + case AvatarTextureIndex.EyesBaked: + case AvatarTextureIndex.UpperBaked: + case AvatarTextureIndex.LowerBaked: + case AvatarTextureIndex.SkirtBaked: + type = ImageType.Baked; + break; + } + + OutfitAssets.Add(face.TextureID); + Client.Assets.RequestImage(face.TextureID, type, Assets_OnImageReceived); + output.Append(((AvatarTextureIndex)j).ToString()); + output.Append(" "); + } + } + + return output.ToString(); + } + } + } + + return "Couldn't find avatar " + target.ToString(); + } + + private void Assets_OnImageReceived(TextureRequestState state, AssetTexture assetTexture) + { + lock (OutfitAssets) + { + if (OutfitAssets.Contains(assetTexture.AssetID)) + { + if (state == TextureRequestState.Finished) + { + try + { + File.WriteAllBytes(assetTexture.AssetID + ".jp2", assetTexture.AssetData); + Console.WriteLine("Wrote JPEG2000 image " + assetTexture.AssetID + ".jp2"); + + ManagedImage imgData; + OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData); + byte[] tgaFile = imgData.ExportTGA(); + File.WriteAllBytes(assetTexture.AssetID + ".tga", tgaFile); + Console.WriteLine("Wrote TGA image " + assetTexture.AssetID + ".tga"); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + } + else + { + Console.WriteLine("Failed to download image " + assetTexture.AssetID); + } + + OutfitAssets.Remove(assetTexture.AssetID); + } + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/EmptyLostAndFound.cs b/Programs/examples/TestClient/Commands/Inventory/EmptyLostAndFound.cs new file mode 100644 index 0000000..ce251a1 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/EmptyLostAndFound.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class EmptyLostAndCommand : Command + { + /// + /// TestClient command to download and display a notecard asset + /// + /// + public EmptyLostAndCommand(TestClient testClient) + { + Name = "emptylostandfound"; + Description = "Empty inventory Lost And Found folder"; + Category = CommandCategory.Inventory; + } + + /// + /// Exectute the command + /// + /// + /// + /// + public override string Execute(string[] args, UUID fromAgentID) + { + Client.Inventory.EmptyLostAndFound(); + return "Lost And Found Emptied"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/EmptyTrashCommand.cs b/Programs/examples/TestClient/Commands/Inventory/EmptyTrashCommand.cs new file mode 100644 index 0000000..264bce2 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/EmptyTrashCommand.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class EmptyTrashCommand : Command + { + /// + /// TestClient command to download and display a notecard asset + /// + /// + public EmptyTrashCommand(TestClient testClient) + { + Name = "emptytrash"; + Description = "Empty inventory Trash folder"; + Category = CommandCategory.Inventory; + } + + /// + /// Exectute the command + /// + /// + /// + /// + public override string Execute(string[] args, UUID fromAgentID) + { + Client.Inventory.EmptyTrash(); + return "Trash Emptied"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/GiveAllCommand.cs b/Programs/examples/TestClient/Commands/Inventory/GiveAllCommand.cs new file mode 100644 index 0000000..f930eee --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/GiveAllCommand.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class GiveAllCommand: Command + { + public GiveAllCommand(TestClient testClient) + { + Name = "giveAll"; + Description = "Gives you all it's money."; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (fromAgentID == UUID.Zero) + return "Unable to send money to console. This command only works when IMed."; + + int amount = Client.Self.Balance; + Client.Self.GiveAvatarMoney(fromAgentID, Client.Self.Balance, "TestClient.GiveAll"); + return "Gave $" + amount + " to " + fromAgentID; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/GiveItemCommand.cs b/Programs/examples/TestClient/Commands/Inventory/GiveItemCommand.cs new file mode 100644 index 0000000..790517c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/GiveItemCommand.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands.Inventory.Shell +{ + class GiveItemCommand : Command + { + private InventoryManager Manager; + private OpenMetaverse.Inventory Inventory; + public GiveItemCommand(TestClient client) + { + Name = "give"; + Description = "Gives items from the current working directory to an avatar."; + Category = CommandCategory.Inventory; + } + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 2) + { + return "Usage: give itemname"; + } + UUID dest; + if (!UUID.TryParse(args[0], out dest)) + { + return "First argument expected agent UUID."; + } + Manager = Client.Inventory; + Inventory = Manager.Store; + string ret = ""; + string nl = "\n"; + + string target = String.Empty; + for (int ct = 0; ct < args.Length; ct++) + target = target + args[ct] + " "; + target = target.TrimEnd(); + + string inventoryName = target; + // WARNING: Uses local copy of inventory contents, need to download them first. + List contents = Inventory.GetContents(Client.CurrentDirectory); + bool found = false; + foreach (InventoryBase b in contents) + { + if (inventoryName == b.Name || inventoryName == b.UUID.ToString()) + { + found = true; + if (b is InventoryItem) + { + InventoryItem item = b as InventoryItem; + Manager.GiveItem(item.UUID, item.Name, item.AssetType, dest, true); + ret += "Gave " + item.Name + " (" + item.AssetType + ")" + nl; + } + else + { + ret += "Unable to give folder " + b.Name + nl; + } + } + } + if (!found) + ret += "No inventory item named " + inventoryName + " found." + nl; + + return ret; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/InventoryCommand.cs b/Programs/examples/TestClient/Commands/Inventory/InventoryCommand.cs new file mode 100644 index 0000000..1e6a956 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/InventoryCommand.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Xml; +using System.Xml.Serialization; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class InventoryCommand : Command + { + private Inventory Inventory; + private InventoryManager Manager; + + public InventoryCommand(TestClient testClient) + { + Name = "i"; + Description = "Prints out inventory."; + Category = CommandCategory.Inventory; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Manager = Client.Inventory; + Inventory = Manager.Store; + + StringBuilder result = new StringBuilder(); + + InventoryFolder rootFolder = Inventory.RootFolder; + PrintFolder(rootFolder, result, 0); + + return result.ToString(); + } + + void PrintFolder(InventoryFolder f, StringBuilder result, int indent) + { + List contents = Manager.FolderContents(f.UUID, Client.Self.AgentID, + true, true, InventorySortOrder.ByName, 3000); + + if (contents != null) + { + foreach (InventoryBase i in contents) + { + result.AppendFormat("{0}{1} ({2})\n", new String(' ', indent * 2), i.Name, i.UUID); + if (i is InventoryFolder) + { + InventoryFolder folder = (InventoryFolder)i; + PrintFolder(folder, result, indent + 1); + } + } + } + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Inventory/ListContentsCommand.cs b/Programs/examples/TestClient/Commands/Inventory/ListContentsCommand.cs new file mode 100644 index 0000000..73cda4c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/ListContentsCommand.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient.Commands.Inventory.Shell +{ + public class ListContentsCommand : Command + { + private InventoryManager Manager; + private OpenMetaverse.Inventory Inventory; + public ListContentsCommand(TestClient client) + { + Name = "ls"; + Description = "Lists the contents of the current working inventory folder."; + Category = CommandCategory.Inventory; + } + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length > 1) + return "Usage: ls [-l]"; + bool longDisplay = false; + if (args.Length > 0 && args[0] == "-l") + longDisplay = true; + + Manager = Client.Inventory; + Inventory = Manager.Store; + // WARNING: Uses local copy of inventory contents, need to download them first. + List contents = Inventory.GetContents(Client.CurrentDirectory); + string displayString = ""; + string nl = "\n"; // New line character + // Pretty simple, just print out the contents. + foreach (InventoryBase b in contents) + { + if (longDisplay) + { + // Generate a nicely formatted description of the item. + // It kinda looks like the output of the unix ls. + // starts with 'd' if the inventory is a folder, '-' if not. + // 9 character permissions string + // UUID of object + // Name of object + if (b is InventoryFolder) + { + InventoryFolder folder = b as InventoryFolder; + displayString += "d--------- "; + displayString += folder.UUID; + displayString += " " + folder.Name; + } + else if (b is InventoryItem) + { + InventoryItem item = b as InventoryItem; + displayString += "-"; + displayString += PermMaskString(item.Permissions.OwnerMask); + displayString += PermMaskString(item.Permissions.GroupMask); + displayString += PermMaskString(item.Permissions.EveryoneMask); + displayString += " " + item.UUID; + displayString += " " + item.Name; + displayString += nl; + displayString += " AssetID: " + item.AssetUUID; + } + } + else + { + displayString += b.Name; + } + displayString += nl; + } + return displayString; + } + + /// + /// Returns a 3-character summary of the PermissionMask + /// CMT if the mask allows copy, mod and transfer + /// -MT if it disallows copy + /// --T if it only allows transfer + /// --- if it disallows everything + /// + /// + /// + private static string PermMaskString(PermissionMask mask) + { + string str = ""; + if (((uint)mask | (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy) + str += "C"; + else + str += "-"; + if (((uint)mask | (uint)PermissionMask.Modify) == (uint)PermissionMask.Modify) + str += "M"; + else + str += "-"; + if (((uint)mask | (uint)PermissionMask.Transfer) == (uint)PermissionMask.Transfer) + str += "T"; + else + str += "-"; + return str; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/ObjectInventoryCommand.cs b/Programs/examples/TestClient/Commands/Inventory/ObjectInventoryCommand.cs new file mode 100644 index 0000000..8df7543 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/ObjectInventoryCommand.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ObjectInventoryCommand : Command + { + public ObjectInventoryCommand(TestClient testClient) + { + Name = "objectinventory"; + Description = "Retrieves a listing of items inside an object (task inventory). Usage: objectinventory [objectID]"; + Category = CommandCategory.Inventory; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: objectinventory [objectID]"; + + uint objectLocalID; + UUID objectID; + if (!UUID.TryParse(args[0], out objectID)) + return "Usage: objectinventory [objectID]"; + + Primitive found = Client.Network.CurrentSim.ObjectsPrimitives.Find(delegate(Primitive prim) { return prim.ID == objectID; }); + if (found != null) + objectLocalID = found.LocalID; + else + return "Couldn't find prim " + objectID.ToString(); + + List items = Client.Inventory.GetTaskInventory(objectID, objectLocalID, 1000 * 30); + + if (items != null) + { + string result = String.Empty; + + for (int i = 0; i < items.Count; i++) + { + if (items[i] is InventoryFolder) + { + result += String.Format("[Folder] Name: {0}", items[i].Name) + Environment.NewLine; + } + else + { + InventoryItem item = (InventoryItem)items[i]; + result += String.Format("[Item] Name: {0} Desc: {1} Type: {2}", item.Name, item.Description, + item.AssetType) + Environment.NewLine; + } + } + + return result; + } + else + { + return "Failed to download task inventory for " + objectLocalID; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/ScriptCommand.cs b/Programs/examples/TestClient/Commands/Inventory/ScriptCommand.cs new file mode 100644 index 0000000..e72fb44 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/ScriptCommand.cs @@ -0,0 +1,38 @@ +using System; +using System.IO; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ScriptCommand : Command + { + public ScriptCommand(TestClient testClient) + { + Name = "script"; + Description = "Reads TestClient commands from a file. One command per line, arguments separated by spaces. Usage: script [filename]"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: script [filename]"; + + // Load the file + string[] lines; + try { lines = File.ReadAllLines(args[0]); } + catch (Exception e) { return e.Message; } + + // Execute all of the commands + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i].Trim(); + + if (line.Length > 0) + ClientManager.Instance.DoCommandAll(line, UUID.Zero); + } + + return "Finished executing " + lines.Length + " commands"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/TaskRunningCommand.cs b/Programs/examples/TestClient/Commands/Inventory/TaskRunningCommand.cs new file mode 100644 index 0000000..82e7e51 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/TaskRunningCommand.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class TaskRunningCommand : Command + { + public TaskRunningCommand(TestClient testClient) + { + Name = "taskrunning"; + Description = "Retrieves or set IsRunning flag on items inside an object (task inventory). Usage: taskrunning objectID [[scriptName] true|false]"; + Category = CommandCategory.Inventory; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: taskrunning objectID [[scriptName] true|false]"; + + uint objectLocalID; + UUID objectID; + + if (!UUID.TryParse(args[0], out objectID)) + return "Usage: taskrunning objectID [[scriptName] true|false]"; + + Primitive found = Client.Network.CurrentSim.ObjectsPrimitives.Find(delegate(Primitive prim) { return prim.ID == objectID; }); + if (found != null) + objectLocalID = found.LocalID; + else + return String.Format("Couldn't find prim {0}", objectID); + + List items = Client.Inventory.GetTaskInventory(objectID, objectLocalID, 1000 * 30); + + //bool wantSet = false; + bool setTaskTo = false; + if (items != null) + { + string result = String.Empty; + string matching = String.Empty; + bool setAny = false; + if (args.Length > 1) + { + matching = args[1]; + + string tf; + if (args.Length > 2) + { + tf = args[2]; + } + else + { + tf = matching.ToLower(); + } + if (tf == "true") + { + setAny = true; + setTaskTo = true; + } + else if (tf == "false") + { + setAny = true; + setTaskTo = false; + } + + } + bool wasRunning = false; + + EventHandler callback; + using (AutoResetEvent OnScriptRunningReset = new AutoResetEvent(false)) + { + callback = ((object sender, ScriptRunningReplyEventArgs e) => + { + if (e.ObjectID == objectID) + { + result += String.Format(" IsMono: {0} IsRunning: {1}", e.IsMono, e.IsRunning); + wasRunning = e.IsRunning; + OnScriptRunningReset.Set(); + } + }); + + Client.Inventory.ScriptRunningReply += callback; + + for (int i = 0; i < items.Count; i++) + { + if (items[i] is InventoryFolder) + { + // this shouldn't happen this year + result += String.Format("[Folder] Name: {0}", items[i].Name) + Environment.NewLine; + } + else + { + InventoryItem item = (InventoryItem)items[i]; + AssetType assetType = item.AssetType; + result += String.Format("[Item] Name: {0} Desc: {1} Type: {2}", item.Name, item.Description, + assetType); + if (assetType == AssetType.LSLBytecode || assetType == AssetType.LSLText) + { + OnScriptRunningReset.Reset(); + Client.Inventory.RequestGetScriptRunning(objectID, item.UUID); + if (!OnScriptRunningReset.WaitOne(10000, true)) + { + result += " (no script info)"; + } + if (setAny && item.Name.Contains(matching)) + { + if (wasRunning != setTaskTo) + { + OnScriptRunningReset.Reset(); + result += " Setting " + setTaskTo + " => "; + Client.Inventory.RequestSetScriptRunning(objectID, item.UUID, setTaskTo); + if (!OnScriptRunningReset.WaitOne(10000, true)) + { + result += " (was not set)"; + } + } + } + } + + result += Environment.NewLine; + } + } + } + Client.Inventory.ScriptRunningReply -= callback; + return result; + } + else + { + return "Failed to download task inventory for " + objectLocalID; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/TreeCommand.cs b/Programs/examples/TestClient/Commands/Inventory/TreeCommand.cs new file mode 100644 index 0000000..56118c9 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/TreeCommand.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class TreeCommand: Command + { + public TreeCommand(TestClient testClient) + { + Name = "tree"; + Description = "Rez a tree."; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length == 1) + { + try + { + string treeName = args[0].Trim(new char[] { ' ' }); + Tree tree = (Tree)Enum.Parse(typeof(Tree), treeName); + + Vector3 treePosition = Client.Self.SimPosition; + treePosition.Z += 3.0f; + + Client.Objects.AddTree(Client.Network.CurrentSim, new Vector3(0.5f, 0.5f, 0.5f), + Quaternion.Identity, treePosition, tree, Client.GroupID, false); + + return "Attempted to rez a " + treeName + " tree"; + } + catch (Exception) + { + return "Type !tree for usage"; + } + } + + string usage = "Usage: !tree ["; + foreach (string value in Enum.GetNames(typeof(Tree))) + { + usage += value + ","; + } + usage = usage.TrimEnd(new char[] { ',' }); + usage += "]"; + return usage; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs b/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs new file mode 100644 index 0000000..5322bca --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Drawing; +using OpenMetaverse; +using OpenMetaverse.Http; +using OpenMetaverse.Imaging; + +namespace OpenMetaverse.TestClient +{ + public class UploadImageCommand : Command + { + AutoResetEvent UploadCompleteEvent = new AutoResetEvent(false); + UUID TextureID = UUID.Zero; + DateTime start; + + public UploadImageCommand(TestClient testClient) + { + Name = "uploadimage"; + Description = "Upload an image to your inventory. Usage: uploadimage [inventoryname] [timeout] [filename]"; + Category = CommandCategory.Inventory; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + string inventoryName; + uint timeout; + string fileName; + + if (args.Length != 3) + return "Usage: uploadimage [inventoryname] [timeout] [filename]"; + + TextureID = UUID.Zero; + inventoryName = args[0]; + fileName = args[2]; + if (!UInt32.TryParse(args[1], out timeout)) + return "Usage: uploadimage [inventoryname] [timeout] [filename]"; + + Console.WriteLine("Loading image " + fileName); + byte[] jpeg2k = LoadImage(fileName); + if (jpeg2k == null) + return "Failed to compress image to JPEG2000"; + Console.WriteLine("Finished compressing image to JPEG2000, uploading..."); + start = DateTime.Now; + DoUpload(jpeg2k, inventoryName); + + if (UploadCompleteEvent.WaitOne((int)timeout, false)) + { + return String.Format("Texture upload {0}: {1}", (TextureID != UUID.Zero) ? "succeeded" : "failed", + TextureID); + } + else + { + return "Texture upload timed out"; + } + } + + private void DoUpload(byte[] UploadData, string FileName) + { + if (UploadData != null) + { + string name = System.IO.Path.GetFileNameWithoutExtension(FileName); + + Client.Inventory.RequestCreateItemFromAsset(UploadData, name, "Uploaded with TestClient", + AssetType.Texture, InventoryType.Texture, Client.Inventory.FindFolderForType(AssetType.Texture), + delegate(bool success, string status, UUID itemID, UUID assetID) + { + Console.WriteLine(String.Format( + "RequestCreateItemFromAsset() returned: Success={0}, Status={1}, ItemID={2}, AssetID={3}", + success, status, itemID, assetID)); + + TextureID = assetID; + Console.WriteLine(String.Format("Upload took {0}", DateTime.Now.Subtract(start))); + UploadCompleteEvent.Set(); + } + ); + } + } + + private byte[] LoadImage(string fileName) + { + byte[] UploadData; + string lowfilename = fileName.ToLower(); + Bitmap bitmap = null; + + try + { + if (lowfilename.EndsWith(".jp2") || lowfilename.EndsWith(".j2c")) + { + Image image; + ManagedImage managedImage; + + // Upload JPEG2000 images untouched + UploadData = System.IO.File.ReadAllBytes(fileName); + + OpenJPEG.DecodeToImage(UploadData, out managedImage, out image); + bitmap = (Bitmap)image; + } + else + { + if (lowfilename.EndsWith(".tga")) + bitmap = LoadTGAClass.LoadTGA(fileName); + else + bitmap = (Bitmap)System.Drawing.Image.FromFile(fileName); + + int oldwidth = bitmap.Width; + int oldheight = bitmap.Height; + + if (!IsPowerOfTwo((uint)oldwidth) || !IsPowerOfTwo((uint)oldheight)) + { + Bitmap resized = new Bitmap(256, 256, bitmap.PixelFormat); + Graphics graphics = Graphics.FromImage(resized); + + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + graphics.InterpolationMode = + System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + graphics.DrawImage(bitmap, 0, 0, 256, 256); + + bitmap.Dispose(); + bitmap = resized; + + oldwidth = 256; + oldheight = 256; + } + + // Handle resizing to prevent excessively large images + if (oldwidth > 1024 || oldheight > 1024) + { + int newwidth = (oldwidth > 1024) ? 1024 : oldwidth; + int newheight = (oldheight > 1024) ? 1024 : oldheight; + + Bitmap resized = new Bitmap(newwidth, newheight, bitmap.PixelFormat); + Graphics graphics = Graphics.FromImage(resized); + + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + graphics.InterpolationMode = + System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + graphics.DrawImage(bitmap, 0, 0, newwidth, newheight); + + bitmap.Dispose(); + bitmap = resized; + } + + UploadData = OpenJPEG.EncodeFromImage(bitmap, false); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString() + " SL Image Upload "); + return null; + } + return UploadData; + } + + private static bool IsPowerOfTwo(uint n) + { + return (n & (n - 1)) == 0 && n != 0; + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Inventory/UploadScriptCommand.cs b/Programs/examples/TestClient/Commands/Inventory/UploadScriptCommand.cs new file mode 100644 index 0000000..7664f25 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/UploadScriptCommand.cs @@ -0,0 +1,89 @@ +using System; +using System.IO; +using System.Collections.Generic; + +namespace OpenMetaverse.TestClient +{ + /// + /// Example of how to put a new script in your inventory + /// + public class UploadScriptCommand : Command + { + /// + /// The default constructor for TestClient commands + /// + /// + public UploadScriptCommand(TestClient testClient) + { + Name = "uploadscript"; + Description = "Upload a local .lsl file file into your inventory."; + Category = CommandCategory.Inventory; + } + + /// + /// The default override for TestClient commands + /// + /// + /// + /// + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: uploadscript filename.lsl"; + + string file = String.Empty; + for (int ct = 0; ct < args.Length; ct++) + file = String.Format("{0}{1} ", file, args[ct]); + file = file.TrimEnd(); + + if (!File.Exists(file)) + return String.Format("Filename '{0}' does not exist", file); + + string ret = String.Format("Filename: {0}", file); + + try + { + using (StreamReader reader = new StreamReader(file)) + { + string body = reader.ReadToEnd(); + string desc = String.Format("{0} created by OpenMetaverse TestClient {1}", file, DateTime.Now); + // create the asset + Client.Inventory.RequestCreateItem(Client.Inventory.FindFolderForType(AssetType.LSLText), file, desc, AssetType.LSLText, UUID.Random(), InventoryType.LSL, PermissionMask.All, + delegate(bool success, InventoryItem item) + { + if (success) + // upload the asset + Client.Inventory.RequestUpdateScriptAgentInventory(EncodeScript(body), item.UUID, true, new InventoryManager.ScriptUpdatedCallback(delegate(bool uploadSuccess, string uploadStatus, bool compileSuccess, List compileMessages, UUID itemid, UUID assetid) + { + if (uploadSuccess) + ret += String.Format(" Script successfully uploaded, ItemID {0} AssetID {1}", itemid, assetid); + if (compileSuccess) + ret += " compilation successful"; + + })); + }); + } + return ret; + + } + catch (System.Exception e) + { + Logger.Log(e.ToString(), Helpers.LogLevel.Error, Client); + return String.Format("Error creating script for {0}", ret); + } + } + /// + /// Encodes the script text for uploading + /// + /// + public static byte[] EncodeScript(string body) + { + // Assume this is a string, add 1 for the null terminator ? + byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(body); + byte[] assetData = new byte[stringBytes.Length]; //+ 1]; + Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length); + return assetData; + } + } + +} diff --git a/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs b/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs new file mode 100644 index 0000000..adabc60 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class ViewNotecardCommand : Command + { + /// + /// TestClient command to download and display a notecard asset + /// + /// + public ViewNotecardCommand(TestClient testClient) + { + Name = "viewnote"; + Description = "Downloads and displays a notecard asset"; + Category = CommandCategory.Inventory; + } + + /// + /// Exectute the command + /// + /// + /// + /// + public override string Execute(string[] args, UUID fromAgentID) + { + + if (args.Length < 1) + { + return "Usage: viewnote [notecard asset uuid]"; + } + UUID note; + if (!UUID.TryParse(args[0], out note)) + { + return "First argument expected agent UUID."; + } + + System.Threading.AutoResetEvent waitEvent = new System.Threading.AutoResetEvent(false); + + System.Text.StringBuilder result = new System.Text.StringBuilder(); + + // verify asset is loaded in store + if (Client.Inventory.Store.Contains(note)) + { + // retrieve asset from store + InventoryItem ii = (InventoryItem)Client.Inventory.Store[note]; + + // make request for asset + Client.Assets.RequestInventoryAsset(ii, true, + delegate(AssetDownload transfer, Asset asset) + { + if (transfer.Success) + { + result.AppendFormat("Raw Notecard Data: " + System.Environment.NewLine + " {0}", Utils.BytesToString(asset.AssetData)); + waitEvent.Set(); + } + } + ); + + // wait for reply or timeout + if (!waitEvent.WaitOne(10000, false)) + { + result.Append("Timeout waiting for notecard to download."); + } + } + else + { + result.Append("Cannot find asset in inventory store, use 'i' to populate store"); + } + + // return results + return result.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Inventory/XferCommand.cs b/Programs/examples/TestClient/Commands/Inventory/XferCommand.cs new file mode 100644 index 0000000..5029275 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Inventory/XferCommand.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.TestClient +{ + public class XferCommand : Command + { + const int FETCH_ASSET_TIMEOUT = 1000 * 10; + + public XferCommand(TestClient testClient) + { + Name = "xfer"; + Description = "Downloads the specified asset using the Xfer system. Usage: xfer [uuid]"; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + UUID assetID; + + if (args.Length != 1 || !UUID.TryParse(args[0], out assetID)) + return "Usage: xfer [uuid]"; + + string filename; + byte[] assetData = RequestXfer(assetID, AssetType.Object, out filename); + + if (assetData != null) + { + try + { + File.WriteAllBytes(filename, assetData); + return "Saved asset " + filename; + } + catch (Exception ex) + { + return "Failed to save asset " + filename + ": " + ex.Message; + } + } + else + { + return "Failed to xfer asset " + assetID; + } + } + + byte[] RequestXfer(UUID assetID, AssetType type, out string filename) + { + AutoResetEvent xferEvent = new AutoResetEvent(false); + ulong xferID = 0; + byte[] data = null; + + EventHandler xferCallback = + delegate(object sender, XferReceivedEventArgs e) + { + if (e.Xfer.XferID == xferID) + { + if (e.Xfer.Success) + data = e.Xfer.AssetData; + xferEvent.Set(); + } + }; + + Client.Assets.XferReceived += xferCallback; + + filename = assetID + ".asset"; + xferID = Client.Assets.RequestAssetXfer(filename, false, true, assetID, type, false); + + xferEvent.WaitOne(FETCH_ASSET_TIMEOUT, false); + + Client.Assets.XferReceived -= xferCallback; + + return data; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/AgentLocationsCommand.cs b/Programs/examples/TestClient/Commands/Land/AgentLocationsCommand.cs new file mode 100644 index 0000000..b06278a --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/AgentLocationsCommand.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + /// + /// Display a list of all agent locations in a specified region + /// + public class AgentLocationsCommand : Command + { + public AgentLocationsCommand(TestClient testClient) + { + Name = "agentlocations"; + Description = "Downloads all of the agent locations in a specified region. Usage: agentlocations [regionhandle]"; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + ulong regionHandle; + + if (args.Length == 0) + regionHandle = Client.Network.CurrentSim.Handle; + else if (!(args.Length == 1 && UInt64.TryParse(args[0], out regionHandle))) + return "Usage: agentlocations [regionhandle]"; + + List items = Client.Grid.MapItems(regionHandle, GridItemType.AgentLocations, + GridLayerType.Objects, 1000 * 20); + + if (items != null) + { + StringBuilder ret = new StringBuilder(); + ret.AppendLine("Agent locations:"); + + for (int i = 0; i < items.Count; i++) + { + MapAgentLocation location = (MapAgentLocation)items[i]; + + ret.AppendLine(String.Format("{0} avatar(s) at {1},{2}", location.AvatarCount, location.LocalX, + location.LocalY)); + } + + return ret.ToString(); + } + else + { + return "Failed to fetch agent locations"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/FindSimCommand.cs b/Programs/examples/TestClient/Commands/Land/FindSimCommand.cs new file mode 100644 index 0000000..f69d52c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/FindSimCommand.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class FindSimCommand : Command + { + public FindSimCommand(TestClient testClient) + { + Name = "findsim"; + Description = "Searches for a simulator and returns information about it. Usage: findsim [Simulator Name]"; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: findsim [Simulator Name]"; + + // Build the simulator name from the args list + string simName = string.Empty; + for (int i = 0; i < args.Length; i++) + simName += args[i] + " "; + simName = simName.TrimEnd().ToLower(); + + //if (!GridDataCached[Client]) + //{ + // Client.Grid.RequestAllSims(GridManager.MapLayerType.Objects); + // System.Threading.Thread.Sleep(5000); + // GridDataCached[Client] = true; + //} + + GridRegion region; + + if (Client.Grid.GetGridRegion(simName, GridLayerType.Objects, out region)) + return String.Format("{0}: handle={1} ({2},{3})", region.Name, region.RegionHandle, region.X, region.Y); + else + return "Lookup of " + simName + " failed"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/GridLayerCommand.cs b/Programs/examples/TestClient/Commands/Land/GridLayerCommand.cs new file mode 100644 index 0000000..bb775fe --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/GridLayerCommand.cs @@ -0,0 +1,30 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class GridLayerCommand : Command + { + public GridLayerCommand(TestClient testClient) + { + Name = "gridlayer"; + Description = "Downloads all of the layer chunks for the grid object map"; + Category = CommandCategory.Simulator; + + testClient.Grid.GridLayer += Grid_GridLayer; + } + + void Grid_GridLayer(object sender, GridLayerEventArgs e) + { + Console.WriteLine(String.Format("Layer({0}) Bottom: {1} Left: {2} Top: {3} Right: {4}", + e.Layer.ImageID.ToString(), e.Layer.Bottom, e.Layer.Left, e.Layer.Top, e.Layer.Right)); + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Client.Grid.RequestMapLayer(GridLayerType.Objects); + + return "Sent."; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/GridMapCommand.cs b/Programs/examples/TestClient/Commands/Land/GridMapCommand.cs new file mode 100644 index 0000000..6273763 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/GridMapCommand.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class GridMapCommand : Command + { + public GridMapCommand(TestClient testClient) + { + Name = "gridmap"; + Description = "Downloads all visible information about the grid map"; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + //if (args.Length < 1) + // return ""; + + Client.Grid.RequestMainlandSims(GridLayerType.Objects); + + return "Sent."; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/ParcelDetailsCommand.cs b/Programs/examples/TestClient/Commands/Land/ParcelDetailsCommand.cs new file mode 100644 index 0000000..18aff2a --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/ParcelDetailsCommand.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ParcelDetailsCommand : Command + { + public ParcelDetailsCommand(TestClient testClient) + { + Name = "parceldetails"; + Description = "Displays parcel details from the ParcelTracker dictionary. Usage: parceldetails parcelID"; + Category = CommandCategory.Parcel; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: parceldetails parcelID (use parcelinfo to get ID)"; + + int parcelID; + Parcel parcel; + + // test argument that is is a valid integer, then verify we have that parcel data stored in the dictionary + if (Int32.TryParse(args[0], out parcelID) && Client.Network.CurrentSim.Parcels.TryGetValue(parcelID, out parcel)) + { + // this request will update the parcels dictionary + Client.Parcels.RequestParcelProperties(Client.Network.CurrentSim, parcelID, 0); + + // Use reflection to dynamically get the fields from the Parcel struct + Type t = parcel.GetType(); + System.Reflection.FieldInfo[] fields = t.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); + + StringBuilder sb = new StringBuilder(); + foreach (System.Reflection.FieldInfo field in fields) + { + sb.AppendFormat("{0} = {1}" + System.Environment.NewLine, field.Name, field.GetValue(parcel)); + } + return sb.ToString(); + } + else + { + return String.Format("Unable to find Parcel {0} in Parcels Dictionary, Did you run parcelinfo to populate the dictionary first?", args[0]); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/ParcelInfoCommand.cs b/Programs/examples/TestClient/Commands/Land/ParcelInfoCommand.cs new file mode 100644 index 0000000..8dc261c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/ParcelInfoCommand.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ParcelInfoCommand : Command + { + private AutoResetEvent ParcelsDownloaded = new AutoResetEvent(false); + + public ParcelInfoCommand(TestClient testClient) + { + Name = "parcelinfo"; + Description = "Prints out info about all the parcels in this simulator"; + Category = CommandCategory.Parcel; + + testClient.Network.Disconnected += Network_OnDisconnected; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + StringBuilder sb = new StringBuilder(); + string result; + EventHandler del = delegate(object sender, SimParcelsDownloadedEventArgs e) + { + ParcelsDownloaded.Set(); + }; + + + ParcelsDownloaded.Reset(); + Client.Parcels.SimParcelsDownloaded += del; + Client.Parcels.RequestAllSimParcels(Client.Network.CurrentSim); + + if (Client.Network.CurrentSim.IsParcelMapFull()) + ParcelsDownloaded.Set(); + + if (ParcelsDownloaded.WaitOne(30000, false) && Client.Network.Connected) + { + sb.AppendFormat("Downloaded {0} Parcels in {1} " + System.Environment.NewLine, + Client.Network.CurrentSim.Parcels.Count, Client.Network.CurrentSim.Name); + + Client.Network.CurrentSim.Parcels.ForEach(delegate(Parcel parcel) + { + sb.AppendFormat("Parcel[{0}]: Name: \"{1}\", Description: \"{2}\" ACLBlacklist Count: {3}, ACLWhiteList Count: {5} Traffic: {4}" + System.Environment.NewLine, + parcel.LocalID, parcel.Name, parcel.Desc, parcel.AccessBlackList.Count, parcel.Dwell, parcel.AccessWhiteList.Count); + }); + + result = sb.ToString(); + } + else + result = "Failed to retrieve information on all the simulator parcels"; + + Client.Parcels.SimParcelsDownloaded -= del; + return result; + } + + void Network_OnDisconnected(object sender, DisconnectedEventArgs e) + { + ParcelsDownloaded.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/ParcelPrimOwnersCommand.cs b/Programs/examples/TestClient/Commands/Land/ParcelPrimOwnersCommand.cs new file mode 100644 index 0000000..1cb4def --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/ParcelPrimOwnersCommand.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ParcelPrimOwnersCommand : Command + { + public ParcelPrimOwnersCommand(TestClient testClient) + { + Name = "primowners"; + Description = "Displays a list of prim owners and prim counts on a parcel. Usage: primowners parcelID"; + Category = CommandCategory.Parcel; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: primowners parcelID (use parcelinfo to get ID)"; + + int parcelID; + Parcel parcel; + StringBuilder result = new StringBuilder(); + // test argument that is is a valid integer, then verify we have that parcel data stored in the dictionary + if (Int32.TryParse(args[0], out parcelID) && Client.Network.CurrentSim.Parcels.TryGetValue(parcelID, out parcel)) + { + AutoResetEvent wait = new AutoResetEvent(false); + + EventHandler callback = delegate(object sender, ParcelObjectOwnersReplyEventArgs e) + { + for (int i = 0; i < e.PrimOwners.Count; i++) + { + result.AppendFormat("Owner: {0} Count: {1}" + System.Environment.NewLine, e.PrimOwners[i].OwnerID, e.PrimOwners[i].Count); + wait.Set(); + } + }; + + + Client.Parcels.ParcelObjectOwnersReply += callback; + + Client.Parcels.RequestObjectOwners(Client.Network.CurrentSim, parcelID); + if (!wait.WaitOne(10000, false)) + { + result.AppendLine("Timed out waiting for packet."); + } + Client.Parcels.ParcelObjectOwnersReply -= callback; + + return result.ToString(); + } + else + { + return String.Format("Unable to find Parcel {0} in Parcels Dictionary, Did you run parcelinfo to populate the dictionary first?", args[0]); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/ParcelSelectObjectsCommand.cs b/Programs/examples/TestClient/Commands/Land/ParcelSelectObjectsCommand.cs new file mode 100644 index 0000000..afdd5ca --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/ParcelSelectObjectsCommand.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ParcelSelectObjectsCommand : Command + { + public ParcelSelectObjectsCommand(TestClient testClient) + { + Name = "selectobjects"; + Description = "Displays a list of prim localIDs on a given parcel with a specific owner. Usage: selectobjects parcelID OwnerUUID"; + Category = CommandCategory.Parcel; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 2) + return "Usage: selectobjects parcelID OwnerUUID (use parcelinfo to get ID, use parcelprimowners to get ownerUUID)"; + + int parcelID; + UUID ownerUUID; + + int counter = 0; + StringBuilder result = new StringBuilder(); + // test argument that is is a valid integer, then verify we have that parcel data stored in the dictionary + if (Int32.TryParse(args[0], out parcelID) + && UUID.TryParse(args[1], out ownerUUID)) + { + AutoResetEvent wait = new AutoResetEvent(false); + EventHandler callback = delegate(object sender, ForceSelectObjectsReplyEventArgs e) + { + + for (int i = 0; i < e.ObjectIDs.Count; i++) + { + result.Append(e.ObjectIDs[i].ToString() + " "); + counter++; + } + + if (e.ObjectIDs.Count < 251) + wait.Set(); + }; + + + Client.Parcels.ForceSelectObjectsReply += callback; + Client.Parcels.RequestSelectObjects(parcelID, (ObjectReturnType)16, ownerUUID); + + + Client.Parcels.RequestObjectOwners(Client.Network.CurrentSim, parcelID); + if (!wait.WaitOne(30000, false)) + { + result.AppendLine("Timed out waiting for packet."); + } + + Client.Parcels.ForceSelectObjectsReply -= callback; + result.AppendLine("Found a total of " + counter + " Objects"); + return result.ToString(); + } + else + { + return String.Format("Unable to find Parcel {0} in Parcels Dictionary, Did you run parcelinfo to populate the dictionary first?", args[0]); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Land/WindCommand.cs b/Programs/examples/TestClient/Commands/Land/WindCommand.cs new file mode 100644 index 0000000..d16c901 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Land/WindCommand.cs @@ -0,0 +1,28 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class WindCommand : Command + { + public WindCommand(TestClient testClient) + { + Name = "wind"; + Description = "Displays current wind data"; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // Get the agent's current "patch" position, where each patch of + // wind data is a 16x16m square + Vector3 agentPos = Client.Self.SimPosition; + int xPos = (int)Utils.Clamp(agentPos.X, 0.0f, 255.0f) / 16; + int yPos = (int)Utils.Clamp(agentPos.Y, 0.0f, 255.0f) / 16; + + Vector2 windSpeed = Client.Network.CurrentSim.WindSpeeds[yPos * 16 + xPos]; + + return "Local wind speed is " + windSpeed.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/BackCommand.cs b/Programs/examples/TestClient/Commands/Movement/BackCommand.cs new file mode 100644 index 0000000..7587fef --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/BackCommand.cs @@ -0,0 +1,53 @@ +using System; + +namespace OpenMetaverse.TestClient.Commands.Movement +{ + class BackCommand : Command + { + public BackCommand(TestClient client) + { + Name = "back"; + Description = "Sends the move back command to the server for a single packet or a given number of seconds. Usage: back [seconds]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length > 1) + return "Usage: back [seconds]"; + + if (args.Length == 0) + { + Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, Client.Self.Movement.Camera.Position, + Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis, + Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None, + AgentState.None, true); + } + else + { + // Parse the number of seconds + int duration; + if (!Int32.TryParse(args[0], out duration)) + return "Usage: back [seconds]"; + // Convert to milliseconds + duration *= 1000; + + int start = Environment.TickCount; + + Client.Self.Movement.AtNeg = true; + + while (Environment.TickCount - start < duration) + { + // The movement timer will do this automatically, but we do it here as an example + // and to make sure updates are being sent out fast enough + Client.Self.Movement.SendUpdate(false); + System.Threading.Thread.Sleep(100); + } + + Client.Self.Movement.AtNeg = false; + } + + return "Moved backward"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/CrouchCommand.cs b/Programs/examples/TestClient/Commands/Movement/CrouchCommand.cs new file mode 100644 index 0000000..ac5a1ce --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/CrouchCommand.cs @@ -0,0 +1,34 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class CrouchCommand : Command + { + public CrouchCommand(TestClient testClient) + { + Name = "crouch"; + Description = "Starts or stops crouching. Usage: crouch [start/stop]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + bool start = true; + + if (args.Length == 1 && args[0].ToLower() == "stop") + start = false; + + if (start) + { + Client.Self.Crouch(true); + return "Started crouching"; + } + else + { + Client.Self.Crouch(false); + return "Stopped crouching"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/FlyCommand.cs b/Programs/examples/TestClient/Commands/Movement/FlyCommand.cs new file mode 100644 index 0000000..aaf85e9 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/FlyCommand.cs @@ -0,0 +1,34 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class FlyCommand : Command + { + public FlyCommand(TestClient testClient) + { + Name = "fly"; + Description = "Starts or stops flying. Usage: fly [start/stop]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + bool start = true; + + if (args.Length == 1 && args[0].ToLower() == "stop") + start = false; + + if (start) + { + Client.Self.Fly(true); + return "Started flying"; + } + else + { + Client.Self.Fly(false); + return "Stopped flying"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/FlyToCommand.cs b/Programs/examples/TestClient/Commands/Movement/FlyToCommand.cs new file mode 100644 index 0000000..3227511 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/FlyToCommand.cs @@ -0,0 +1,164 @@ +using System; + +namespace OpenMetaverse.TestClient.Commands.Movement +{ + class FlyToCommand : Command + { + + Vector3 myPos = new Vector3(); + Vector2 myPos0 = new Vector2(); + Vector3 target = new Vector3(); + Vector2 target0 = new Vector2(); + float diff, olddiff, saveolddiff; + int startTime = 0; + int duration = 10000; + bool running = false; + + public FlyToCommand(TestClient Client) + { + Name = "FlyTo"; + Description = "Fly the avatar toward the specified position for a maximum of seconds. Usage: FlyTo x y z [seconds]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length > 4 || args.Length < 3) + return "Usage: FlyTo x y z [seconds]"; + + if (!float.TryParse(args[0], out target.X) || + !float.TryParse(args[1], out target.Y) || + !float.TryParse(args[2], out target.Z)) + { + return "Usage: FlyTo x y z [seconds]"; + } + + if (running) + return "Already in progress, wait for the previous FlyTo to finish"; + + running = true; + + // Subscribe to terse update events while this command is running + Client.Objects.TerseObjectUpdate += Objects_OnObjectUpdated; + + target0.X = target.X; + target0.Y = target.Y; + + if (args.Length == 4 && Int32.TryParse(args[3], out duration)) + duration *= 1000; + + startTime = Environment.TickCount; + Client.Self.Movement.Fly = true; + Client.Self.Movement.AtPos = true; + Client.Self.Movement.AtNeg = false; + ZMovement(); + Client.Self.Movement.TurnToward(target); + + return string.Format("flying to {0} in {1} seconds", target.ToString(), duration / 1000); + } + + private void Objects_OnObjectUpdated(object sender, TerseObjectUpdateEventArgs e) + { + if (startTime == 0) return; + if (e.Update.LocalID == Client.Self.LocalID) + { + XYMovement(); + ZMovement(); + if (Client.Self.Movement.AtPos || Client.Self.Movement.AtNeg) + { + Client.Self.Movement.TurnToward(target); + Debug("Flyxy "); + } + else if (Client.Self.Movement.UpPos || Client.Self.Movement.UpNeg) + { + Client.Self.Movement.TurnToward(target); + //Client.Self.Movement.SendUpdate(false); + Debug("Fly z "); + } + else if (Vector3.Distance(target, Client.Self.SimPosition) <= 2.0) + { + EndFlyto(); + Debug("At Target"); + } + } + if (Environment.TickCount - startTime > duration) + { + EndFlyto(); + Debug("End Flyto"); + } + } + + private bool XYMovement() + { + bool res = false; + + myPos = Client.Self.SimPosition; + myPos0.X = myPos.X; + myPos0.Y = myPos.Y; + diff = Vector2.Distance(target0, myPos0); + Vector2 vvel = new Vector2(Client.Self.Velocity.X, Client.Self.Velocity.Y); + float vel = vvel.Length(); + if (diff >= 10.0) + { + Client.Self.Movement.AtPos = true; + + res = true; + } + else if (diff >= 2 && vel < 5) + { + Client.Self.Movement.AtPos = true; + } + else + { + Client.Self.Movement.AtPos = false; + Client.Self.Movement.AtNeg = false; + } + saveolddiff = olddiff; + olddiff = diff; + return res; + } + + private void ZMovement() + { + Client.Self.Movement.UpPos = false; + Client.Self.Movement.UpNeg = false; + float diffz = (target.Z - Client.Self.SimPosition.Z); + if (diffz >= 20.0) + Client.Self.Movement.UpPos = true; + else if (diffz <= -20.0) + Client.Self.Movement.UpNeg = true; + else if (diffz >= +5.0 && Client.Self.Velocity.Z < +4.0) + Client.Self.Movement.UpPos = true; + else if (diffz <= -5.0 && Client.Self.Velocity.Z > -4.0) + Client.Self.Movement.UpNeg = true; + else if (diffz >= +2.0 && Client.Self.Velocity.Z < +1.0) + Client.Self.Movement.UpPos = true; + else if (diffz <= -2.0 && Client.Self.Velocity.Z > -1.0) + Client.Self.Movement.UpNeg = true; + } + + private void EndFlyto() + { + // Unsubscribe from terse update events + Client.Objects.TerseObjectUpdate -= Objects_OnObjectUpdated; + + startTime = 0; + Client.Self.Movement.AtPos = false; + Client.Self.Movement.AtNeg = false; + Client.Self.Movement.UpPos = false; + Client.Self.Movement.UpNeg = false; + Client.Self.Movement.SendUpdate(false); + + running = false; + } + + [System.Diagnostics.Conditional("DEBUG")] + private void Debug(string x) + { + Console.WriteLine(x + " {0,3:##0} {1,3:##0} {2,3:##0} diff {3,5:##0.0} olddiff {4,5:##0.0} At:{5,5} {6,5} Up:{7,5} {8,5} v: {9} w: {10}", + myPos.X, myPos.Y, myPos.Z, diff, saveolddiff, + Client.Self.Movement.AtPos, Client.Self.Movement.AtNeg, Client.Self.Movement.UpPos, Client.Self.Movement.UpNeg, + Client.Self.Velocity.ToString(), Client.Self.AngularVelocity.ToString()); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/FollowCommand.cs b/Programs/examples/TestClient/Commands/Movement/FollowCommand.cs new file mode 100644 index 0000000..da4f6c4 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/FollowCommand.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class FollowCommand: Command + { + const float DISTANCE_BUFFER = 3.0f; + uint targetLocalID = 0; + + public FollowCommand(TestClient testClient) + { + Name = "follow"; + Description = "Follow another avatar. Usage: follow [FirstName LastName]/off."; + Category = CommandCategory.Movement; + + testClient.Network.RegisterCallback(PacketType.AlertMessage, AlertMessageHandler); + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // Construct the target name from the passed arguments + string target = String.Empty; + for (int ct = 0; ct < args.Length; ct++) + target = target + args[ct] + " "; + target = target.TrimEnd(); + + if (target.Length == 0 || target == "off") + { + Active = false; + targetLocalID = 0; + Client.Self.AutoPilotCancel(); + return "Following is off"; + } + else + { + if (Follow(target)) + return "Following " + target; + else + return "Unable to follow " + target + ". Client may not be able to see that avatar."; + } + } + + bool Follow(string name) + { + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Avatar target = Client.Network.Simulators[i].ObjectsAvatars.Find( + delegate(Avatar avatar) + { + return avatar.Name == name; + } + ); + + if (target != null) + { + targetLocalID = target.LocalID; + Active = true; + return true; + } + } + } + + if (Active) + { + Client.Self.AutoPilotCancel(); + Active = false; + } + + return false; + } + + public override void Think() + { + if (Active) + { + // Find the target position + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Avatar targetAv; + + if (Client.Network.Simulators[i].ObjectsAvatars.TryGetValue(targetLocalID, out targetAv)) + { + float distance = 0.0f; + + if (Client.Network.Simulators[i] == Client.Network.CurrentSim) + { + distance = Vector3.Distance(targetAv.Position, Client.Self.SimPosition); + } + else + { + // FIXME: Calculate global distances + } + + if (distance > DISTANCE_BUFFER) + { + uint regionX, regionY; + Utils.LongToUInts(Client.Network.Simulators[i].Handle, out regionX, out regionY); + + double xTarget = (double)targetAv.Position.X + (double)regionX; + double yTarget = (double)targetAv.Position.Y + (double)regionY; + double zTarget = targetAv.Position.Z - 2f; + + Logger.DebugLog(String.Format("[Autopilot] {0} meters away from the target, starting autopilot to <{1},{2},{3}>", + distance, xTarget, yTarget, zTarget), Client); + + Client.Self.AutoPilot(xTarget, yTarget, zTarget); + } + else + { + // We are in range of the target and moving, stop moving + Client.Self.AutoPilotCancel(); + } + } + } + } + } + + base.Think(); + } + + private void AlertMessageHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + AlertMessagePacket alert = (AlertMessagePacket)packet; + string message = Utils.BytesToString(alert.AlertData.Message); + + if (message.Contains("Autopilot cancel")) + { + Logger.Log("FollowCommand: " + message, Helpers.LogLevel.Info, Client); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/ForwardCommand.cs b/Programs/examples/TestClient/Commands/Movement/ForwardCommand.cs new file mode 100644 index 0000000..59b5263 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/ForwardCommand.cs @@ -0,0 +1,53 @@ +using System; + +namespace OpenMetaverse.TestClient.Commands.Movement +{ + class ForwardCommand : Command + { + public ForwardCommand(TestClient client) + { + Name = "forward"; + Description = "Sends the move forward command to the server for a single packet or a given number of seconds. Usage: forward [seconds]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length > 1) + return "Usage: forward [seconds]"; + + if (args.Length == 0) + { + Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, Client.Self.Movement.Camera.Position, + Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis, + Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None, + AgentState.None, true); + } + else + { + // Parse the number of seconds + int duration; + if (!Int32.TryParse(args[0], out duration)) + return "Usage: forward [seconds]"; + // Convert to milliseconds + duration *= 1000; + + int start = Environment.TickCount; + + Client.Self.Movement.AtPos = true; + + while (Environment.TickCount - start < duration) + { + // The movement timer will do this automatically, but we do it here as an example + // and to make sure updates are being sent out fast enough + Client.Self.Movement.SendUpdate(false); + System.Threading.Thread.Sleep(100); + } + + Client.Self.Movement.AtPos = false; + } + + return "Moved forward"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/GoHome.cs b/Programs/examples/TestClient/Commands/Movement/GoHome.cs new file mode 100644 index 0000000..174065d --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/GoHome.cs @@ -0,0 +1,24 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class GoHomeCommand : Command + { + public GoHomeCommand(TestClient testClient) + { + Name = "gohome"; + Description = "Teleports home"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if ( Client.Self.GoHome() ) { + return "Teleport Home Succesful"; + } else { + return "Teleport Home Failed"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/GotoCommand.cs b/Programs/examples/TestClient/Commands/Movement/GotoCommand.cs new file mode 100644 index 0000000..5dc555c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/GotoCommand.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class GotoCommand: Command + { + public GotoCommand(TestClient testClient) + { + Name = "goto"; + Description = "Teleport to a location (e.g. \"goto Hooper/100/100/30\")"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: goto sim/x/y/z"; + + string destination = String.Empty; + + // Handle multi-word sim names by combining the arguments + foreach (string arg in args) + { + destination += arg + " "; + } + destination = destination.Trim(); + + string[] tokens = destination.Split(new char[] { '/' }); + if (tokens.Length != 4) + return "Usage: goto sim/x/y/z"; + + string sim = tokens[0]; + float x, y, z; + if (!float.TryParse(tokens[1], out x) || + !float.TryParse(tokens[2], out y) || + !float.TryParse(tokens[3], out z)) + { + return "Usage: goto sim/x/y/z"; + } + + if (Client.Self.Teleport(sim, new Vector3(x, y, z))) + return "Teleported to " + Client.Network.CurrentSim; + else + return "Teleport failed: " + Client.Self.TeleportMessage; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/GotoLandmark.cs b/Programs/examples/TestClient/Commands/Movement/GotoLandmark.cs new file mode 100644 index 0000000..a1c4c61 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/GotoLandmark.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class GotoLandmarkCommand : Command + { + public GotoLandmarkCommand(TestClient testClient) + { + Name = "goto_landmark"; + Description = "Teleports to a Landmark. Usage: goto_landmark [UUID]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + { + return "Usage: goto_landmark [UUID]"; + } + + UUID landmark = new UUID(); + if (!UUID.TryParse(args[0], out landmark)) + { + return "Invalid LLUID"; + } + else + { + Console.WriteLine("Teleporting to " + landmark.ToString()); + } + if (Client.Self.Teleport(landmark)) + { + return "Teleport Succesful"; + } + else + { + return "Teleport Failed"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/JumpCommand.cs b/Programs/examples/TestClient/Commands/Movement/JumpCommand.cs new file mode 100644 index 0000000..ba8526e --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/JumpCommand.cs @@ -0,0 +1,21 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class JumpCommand: Command + { + public JumpCommand(TestClient testClient) + { + Name = "jump"; + Description = "Jumps or flies up"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Client.Self.Jump(true); + return "Jumped"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/LeftCommand.cs b/Programs/examples/TestClient/Commands/Movement/LeftCommand.cs new file mode 100644 index 0000000..175979f --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/LeftCommand.cs @@ -0,0 +1,53 @@ +using System; + +namespace OpenMetaverse.TestClient.Commands.Movement +{ + class LeftCommand : Command + { + public LeftCommand(TestClient client) + { + Name = "left"; + Description = "Sends the move left command to the server for a single packet or a given number of seconds. Usage: left [seconds]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length > 1) + return "Usage: left [seconds]"; + + if (args.Length == 0) + { + Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS, Client.Self.Movement.Camera.Position, + Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis, + Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None, + AgentState.None, true); + } + else + { + // Parse the number of seconds + int duration; + if (!Int32.TryParse(args[0], out duration)) + return "Usage: left [seconds]"; + // Convert to milliseconds + duration *= 1000; + + int start = Environment.TickCount; + + Client.Self.Movement.LeftPos = true; + + while (Environment.TickCount - start < duration) + { + // The movement timer will do this automatically, but we do it here as an example + // and to make sure updates are being sent out fast enough + Client.Self.Movement.SendUpdate(false); + System.Threading.Thread.Sleep(100); + } + + Client.Self.Movement.LeftPos = false; + } + + return "Moved left"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/LocationCommand.cs b/Programs/examples/TestClient/Commands/Movement/LocationCommand.cs new file mode 100644 index 0000000..7351ca4 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/LocationCommand.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class LocationCommand: Command + { + public LocationCommand(TestClient testClient) + { + Name = "location"; + Description = "Show current location of avatar."; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + return "CurrentSim: '" + Client.Network.CurrentSim.ToString() + "' Position: " + + Client.Self.SimPosition.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/MoveToCommand.cs b/Programs/examples/TestClient/Commands/Movement/MoveToCommand.cs new file mode 100644 index 0000000..cfde739 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/MoveToCommand.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands.Movement +{ + class MovetoCommand : Command + { + public MovetoCommand(TestClient client) + { + Name = "moveto"; + Description = "Moves the avatar to the specified global position using simulator autopilot. Usage: moveto x y z"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 3) + return "Usage: moveto x y z"; + + uint regionX, regionY; + Utils.LongToUInts(Client.Network.CurrentSim.Handle, out regionX, out regionY); + + double x, y, z; + if (!Double.TryParse(args[0], out x) || + !Double.TryParse(args[1], out y) || + !Double.TryParse(args[2], out z)) + { + return "Usage: moveto x y z"; + } + + // Convert the local coordinates to global ones by adding the region handle parts to x and y + x += (double)regionX; + y += (double)regionY; + + Client.Self.AutoPilot(x, y, z); + + return String.Format("Attempting to move to <{0},{1},{2}>", x, y, z); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/RightCommand.cs b/Programs/examples/TestClient/Commands/Movement/RightCommand.cs new file mode 100644 index 0000000..8adb843 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/RightCommand.cs @@ -0,0 +1,53 @@ +using System; + +namespace OpenMetaverse.TestClient.Commands.Movement +{ + class RightCommand : Command + { + public RightCommand(TestClient client) + { + Name = "right"; + Description = "Sends the move right command to the server for a single packet or a given number of seconds. Usage: right [seconds]"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length > 1) + return "Usage: right [seconds]"; + + if (args.Length == 0) + { + Client.Self.Movement.SendManualUpdate(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG, Client.Self.Movement.Camera.Position, + Client.Self.Movement.Camera.AtAxis, Client.Self.Movement.Camera.LeftAxis, Client.Self.Movement.Camera.UpAxis, + Client.Self.Movement.BodyRotation, Client.Self.Movement.HeadRotation, Client.Self.Movement.Camera.Far, AgentFlags.None, + AgentState.None, true); + } + else + { + // Parse the number of seconds + int duration; + if (!Int32.TryParse(args[0], out duration)) + return "Usage: right [seconds]"; + // Convert to milliseconds + duration *= 1000; + + int start = Environment.TickCount; + + Client.Self.Movement.LeftNeg = true; + + while (Environment.TickCount - start < duration) + { + // The movement timer will do this automatically, but we do it here as an example + // and to make sure updates are being sent out fast enough + Client.Self.Movement.SendUpdate(false); + System.Threading.Thread.Sleep(100); + } + + Client.Self.Movement.LeftNeg = false; + } + + return "Moved right"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/SetHome.cs b/Programs/examples/TestClient/Commands/Movement/SetHome.cs new file mode 100644 index 0000000..76718ef --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/SetHome.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class SetHomeCommand : Command + { + public SetHomeCommand(TestClient testClient) + { + Name = "sethome"; + Description = "Sets home to the current location."; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Client.Self.SetHome(); + return "Home Set"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/SitCommand.cs b/Programs/examples/TestClient/Commands/Movement/SitCommand.cs new file mode 100644 index 0000000..cae0926 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/SitCommand.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class SitCommand: Command + { + public SitCommand(TestClient testClient) + { + Name = "sit"; + Description = "Attempt to sit on the closest prim"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Primitive closest = null; + double closestDistance = Double.MaxValue; + + Client.Network.CurrentSim.ObjectsPrimitives.ForEach( + delegate(Primitive prim) + { + float distance = Vector3.Distance(Client.Self.SimPosition, prim.Position); + + if (closest == null || distance < closestDistance) + { + closest = prim; + closestDistance = distance; + } + } + ); + + if (closest != null) + { + Client.Self.RequestSit(closest.ID, Vector3.Zero); + Client.Self.Sit(); + + return "Sat on " + closest.ID + " (" + closest.LocalID + "). Distance: " + closestDistance; + } + else + { + return "Couldn't find a nearby prim to sit on"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/SitOnCommand.cs b/Programs/examples/TestClient/Commands/Movement/SitOnCommand.cs new file mode 100644 index 0000000..452e21c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/SitOnCommand.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class SitOnCommand : Command + { + public SitOnCommand(TestClient testClient) + { + Name = "siton"; + Description = "Attempt to sit on a particular prim, with specified UUID"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: siton UUID"; + + UUID target; + + if (UUID.TryParse(args[0], out target)) + { + Primitive targetPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find( + delegate(Primitive prim) + { + return prim.ID == target; + } + ); + + if (targetPrim != null) + { + Client.Self.RequestSit(targetPrim.ID, Vector3.Zero); + Client.Self.Sit(); + return "Requested to sit on prim " + targetPrim.ID.ToString() + + " (" + targetPrim.LocalID + ")"; + } + } + + return "Couldn't find a prim to sit on with UUID " + args[0]; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/StandCommand.cs b/Programs/examples/TestClient/Commands/Movement/StandCommand.cs new file mode 100644 index 0000000..f96e52d --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/StandCommand.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class StandCommand: Command + { + public StandCommand(TestClient testClient) + { + Name = "stand"; + Description = "Stand"; + Category = CommandCategory.Movement; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Client.Self.Stand(); + return "Standing up."; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Movement/TurnToCommand.cs b/Programs/examples/TestClient/Commands/Movement/TurnToCommand.cs new file mode 100644 index 0000000..a0ae799 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Movement/TurnToCommand.cs @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006-2014, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +using System; +namespace OpenMetaverse.TestClient.Commands.Movement +{ + class TurnToCommand : Command + { + public TurnToCommand(TestClient client) + { + Name = "turnto"; + Description = "Turns the avatar looking to a specified point. Usage: turnto x y z"; + Category = CommandCategory.Movement; + } + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 3) + return "Usage: turnto x y z"; + double x, y, z; + if (!Double.TryParse(args[0], out x) || + !Double.TryParse(args[1], out y) || + !Double.TryParse(args[2], out z)) + { + return "Usage: turnto x y z"; + } + + Vector3 newDirection; + newDirection.X = (float)x; + newDirection.Y = (float)y; + newDirection.Z = (float)z; + Client.Self.Movement.TurnToward(newDirection); + Client.Self.Movement.SendUpdate(false); + return "Turned to "; + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Prims/ChangePermsCommand.cs b/Programs/examples/TestClient/Commands/Prims/ChangePermsCommand.cs new file mode 100644 index 0000000..490e024 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/ChangePermsCommand.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace OpenMetaverse.TestClient +{ + public class ChangePermsCommand : Command + { + AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false); + Dictionary Objects = new Dictionary(); + PermissionMask Perms = PermissionMask.None; + private bool PermsSent; + private int PermCount; + + public ChangePermsCommand(TestClient testClient) + { + testClient.Objects.ObjectProperties += new EventHandler(Objects_OnObjectProperties); + + Name = "changeperms"; + Description = "Recursively changes all of the permissions for child and task inventory objects. Usage prim-uuid [copy] [mod] [xfer]"; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + UUID rootID; + Primitive rootPrim; + List childPrims; + List localIDs = new List(); + + // Reset class-wide variables + PermsSent = false; + Objects.Clear(); + Perms = PermissionMask.None; + PermCount = 0; + + if (args.Length < 1 || args.Length > 4) + return "Usage prim-uuid [copy] [mod] [xfer]"; + + if (!UUID.TryParse(args[0], out rootID)) + return "Usage prim-uuid [copy] [mod] [xfer]"; + + for (int i = 1; i < args.Length; i++) + { + switch (args[i].ToLower()) + { + case "copy": + Perms |= PermissionMask.Copy; + break; + case "mod": + Perms |= PermissionMask.Modify; + break; + case "xfer": + Perms |= PermissionMask.Transfer; + break; + default: + return "Usage prim-uuid [copy] [mod] [xfer]"; + } + } + + Logger.DebugLog("Using PermissionMask: " + Perms.ToString(), Client); + + // Find the requested prim + rootPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find(delegate(Primitive prim) { return prim.ID == rootID; }); + if (rootPrim == null) + return "Cannot find requested prim " + rootID.ToString(); + else + Logger.DebugLog("Found requested prim " + rootPrim.ID.ToString(), Client); + + if (rootPrim.ParentID != 0) + { + // This is not actually a root prim, find the root + if (!Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(rootPrim.ParentID, out rootPrim)) + return "Cannot find root prim for requested object"; + else + Logger.DebugLog("Set root prim to " + rootPrim.ID.ToString(), Client); + } + + // Find all of the child objects linked to this root + childPrims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll(delegate(Primitive prim) { return prim.ParentID == rootPrim.LocalID; }); + + // Build a dictionary of primitives for referencing later + Objects[rootPrim.ID] = rootPrim; + for (int i = 0; i < childPrims.Count; i++) + Objects[childPrims[i].ID] = childPrims[i]; + + // Build a list of all the localIDs to set permissions for + localIDs.Add(rootPrim.LocalID); + for (int i = 0; i < childPrims.Count; i++) + localIDs.Add(childPrims[i].LocalID); + + // Go through each of the three main permissions and enable or disable them + #region Set Linkset Permissions + + PermCount = 0; + if ((Perms & PermissionMask.Modify) == PermissionMask.Modify) + Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Modify, true); + else + Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Modify, false); + PermsSent = true; + + if (!GotPermissionsEvent.WaitOne(1000 * 30, false)) + return "Failed to set the modify bit, permissions in an unknown state"; + + PermCount = 0; + if ((Perms & PermissionMask.Copy) == PermissionMask.Copy) + Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Copy, true); + else + Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Copy, false); + PermsSent = true; + + if (!GotPermissionsEvent.WaitOne(1000 * 30, false)) + return "Failed to set the copy bit, permissions in an unknown state"; + + PermCount = 0; + if ((Perms & PermissionMask.Transfer) == PermissionMask.Transfer) + Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Transfer, true); + else + Client.Objects.SetPermissions(Client.Network.CurrentSim, localIDs, PermissionWho.NextOwner, PermissionMask.Transfer, false); + PermsSent = true; + + if (!GotPermissionsEvent.WaitOne(1000 * 30, false)) + return "Failed to set the transfer bit, permissions in an unknown state"; + + #endregion Set Linkset Permissions + + // Check each prim for task inventory and set permissions on the task inventory + int taskItems = 0; + foreach (Primitive prim in Objects.Values) + { + if ((prim.Flags & PrimFlags.InventoryEmpty) == 0) + { + List items = Client.Inventory.GetTaskInventory(prim.ID, prim.LocalID, 1000 * 30); + + if (items != null) + { + for (int i = 0; i < items.Count; i++) + { + if (!(items[i] is InventoryFolder)) + { + InventoryItem item = (InventoryItem)items[i]; + item.Permissions.NextOwnerMask = Perms; + + Client.Inventory.UpdateTaskInventory(prim.LocalID, item); + ++taskItems; + } + } + } + } + } + + return "Set permissions to " + Perms.ToString() + " on " + localIDs.Count + " objects and " + taskItems + " inventory items"; + } + + void Objects_OnObjectProperties(object sender, ObjectPropertiesEventArgs e) + { + if (PermsSent) + { + if (Objects.ContainsKey(e.Properties.ObjectID)) + { + // FIXME: Confirm the current operation against properties.Permissions.NextOwnerMask + + ++PermCount; + if (PermCount >= Objects.Count) + GotPermissionsEvent.Set(); + } + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/DeRezObjectCommand.cs b/Programs/examples/TestClient/Commands/Prims/DeRezObjectCommand.cs new file mode 100644 index 0000000..a0ded0a --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/DeRezObjectCommand.cs @@ -0,0 +1,47 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class DeRezCommand : Command + { + public DeRezCommand(TestClient testClient) + { + Name = "derez"; + Description = "De-Rezes a specified prim. " + "Usage: derez [prim-uuid]"; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + UUID primID; + + if (args.Length != 1) + return "Usage: derez [prim-uuid]"; + + if (UUID.TryParse(args[0], out primID)) + { + Primitive target = Client.Network.CurrentSim.ObjectsPrimitives.Find( + delegate(Primitive prim) { return prim.ID == primID; } + ); + + if (target != null) + { + uint objectLocalID = target.LocalID; + Client.Inventory.RequestDeRezToInventory(objectLocalID, DeRezDestination.AgentInventoryTake, + Client.Inventory.FindFolderForType(AssetType.TrashFolder), + UUID.Random()); + return "removing " + target; + } + else + { + return "Could not find prim " + primID.ToString(); + } + } + else + { + return "Usage: derez [prim-uuid]"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs b/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs new file mode 100644 index 0000000..1d55e45 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs @@ -0,0 +1,90 @@ +using System; +using System.IO; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class DownloadTextureCommand : Command + { + UUID TextureID; + AutoResetEvent DownloadHandle = new AutoResetEvent(false); + AssetTexture Asset; + TextureRequestState resultState; + + public DownloadTextureCommand(TestClient testClient) + { + Name = "downloadtexture"; + Description = "Downloads the specified texture. " + + "Usage: downloadtexture [texture-uuid] [discardlevel]"; + Category = CommandCategory.Inventory; + + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1 && args.Length != 2) + return "Usage: downloadtexture [texture-uuid] [discardlevel]"; + + TextureID = UUID.Zero; + DownloadHandle.Reset(); + Asset = null; + + if (UUID.TryParse(args[0], out TextureID)) + { + int discardLevel = 0; + + if (args.Length > 1) + { + if (!Int32.TryParse(args[1], out discardLevel)) + return "Usage: downloadtexture [texture-uuid] [discardlevel]"; + } + + Client.Assets.RequestImage(TextureID, ImageType.Normal, Assets_OnImageReceived); + + if (DownloadHandle.WaitOne(120 * 1000, false)) + { + if (resultState == TextureRequestState.Finished) + { + if (Asset != null && Asset.Decode()) + { + try { File.WriteAllBytes(Asset.AssetID + ".jp2", Asset.AssetData); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + + return String.Format("Saved {0}.jp2 ({1}x{2})", Asset.AssetID, Asset.Image.Width, Asset.Image.Height); + } + else + { + return "Failed to decode texture " + TextureID.ToString(); + } + } + else if (resultState == TextureRequestState.NotFound) + { + return "Simulator reported texture not found: " + TextureID.ToString(); + } + else + { + return "Download failed for texture " + TextureID + " " + resultState; + } + } + else + { + return "Timed out waiting for texture download"; + } + } + else + { + return "Usage: downloadtexture [texture-uuid]"; + } + } + + private void Assets_OnImageReceived(TextureRequestState state, AssetTexture asset) + { + resultState = state; + Asset = asset; + + DownloadHandle.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs new file mode 100644 index 0000000..e5f3e72 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class ExportCommand : Command + { + List Textures = new List(); + AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false); + Primitive.ObjectProperties Properties; + bool GotPermissions = false; + UUID SelectedObject = UUID.Zero; + + Dictionary PrimsWaiting = new Dictionary(); + AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); + + public ExportCommand(TestClient testClient) + { + testClient.Objects.ObjectPropertiesFamily += new EventHandler(Objects_OnObjectPropertiesFamily); + + testClient.Objects.ObjectProperties += new EventHandler(Objects_OnObjectProperties); + testClient.Avatars.ViewerEffectPointAt += new EventHandler(Avatars_ViewerEffectPointAt); + + Name = "export"; + Description = "Exports an object to an xml file. Usage: export uuid outputfile.xml"; + Category = CommandCategory.Objects; + } + + void Avatars_ViewerEffectPointAt(object sender, ViewerEffectPointAtEventArgs e) + { + if (e.SourceID == Client.MasterKey) + { + //Client.DebugLog("Master is now selecting " + targetID.ToString()); + SelectedObject = e.TargetID; + } + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 2 && !(args.Length == 1 && SelectedObject != UUID.Zero)) + return "Usage: export uuid outputfile.xml"; + + UUID id; + uint localid; + string file; + + if (args.Length == 2) + { + file = args[1]; + if (!UUID.TryParse(args[0], out id)) + return "Usage: export uuid outputfile.xml"; + } + else + { + file = args[0]; + id = SelectedObject; + } + + Primitive exportPrim; + + exportPrim = Client.Network.CurrentSim.ObjectsPrimitives.Find( + delegate(Primitive prim) { return prim.ID == id; } + ); + + if (exportPrim != null) + { + if (exportPrim.ParentID != 0) + localid = exportPrim.ParentID; + else + localid = exportPrim.LocalID; + + // Check for export permission first + Client.Objects.RequestObjectPropertiesFamily(Client.Network.CurrentSim, id); + GotPermissionsEvent.WaitOne(1000 * 10, false); + + if (!GotPermissions) + { + return "Couldn't fetch permissions for the requested object, try again"; + } + else + { + GotPermissions = false; + if (Properties.OwnerID != Client.Self.AgentID && + Properties.OwnerID != Client.MasterKey && + Client.Self.AgentID != Client.Self.AgentID) + { + return "That object is owned by " + Properties.OwnerID + ", we don't have permission " + + "to export it"; + } + } + + List prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( + delegate(Primitive prim) + { + return (prim.LocalID == localid || prim.ParentID == localid); + } + ); + + bool complete = RequestObjectProperties(prims, 250); + + if (!complete) + { + Logger.Log("Warning: Unable to retrieve full properties for:", Helpers.LogLevel.Warning, Client); + foreach (UUID uuid in PrimsWaiting.Keys) + Logger.Log(uuid.ToString(), Helpers.LogLevel.Warning, Client); + } + + string output = OSDParser.SerializeLLSDXmlString(Helpers.PrimListToOSD(prims)); + try { File.WriteAllText(file, output); } + catch (Exception e) { return e.Message; } + + Logger.Log("Exported " + prims.Count + " prims to " + file, Helpers.LogLevel.Info, Client); + + // Create a list of all of the textures to download + List textureRequests = new List(); + + lock (Textures) + { + for (int i = 0; i < prims.Count; i++) + { + Primitive prim = prims[i]; + + if (prim.Textures.DefaultTexture.TextureID != Primitive.TextureEntry.WHITE_TEXTURE && + !Textures.Contains(prim.Textures.DefaultTexture.TextureID)) + { + Textures.Add(prim.Textures.DefaultTexture.TextureID); + } + + for (int j = 0; j < prim.Textures.FaceTextures.Length; j++) + { + if (prim.Textures.FaceTextures[j] != null && + prim.Textures.FaceTextures[j].TextureID != Primitive.TextureEntry.WHITE_TEXTURE && + !Textures.Contains(prim.Textures.FaceTextures[j].TextureID)) + { + Textures.Add(prim.Textures.FaceTextures[j].TextureID); + } + } + + if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero && !Textures.Contains(prim.Sculpt.SculptTexture)) + { + Textures.Add(prim.Sculpt.SculptTexture); + } + } + + // Create a request list from all of the images + for (int i = 0; i < Textures.Count; i++) + textureRequests.Add(new ImageRequest(Textures[i], ImageType.Normal, 1013000.0f, 0)); + } + + // Download all of the textures in the export list + foreach (ImageRequest request in textureRequests) + { + Client.Assets.RequestImage(request.ImageID, request.Type, Assets_OnImageReceived); + } + + return "XML exported, began downloading " + Textures.Count + " textures"; + } + else + { + return "Couldn't find UUID " + id.ToString() + " in the " + + Client.Network.CurrentSim.ObjectsPrimitives.Count + + "objects currently indexed in the current simulator"; + } + } + + private bool RequestObjectProperties(List objects, int msPerRequest) + { + // Create an array of the local IDs of all the prims we are requesting properties for + uint[] localids = new uint[objects.Count]; + + lock (PrimsWaiting) + { + PrimsWaiting.Clear(); + + for (int i = 0; i < objects.Count; ++i) + { + localids[i] = objects[i].LocalID; + PrimsWaiting.Add(objects[i].ID, objects[i]); + } + } + + Client.Objects.SelectObjects(Client.Network.CurrentSim, localids); + + return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false); + } + + private void Assets_OnImageReceived(TextureRequestState state, AssetTexture asset) + { + + if (state == TextureRequestState.Finished && Textures.Contains(asset.AssetID)) + { + lock (Textures) + Textures.Remove(asset.AssetID); + + if (state == TextureRequestState.Finished) + { + try { File.WriteAllBytes(asset.AssetID + ".jp2", asset.AssetData); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } + + if (asset.Decode()) + { + try { File.WriteAllBytes(asset.AssetID + ".tga", asset.Image.ExportTGA()); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } + } + else + { + Logger.Log("Failed to decode image " + asset.AssetID, Helpers.LogLevel.Error, Client); + } + + Logger.Log("Finished downloading image " + asset.AssetID, Helpers.LogLevel.Info, Client); + } + else + { + Logger.Log("Failed to download image " + asset.AssetID + ":" + state, Helpers.LogLevel.Warning, Client); + } + } + } + + void Objects_OnObjectPropertiesFamily(object sender, ObjectPropertiesFamilyEventArgs e) + { + Properties = new Primitive.ObjectProperties(); + Properties.SetFamilyProperties(e.Properties); + GotPermissions = true; + GotPermissionsEvent.Set(); + } + + void Objects_OnObjectProperties(object sender, ObjectPropertiesEventArgs e) + { + lock (PrimsWaiting) + { + PrimsWaiting.Remove(e.Properties.ObjectID); + + if (PrimsWaiting.Count == 0) + AllPropertiesReceived.Set(); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs b/Programs/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs new file mode 100644 index 0000000..68ea0ed --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/ExportParticlesCommand.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ExportParticlesCommand : Command + { + public ExportParticlesCommand(TestClient testClient) + { + Name = "exportparticles"; + Description = "Reverse engineers a prim with a particle system to an LSL script. Usage: exportscript [prim-uuid]"; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: exportparticles [prim-uuid]"; + + UUID id; + if (!UUID.TryParse(args[0], out id)) + return "Usage: exportparticles [prim-uuid]"; + + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Primitive exportPrim = Client.Network.Simulators[i].ObjectsPrimitives.Find( + delegate(Primitive prim) + { + return prim.ID == id; + } + ); + + if (exportPrim != null) + { + if (exportPrim.ParticleSys.CRC != 0) + { + StringBuilder lsl = new StringBuilder(); + + #region Particle System to LSL + + lsl.Append("default" + Environment.NewLine); + lsl.Append("{" + Environment.NewLine); + lsl.Append(" state_entry()" + Environment.NewLine); + lsl.Append(" {" + Environment.NewLine); + lsl.Append(" llParticleSystem([" + Environment.NewLine); + + lsl.Append(" PSYS_PART_FLAGS, 0"); + + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpColor) != 0) + lsl.Append(" | PSYS_PART_INTERP_COLOR_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.InterpScale) != 0) + lsl.Append(" | PSYS_PART_INTERP_SCALE_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Bounce) != 0) + lsl.Append(" | PSYS_PART_BOUNCE_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Wind) != 0) + lsl.Append(" | PSYS_PART_WIND_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowSrc) != 0) + lsl.Append(" | PSYS_PART_FOLLOW_SRC_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.FollowVelocity) != 0) + lsl.Append(" | PSYS_PART_FOLLOW_VELOCITY_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetPos) != 0) + lsl.Append(" | PSYS_PART_TARGET_POS_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.TargetLinear) != 0) + lsl.Append(" | PSYS_PART_TARGET_LINEAR_MASK"); + if ((exportPrim.ParticleSys.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.Emissive) != 0) + lsl.Append(" | PSYS_PART_EMISSIVE_MASK"); + + lsl.Append(","); lsl.Append(Environment.NewLine); + lsl.Append(" PSYS_SRC_PATTERN, 0"); + + if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Drop) != 0) + lsl.Append(" | PSYS_SRC_PATTERN_DROP"); + if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Explode) != 0) + lsl.Append(" | PSYS_SRC_PATTERN_EXPLODE"); + if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.Angle) != 0) + lsl.Append(" | PSYS_SRC_PATTERN_ANGLE"); + if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleCone) != 0) + lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE"); + if ((exportPrim.ParticleSys.Pattern & Primitive.ParticleSystem.SourcePattern.AngleConeEmpty) != 0) + lsl.Append(" | PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY"); + + lsl.Append("," + Environment.NewLine); + + lsl.Append(" PSYS_PART_START_ALPHA, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartColor.A) + "," + Environment.NewLine); + lsl.Append(" PSYS_PART_END_ALPHA, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndColor.A) + "," + Environment.NewLine); + lsl.Append(" PSYS_PART_START_COLOR, " + exportPrim.ParticleSys.PartStartColor.ToRGBString() + "," + Environment.NewLine); + lsl.Append(" PSYS_PART_END_COLOR, " + exportPrim.ParticleSys.PartEndColor.ToRGBString() + "," + Environment.NewLine); + lsl.Append(" PSYS_PART_START_SCALE, <" + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartScaleX) + ", " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartStartScaleY) + ", 0>, " + Environment.NewLine); + lsl.Append(" PSYS_PART_END_SCALE, <" + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndScaleX) + ", " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartEndScaleY) + ", 0>, " + Environment.NewLine); + lsl.Append(" PSYS_PART_MAX_AGE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.PartMaxAge) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_MAX_AGE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.MaxAge) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_ACCEL, " + exportPrim.ParticleSys.PartAcceleration.ToString() + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_BURST_PART_COUNT, " + String.Format("{0:0}", exportPrim.ParticleSys.BurstPartCount) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_BURST_RADIUS, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstRadius) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_BURST_RATE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstRate) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_BURST_SPEED_MIN, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstSpeedMin) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_BURST_SPEED_MAX, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.BurstSpeedMax) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_INNERANGLE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.InnerAngle) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_OUTERANGLE, " + String.Format("{0:0.00000}", exportPrim.ParticleSys.OuterAngle) + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_OMEGA, " + exportPrim.ParticleSys.AngularVelocity.ToString() + "," + Environment.NewLine); + lsl.Append(" PSYS_SRC_TEXTURE, (key)\"" + exportPrim.ParticleSys.Texture.ToString() + "\"," + Environment.NewLine); + lsl.Append(" PSYS_SRC_TARGET_KEY, (key)\"" + exportPrim.ParticleSys.Target.ToString() + "\"" + Environment.NewLine); + + lsl.Append(" ]);" + Environment.NewLine); + lsl.Append(" }" + Environment.NewLine); + lsl.Append("}" + Environment.NewLine); + + #endregion Particle System to LSL + + return lsl.ToString(); + } + else + { + return "Prim " + exportPrim.LocalID + " does not have a particle system"; + } + } + } + } + + return "Couldn't find prim " + id.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/FindObjectsCommand.cs b/Programs/examples/TestClient/Commands/Prims/FindObjectsCommand.cs new file mode 100644 index 0000000..90b75e2 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/FindObjectsCommand.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +using OpenMetaverse; + + +namespace OpenMetaverse.TestClient +{ + public class FindObjectsCommand : Command + { + Dictionary PrimsWaiting = new Dictionary(); + AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); + + public FindObjectsCommand(TestClient testClient) + { + testClient.Objects.ObjectProperties += new EventHandler(Objects_OnObjectProperties); + + Name = "findobjects"; + Description = "Finds all objects, which name contains search-string. " + + "Usage: findobjects [radius] "; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // *** parse arguments *** + if ((args.Length < 1) || (args.Length > 2)) + return "Usage: findobjects [radius] "; + float radius = float.Parse(args[0]); + string searchString = (args.Length > 1) ? args[1] : String.Empty; + + // *** get current location *** + Vector3 location = Client.Self.SimPosition; + + // *** find all objects in radius *** + List prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( + delegate(Primitive prim) + { + Vector3 pos = prim.Position; + return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius)); + } + ); + + // *** request properties of these objects *** + bool complete = RequestObjectProperties(prims, 250); + + foreach (Primitive p in prims) + { + string name = p.Properties != null ? p.Properties.Name : null; + if (String.IsNullOrEmpty(searchString) || ((name != null) && (name.Contains(searchString)))) + Console.WriteLine(String.Format("Object '{0}': {1}", name, p.ID.ToString())); + } + + if (!complete) + { + Console.WriteLine("Warning: Unable to retrieve full properties for:"); + foreach (UUID uuid in PrimsWaiting.Keys) + Console.WriteLine(uuid); + } + + return "Done searching"; + } + + private bool RequestObjectProperties(List objects, int msPerRequest) + { + // Create an array of the local IDs of all the prims we are requesting properties for + uint[] localids = new uint[objects.Count]; + + lock (PrimsWaiting) + { + PrimsWaiting.Clear(); + + for (int i = 0; i < objects.Count; ++i) + { + localids[i] = objects[i].LocalID; + PrimsWaiting.Add(objects[i].ID, objects[i]); + } + } + + Client.Objects.SelectObjects(Client.Network.CurrentSim, localids); + + return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false); + } + + void Objects_OnObjectProperties(object sender, ObjectPropertiesEventArgs e) + { + lock (PrimsWaiting) + { + Primitive prim; + if (PrimsWaiting.TryGetValue(e.Properties.ObjectID, out prim)) + { + prim.Properties = e.Properties; + } + PrimsWaiting.Remove(e.Properties.ObjectID); + + if (PrimsWaiting.Count == 0) + AllPropertiesReceived.Set(); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/FindTextureCommand.cs b/Programs/examples/TestClient/Commands/Prims/FindTextureCommand.cs new file mode 100644 index 0000000..e843f0c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/FindTextureCommand.cs @@ -0,0 +1,50 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class FindTextureCommand : Command + { + public FindTextureCommand(TestClient testClient) + { + Name = "findtexture"; + Description = "Checks if a specified texture is currently visible on a specified face. " + + "Usage: findtexture [face-index] [texture-uuid]"; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + int faceIndex; + UUID textureID; + + if (args.Length != 2) + return "Usage: findtexture [face-index] [texture-uuid]"; + + if (Int32.TryParse(args[0], out faceIndex) && + UUID.TryParse(args[1], out textureID)) + { + Client.Network.CurrentSim.ObjectsPrimitives.ForEach( + delegate(Primitive prim) + { + if (prim.Textures != null && prim.Textures.FaceTextures[faceIndex] != null) + { + if (prim.Textures.FaceTextures[faceIndex].TextureID == textureID) + { + Logger.Log(String.Format("Primitive {0} ({1}) has face index {2} set to {3}", + prim.ID.ToString(), prim.LocalID, faceIndex, textureID.ToString()), + Helpers.LogLevel.Info, Client); + } + } + } + ); + + return "Done searching"; + } + else + { + return "Usage: findtexture [face-index] [texture-uuid]"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/ImportCommand.cs b/Programs/examples/TestClient/Commands/Prims/ImportCommand.cs new file mode 100644 index 0000000..257b066 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/ImportCommand.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.IO; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.TestClient +{ + public class ImportCommand : Command + { + private enum ImporterState + { + RezzingParent, + RezzingChildren, + Linking, + Idle + } + + private class Linkset + { + public Primitive RootPrim; + public List Children = new List(); + + public Linkset() + { + RootPrim = new Primitive(); + } + + public Linkset(Primitive rootPrim) + { + RootPrim = rootPrim; + } + } + + Primitive currentPrim; + Vector3 currentPosition; + AutoResetEvent primDone = new AutoResetEvent(false); + List primsCreated; + List linkQueue; + uint rootLocalID; + ImporterState state = ImporterState.Idle; + + public ImportCommand(TestClient testClient) + { + Name = "import"; + Description = "Import prims from an exported xml file. Usage: import inputfile.xml [usegroup]"; + Category = CommandCategory.Objects; + + testClient.Objects.ObjectUpdate += Objects_OnNewPrim; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: import inputfile.xml [usegroup]"; + + string filename = args[0]; + UUID GroupID = (args.Length > 1) ? Client.GroupID : UUID.Zero; + string xml; + List prims; + + try { xml = File.ReadAllText(filename); } + catch (Exception e) { return e.Message; } + + try { prims = Helpers.OSDToPrimList(OSDParser.DeserializeLLSDXml(xml)); } + catch (Exception e) { return "Failed to deserialize " + filename + ": " + e.Message; } + + // Build an organized structure from the imported prims + Dictionary linksets = new Dictionary(); + for (int i = 0; i < prims.Count; i++) + { + Primitive prim = prims[i]; + + if (prim.ParentID == 0) + { + if (linksets.ContainsKey(prim.LocalID)) + linksets[prim.LocalID].RootPrim = prim; + else + linksets[prim.LocalID] = new Linkset(prim); + } + else + { + if (!linksets.ContainsKey(prim.ParentID)) + linksets[prim.ParentID] = new Linkset(); + + linksets[prim.ParentID].Children.Add(prim); + } + } + + primsCreated = new List(); + Console.WriteLine("Importing " + linksets.Count + " structures."); + + foreach (Linkset linkset in linksets.Values) + { + if (linkset.RootPrim.LocalID != 0) + { + state = ImporterState.RezzingParent; + currentPrim = linkset.RootPrim; + // HACK: Import the structure just above our head + // We need a more elaborate solution for importing with relative or absolute offsets + linkset.RootPrim.Position = Client.Self.SimPosition; + linkset.RootPrim.Position.Z += 3.0f; + currentPosition = linkset.RootPrim.Position; + + // Rez the root prim with no rotation + Quaternion rootRotation = linkset.RootPrim.Rotation; + linkset.RootPrim.Rotation = Quaternion.Identity; + + Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim.PrimData, GroupID, + linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation); + + if (!primDone.WaitOne(10000, false)) + return "Rez failed, timed out while creating the root prim."; + + Client.Objects.SetPosition(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, linkset.RootPrim.Position); + + state = ImporterState.RezzingChildren; + + // Rez the child prims + foreach (Primitive prim in linkset.Children) + { + currentPrim = prim; + currentPosition = prim.Position + linkset.RootPrim.Position; + + Client.Objects.AddPrim(Client.Network.CurrentSim, prim.PrimData, GroupID, currentPosition, + prim.Scale, prim.Rotation); + + if (!primDone.WaitOne(10000, false)) + return "Rez failed, timed out while creating child prim."; + Client.Objects.SetPosition(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, currentPosition); + + } + + // Create a list of the local IDs of the newly created prims + List primIDs = new List(primsCreated.Count); + primIDs.Add(rootLocalID); // Root prim is first in list. + + if (linkset.Children.Count != 0) + { + // Add the rest of the prims to the list of local IDs + foreach (Primitive prim in primsCreated) + { + if (prim.LocalID != rootLocalID) + primIDs.Add(prim.LocalID); + } + linkQueue = new List(primIDs.Count); + linkQueue.AddRange(primIDs); + + // Link and set the permissions + rotation + state = ImporterState.Linking; + Client.Objects.LinkPrims(Client.Network.CurrentSim, linkQueue); + + if (primDone.WaitOne(1000 * linkset.Children.Count, false)) + Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation); + else + Console.WriteLine("Warning: Failed to link {0} prims", linkQueue.Count); + + } + else + { + Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation); + } + + // Set permissions on newly created prims + Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs, + PermissionWho.Everyone | PermissionWho.Group | PermissionWho.NextOwner, + PermissionMask.All, true); + + state = ImporterState.Idle; + } + else + { + // Skip linksets with a missing root prim + Console.WriteLine("WARNING: Skipping a linkset with a missing root prim"); + } + + // Reset everything for the next linkset + primsCreated.Clear(); + } + + return "Import complete."; + } + + void Objects_OnNewPrim(object sender, PrimEventArgs e) + { + Primitive prim = e.Prim; + + if ((prim.Flags & PrimFlags.CreateSelected) == 0) + return; // We received an update for an object we didn't create + + switch (state) + { + case ImporterState.RezzingParent: + rootLocalID = prim.LocalID; + goto case ImporterState.RezzingChildren; + case ImporterState.RezzingChildren: + if (!primsCreated.Contains(prim)) + { + Console.WriteLine("Setting properties for " + prim.LocalID); + // TODO: Is there a way to set all of this at once, and update more ObjectProperties stuff? + Client.Objects.SetPosition(e.Simulator, prim.LocalID, currentPosition); + Client.Objects.SetTextures(e.Simulator, prim.LocalID, currentPrim.Textures); + + if (currentPrim.Light != null && currentPrim.Light.Intensity > 0) + { + Client.Objects.SetLight(e.Simulator, prim.LocalID, currentPrim.Light); + } + + if (currentPrim.Flexible != null) + { + Client.Objects.SetFlexible(e.Simulator, prim.LocalID, currentPrim.Flexible); + } + + if (currentPrim.Sculpt != null && currentPrim.Sculpt.SculptTexture != UUID.Zero) + { + Client.Objects.SetSculpt(e.Simulator, prim.LocalID, currentPrim.Sculpt); + } + + if (currentPrim.Properties!= null && !String.IsNullOrEmpty(currentPrim.Properties.Name)) + { + Client.Objects.SetName(e.Simulator, prim.LocalID, currentPrim.Properties.Name); + } + + if (currentPrim.Properties != null && !String.IsNullOrEmpty(currentPrim.Properties.Description)) + { + Client.Objects.SetDescription(e.Simulator, prim.LocalID, currentPrim.Properties.Description); + } + + primsCreated.Add(prim); + primDone.Set(); + } + break; + case ImporterState.Linking: + lock (linkQueue) + { + int index = linkQueue.IndexOf(prim.LocalID); + if (index != -1) + { + linkQueue.RemoveAt(index); + if (linkQueue.Count == 0) + primDone.Set(); + } + } + break; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/PrimCountCommand.cs b/Programs/examples/TestClient/Commands/Prims/PrimCountCommand.cs new file mode 100644 index 0000000..764e36d --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/PrimCountCommand.cs @@ -0,0 +1,37 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class PrimCountCommand: Command + { + public PrimCountCommand(TestClient testClient) + { + Name = "primcount"; + Description = "Shows the number of objects currently being tracked."; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + int count = 0; + + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + int avcount = Client.Network.Simulators[i].ObjectsAvatars.Count; + int primcount = Client.Network.Simulators[i].ObjectsPrimitives.Count; + + Console.WriteLine("{0} (Avatars: {1} Primitives: {2})", + Client.Network.Simulators[i].Name, avcount, primcount); + + count += avcount; + count += primcount; + } + } + + return "Tracking a total of " + count + " objects"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/PrimInfoCommand.cs b/Programs/examples/TestClient/Commands/Prims/PrimInfoCommand.cs new file mode 100644 index 0000000..675933d --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/PrimInfoCommand.cs @@ -0,0 +1,94 @@ +using System; +using System.Threading; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class PrimInfoCommand : Command + { + public PrimInfoCommand(TestClient testClient) + { + Name = "priminfo"; + Description = "Dumps information about a specified prim. " + "Usage: priminfo [prim-uuid]"; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + UUID primID; + + if (args.Length != 1) + return "Usage: priminfo [prim-uuid]"; + + if (UUID.TryParse(args[0], out primID)) + { + Primitive target = Client.Network.CurrentSim.ObjectsPrimitives.Find( + delegate(Primitive prim) { return prim.ID == primID; } + ); + + if (target != null) + { + if (target.Text != String.Empty) + { + Logger.Log("Text: " + target.Text, Helpers.LogLevel.Info, Client); + } + if(target.Light != null) + Logger.Log("Light: " + target.Light.ToString(), Helpers.LogLevel.Info, Client); + + if (target.ParticleSys.CRC != 0) + Logger.Log("Particles: " + target.ParticleSys.ToString(), Helpers.LogLevel.Info, Client); + + Logger.Log("TextureEntry:", Helpers.LogLevel.Info, Client); + if (target.Textures != null) + { + Logger.Log(String.Format("Default texure: {0}", + target.Textures.DefaultTexture.TextureID.ToString()), + Helpers.LogLevel.Info); + + for (int i = 0; i < target.Textures.FaceTextures.Length; i++) + { + if (target.Textures.FaceTextures[i] != null) + { + Logger.Log(String.Format("Face {0}: {1}", i, + target.Textures.FaceTextures[i].TextureID.ToString()), + Helpers.LogLevel.Info, Client); + } + } + } + else + { + Logger.Log("null", Helpers.LogLevel.Info, Client); + } + + AutoResetEvent propsEvent = new AutoResetEvent(false); + EventHandler propsCallback = + delegate(object sender, ObjectPropertiesEventArgs e) + { + Logger.Log(String.Format( + "Category: {0}\nFolderID: {1}\nFromTaskID: {2}\nInventorySerial: {3}\nItemID: {4}\nCreationDate: {5}", + e.Properties.Category, e.Properties.FolderID, e.Properties.FromTaskID, e.Properties.InventorySerial, + e.Properties.ItemID, e.Properties.CreationDate), Helpers.LogLevel.Info); + propsEvent.Set(); + }; + + Client.Objects.ObjectProperties += propsCallback; + + Client.Objects.SelectObject(Client.Network.CurrentSim, target.LocalID, true); + + propsEvent.WaitOne(1000 * 10, false); + Client.Objects.ObjectProperties -= propsCallback; + + return "Done."; + } + else + { + return "Could not find prim " + primID.ToString(); + } + } + else + { + return "Usage: priminfo [prim-uuid]"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/PrimRegexCommand.cs b/Programs/examples/TestClient/Commands/Prims/PrimRegexCommand.cs new file mode 100644 index 0000000..ec2386c --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/PrimRegexCommand.cs @@ -0,0 +1,76 @@ +using System; +using System.Text.RegularExpressions; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class PrimRegexCommand : Command + { + public PrimRegexCommand(TestClient testClient) + { + Name = "primregex"; + Description = "Find prim by text predicat. " + + "Usage: primregex [text predicat] (eg findprim .away.)"; + Category = CommandCategory.Objects; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: primregex [text predicat]"; + + try + { + // Build the predicat from the args list + string predicatPrim = string.Empty; + for (int i = 0; i < args.Length; i++) + predicatPrim += args[i] + " "; + predicatPrim = predicatPrim.TrimEnd(); + + // Build Regex + Regex regexPrimName = new Regex(predicatPrim.ToLower()); + + // Print result + Logger.Log(string.Format("Searching prim for [{0}] ({1} prims loaded in simulator)\n", predicatPrim, + Client.Network.CurrentSim.ObjectsPrimitives.Count), Helpers.LogLevel.Info, Client); + + Client.Network.CurrentSim.ObjectsPrimitives.ForEach( + delegate(Primitive prim) + { + bool match = false; + string name = "(unknown)"; + string description = "(unknown)"; + + + match = (prim.Text != null && regexPrimName.IsMatch(prim.Text.ToLower())); + + if (prim.Properties != null && !match) + { + match = regexPrimName.IsMatch(prim.Properties.Name.ToLower()); + if (!match) + match = regexPrimName.IsMatch(prim.Properties.Description.ToLower()); + } + + if (match) + { + if (prim.Properties != null) + { + name = prim.Properties.Name; + description = prim.Properties.Description; + } + Logger.Log(string.Format("\nNAME={0}\nID = {1}\nFLAGS = {2}\nTEXT = '{3}'\nDESC='{4}'", name, + prim.ID, prim.Flags.ToString(), prim.Text, description), Helpers.LogLevel.Info, Client); + } + } + ); + } + catch (System.Exception e) + { + Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); + return "Error searching"; + } + + return "Done searching"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs b/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs new file mode 100644 index 0000000..ffed393 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Assets; + +namespace OpenMetaverse.TestClient +{ + public class TexturesCommand : Command + { + Dictionary alreadyRequested = new Dictionary(); + bool enabled = false; + + public TexturesCommand(TestClient testClient) + { + enabled = testClient.ClientManager.GetTextures; + + Name = "textures"; + Description = "Turns automatic texture downloading on or off. Usage: textures [on/off]"; + Category = CommandCategory.Objects; + + testClient.Objects.ObjectUpdate += new EventHandler(Objects_OnNewPrim); + testClient.Objects.AvatarUpdate += Objects_OnNewAvatar; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: textures [on/off]"; + + if (args[0].ToLower() == "on") + { + Client.ClientManager.GetTextures = enabled = true; + return "Texture downloading is on"; + } + else if (args[0].ToLower() == "off") + { + Client.ClientManager.GetTextures = enabled = false; + return "Texture downloading is off"; + } + else + { + return "Usage: textures [on/off]"; + } + } + + void Objects_OnNewAvatar(object sender, AvatarUpdateEventArgs e) + { + Avatar avatar = e.Avatar; + if (enabled) + { + // Search this avatar for textures + for (int i = 0; i < avatar.Textures.FaceTextures.Length; i++) + { + Primitive.TextureEntryFace face = avatar.Textures.FaceTextures[i]; + + if (face != null) + { + if (!alreadyRequested.ContainsKey(face.TextureID)) + { + alreadyRequested[face.TextureID] = face.TextureID; + + // Determine if this is a baked outfit texture or a normal texture + ImageType type = ImageType.Normal; + AvatarTextureIndex index = (AvatarTextureIndex)i; + switch (index) + { + case AvatarTextureIndex.EyesBaked: + case AvatarTextureIndex.HeadBaked: + case AvatarTextureIndex.LowerBaked: + case AvatarTextureIndex.SkirtBaked: + case AvatarTextureIndex.UpperBaked: + type = ImageType.Baked; + break; + } + + Client.Assets.RequestImage(face.TextureID, type, Assets_OnImageReceived); + } + } + } + } + } + + void Objects_OnNewPrim(object sender, PrimEventArgs e) + { + Primitive prim = e.Prim; + + if (enabled) + { + // Search this prim for textures + for (int i = 0; i < prim.Textures.FaceTextures.Length; i++) + { + Primitive.TextureEntryFace face = prim.Textures.FaceTextures[i]; + + if (face != null) + { + if (!alreadyRequested.ContainsKey(face.TextureID)) + { + alreadyRequested[face.TextureID] = face.TextureID; + Client.Assets.RequestImage(face.TextureID, ImageType.Normal, Assets_OnImageReceived); + } + } + } + } + } + + private void Assets_OnImageReceived(TextureRequestState state, AssetTexture asset) + { + if (state == TextureRequestState.Finished && enabled && alreadyRequested.ContainsKey(asset.AssetID)) + { + if (state == TextureRequestState.Finished) + Logger.DebugLog(String.Format("Finished downloading texture {0} ({1} bytes)", asset.AssetID, asset.AssetData.Length)); + else + Logger.Log("Failed to download texture " + asset.AssetID + ": " + state, Helpers.LogLevel.Warning); + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/Stats/DilationCommand.cs b/Programs/examples/TestClient/Commands/Stats/DilationCommand.cs new file mode 100644 index 0000000..08ad4d4 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Stats/DilationCommand.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class DilationCommand : Command + { + public DilationCommand(TestClient testClient) + { + Name = "dilation"; + Description = "Shows time dilation for current sim."; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + return "Dilation is " + Client.Network.CurrentSim.Stats.Dilation.ToString(); + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/Stats/NetstatsCommand.cs b/Programs/examples/TestClient/Commands/Stats/NetstatsCommand.cs new file mode 100644 index 0000000..f111e7a --- /dev/null +++ b/Programs/examples/TestClient/Commands/Stats/NetstatsCommand.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class NetstatsCommand : Command + { + public NetstatsCommand(TestClient testClient) + { + Name = "netstats"; + Description = "Provide packet and capabilities utilization statistics"; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + StringBuilder output = new StringBuilder(); + if (!Client.Settings.TRACK_UTILIZATION) + { + return "TRACK_UTILIZATION is not enabled in Settings, statistics not available"; + } + + + StringBuilder packetOutput = new StringBuilder(); + StringBuilder capsOutput = new StringBuilder(); + + packetOutput.AppendFormat("{0,-30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, "Packet Name", "Sent", "Recv", + " TX Bytes ", " RX Bytes "); + + capsOutput.AppendFormat("{0,-30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, "Message Name", "Sent", "Recv", + " TX Bytes ", " RX Bytes "); + // " RX " + + long packetsSentCount = 0; + long packetsRecvCount = 0; + long packetBytesSent = 0; + long packetBytesRecv = 0; + + long capsSentCount = 0; + long capsRecvCount = 0; + long capsBytesSent = 0; + long capsBytesRecv = 0; + + foreach (KeyValuePair kvp in Client.Stats.GetStatistics()) + { + if (kvp.Value.Type == OpenMetaverse.Stats.Type.Message) + { + capsOutput.AppendFormat("{0,-30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, kvp.Key, kvp.Value.TxCount, kvp.Value.RxCount, + FormatBytes(kvp.Value.TxBytes), FormatBytes(kvp.Value.RxBytes)); + + capsSentCount += kvp.Value.TxCount; + capsRecvCount += kvp.Value.RxCount; + capsBytesSent += kvp.Value.TxBytes; + capsBytesRecv += kvp.Value.RxBytes; + } + else if (kvp.Value.Type == OpenMetaverse.Stats.Type.Packet) + { + packetOutput.AppendFormat("{0,-30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, kvp.Key, kvp.Value.TxCount, kvp.Value.RxCount, + FormatBytes(kvp.Value.TxBytes), FormatBytes(kvp.Value.RxBytes)); + + packetsSentCount += kvp.Value.TxCount; + packetsRecvCount += kvp.Value.RxCount; + packetBytesSent += kvp.Value.TxBytes; + packetBytesRecv += kvp.Value.RxBytes; + } + } + + capsOutput.AppendFormat("{0,30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, "Capabilities Totals", capsSentCount, capsRecvCount, + FormatBytes(capsBytesSent), FormatBytes(capsBytesRecv)); + + packetOutput.AppendFormat("{0,30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, "Packet Totals", packetsSentCount, packetsRecvCount, + FormatBytes(packetBytesSent), FormatBytes(packetBytesRecv)); + + return System.Environment.NewLine + capsOutput.ToString() + System.Environment.NewLine + System.Environment.NewLine + packetOutput.ToString(); + } + + public string FormatBytes(long bytes) + { + const int scale = 1024; + string[] orders = new string[] { "GB", "MB", "KB", "Bytes" }; + long max = (long)Math.Pow(scale, orders.Length - 1); + + foreach (string order in orders) + { + if ( bytes > max ) + return string.Format("{0:##.##} {1}", decimal.Divide( bytes, max ), order); + + max /= scale; + } + return "0"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Stats/RegionInfoCommand.cs b/Programs/examples/TestClient/Commands/Stats/RegionInfoCommand.cs new file mode 100644 index 0000000..1184f10 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Stats/RegionInfoCommand.cs @@ -0,0 +1,59 @@ +using System; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class RegionInfoCommand : Command + { + public RegionInfoCommand(TestClient testClient) + { + Name = "regioninfo"; + Description = "Prints out info about all the current region"; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + StringBuilder output = new StringBuilder(); + output.AppendLine(Client.Network.CurrentSim.ToString()); + output.Append("UUID: "); + output.AppendLine(Client.Network.CurrentSim.ID.ToString()); + uint x, y; + Utils.LongToUInts(Client.Network.CurrentSim.Handle, out x, out y); + output.AppendLine(String.Format("Handle: {0} (X: {1} Y: {2})", Client.Network.CurrentSim.Handle, x, y)); + output.Append("Access: "); + output.AppendLine(Client.Network.CurrentSim.Access.ToString()); + output.Append("Flags: "); + output.AppendLine(Client.Network.CurrentSim.Flags.ToString()); + output.Append("TerrainBase0: "); + output.AppendLine(Client.Network.CurrentSim.TerrainBase0.ToString()); + output.Append("TerrainBase1: "); + output.AppendLine(Client.Network.CurrentSim.TerrainBase1.ToString()); + output.Append("TerrainBase2: "); + output.AppendLine(Client.Network.CurrentSim.TerrainBase2.ToString()); + output.Append("TerrainBase3: "); + output.AppendLine(Client.Network.CurrentSim.TerrainBase3.ToString()); + output.Append("TerrainDetail0: "); + output.AppendLine(Client.Network.CurrentSim.TerrainDetail0.ToString()); + output.Append("TerrainDetail1: "); + output.AppendLine(Client.Network.CurrentSim.TerrainDetail1.ToString()); + output.Append("TerrainDetail2: "); + output.AppendLine(Client.Network.CurrentSim.TerrainDetail2.ToString()); + output.Append("TerrainDetail3: "); + output.AppendLine(Client.Network.CurrentSim.TerrainDetail3.ToString()); + output.Append("Water Height: "); + output.AppendLine(Client.Network.CurrentSim.WaterHeight.ToString()); + output.Append("Datacenter:"); + output.AppendLine(Client.Network.CurrentSim.ColoLocation); + output.Append("CPU Ratio:"); + output.AppendLine(Client.Network.CurrentSim.CPURatio.ToString()); + output.Append("CPU Class:"); + output.AppendLine(Client.Network.CurrentSim.CPUClass.ToString()); + output.Append("Region SKU/Type:"); + output.AppendLine(Client.Network.CurrentSim.ProductSku + " " + Client.Network.CurrentSim.ProductName); + + return output.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Stats/StatsCommand.cs b/Programs/examples/TestClient/Commands/Stats/StatsCommand.cs new file mode 100644 index 0000000..d999d44 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Stats/StatsCommand.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class StatsCommand : Command + { + public StatsCommand(TestClient testClient) + { + Name = "stats"; + Description = "Provide connection figures and statistics"; + Category = CommandCategory.Simulator; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + StringBuilder output = new StringBuilder(); + + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Simulator sim = Client.Network.Simulators[i]; + + output.AppendLine(String.Format( + "[{0}] Dilation: {1} InBPS: {2} OutBPS: {3} ResentOut: {4} ResentIn: {5}", + sim.ToString(), sim.Stats.Dilation, sim.Stats.IncomingBPS, sim.Stats.OutgoingBPS, + sim.Stats.ResentPackets, sim.Stats.ReceivedResends)); + } + } + + Simulator csim = Client.Network.CurrentSim; + + output.Append("Packets in the queue: " + Client.Network.InboxCount); + output.AppendLine(String.Format("FPS : {0} PhysicsFPS : {1} AgentUpdates : {2} Objects : {3} Scripted Objects : {4}", + csim.Stats.FPS, csim.Stats.PhysicsFPS, csim.Stats.AgentUpdates, csim.Stats.Objects, csim.Stats.ScriptedObjects)); + output.AppendLine(String.Format("Frame Time : {0} Net Time : {1} Image Time : {2} Physics Time : {3} Script Time : {4} Other Time : {5}", + csim.Stats.FrameTime, csim.Stats.NetTime, csim.Stats.ImageTime, csim.Stats.PhysicsTime, csim.Stats.ScriptTime, csim.Stats.OtherTime)); + output.AppendLine(String.Format("Agents : {0} Child Agents : {1} Active Scripts : {2}", + csim.Stats.Agents, csim.Stats.ChildAgents, csim.Stats.ActiveScripts)); + + return output.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Stats/UptimeCommand.cs b/Programs/examples/TestClient/Commands/Stats/UptimeCommand.cs new file mode 100644 index 0000000..10724fb --- /dev/null +++ b/Programs/examples/TestClient/Commands/Stats/UptimeCommand.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class UptimeCommand : Command + { + public DateTime Created = DateTime.Now; + + public UptimeCommand(TestClient testClient) + { + Name = "uptime"; + Description = "Shows the login name, login time and length of time logged on."; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + string name = Client.ToString(); + return "I am " + name + ", Up Since: " + Created + " (" + (DateTime.Now - Created) + ")"; + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/System/AtCommand.cs b/Programs/examples/TestClient/Commands/System/AtCommand.cs new file mode 100644 index 0000000..5258ddd --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/AtCommand.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class AtCommand : Command + { + public AtCommand(TestClient testClient) + { + Name = "@"; + Description = "Restrict the following commands to one or all avatars. Usage: @ [firstname lastname]"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // This is a dummy command. Calls to it should be intercepted and handled specially + return "This command should not be executed directly"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/DebugCommand.cs b/Programs/examples/TestClient/Commands/System/DebugCommand.cs new file mode 100644 index 0000000..850a130 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/DebugCommand.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class DebugCommand : Command + { + public DebugCommand(TestClient testClient) + { + Name = "debug"; + Description = "Turn debug messages on or off. Usage: debug [level] where level is one of None, Debug, Error, Info, Warn"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 1) + return "Usage: debug [level] where level is one of None, Debug, Error, Info, Warn"; + + if (args[0].ToLower() == "debug") + { + Settings.LOG_LEVEL = Helpers.LogLevel.Debug; + return "Logging is set to Debug"; + } + else if (args[0].ToLower() == "none") + { + Settings.LOG_LEVEL = Helpers.LogLevel.None; + return "Logging is set to None"; + } + else if (args[0].ToLower() == "warn") + { + Settings.LOG_LEVEL = Helpers.LogLevel.Warning; + return "Logging is set to level Warning"; + } + else if (args[0].ToLower() == "info") + { + Settings.LOG_LEVEL = Helpers.LogLevel.Info; + return "Logging is set to level Info"; + } + else if (args[0].ToLower() == "error") + { + Settings.LOG_LEVEL = Helpers.LogLevel.Error; + return "Logging is set to level Error"; + } + else + { + return "Usage: debug [level] where level is one of None, Debug, Error, Info, Warn"; + } + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/HelpCommand.cs b/Programs/examples/TestClient/Commands/System/HelpCommand.cs new file mode 100644 index 0000000..669b9e7 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/HelpCommand.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class HelpCommand: Command + { + public HelpCommand(TestClient testClient) + { + Name = "help"; + Description = "Lists available commands. usage: help [command] to display information on commands"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length > 0) + { + if (Client.Commands.ContainsKey(args[0])) + return Client.Commands[args[0]].Description; + else + return "Command " + args[0] + " Does not exist. \"help\" to display all available commands."; + } + StringBuilder result = new StringBuilder(); + SortedDictionary> CommandTree = new SortedDictionary>(); + + CommandCategory cc; + foreach (Command c in Client.Commands.Values) + { + if (c.Category.Equals(null)) + cc = CommandCategory.Unknown; + else + cc = c.Category; + + if (CommandTree.ContainsKey(cc)) + CommandTree[cc].Add(c); + else + { + List l = new List(); + l.Add(c); + CommandTree.Add(cc, l); + } + } + + foreach (KeyValuePair> kvp in CommandTree) + { + result.AppendFormat(System.Environment.NewLine + "* {0} Related Commands:" + System.Environment.NewLine, kvp.Key.ToString()); + int colMax = 0; + for (int i = 0; i < kvp.Value.Count; i++) + { + if (colMax >= 120) + { + result.AppendLine(); + colMax = 0; + } + + result.AppendFormat(" {0,-15}", kvp.Value[i].Name); + colMax += 15; + } + result.AppendLine(); + } + result.AppendLine(System.Environment.NewLine + "Help [command] for usage/information"); + + return result.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/LoadCommand.cs b/Programs/examples/TestClient/Commands/System/LoadCommand.cs new file mode 100644 index 0000000..b8e096c --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/LoadCommand.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class LoadCommand: Command + { + public LoadCommand(TestClient testClient) + { + Name = "load"; + Description = "Loads commands from a dll. (Usage: load AssemblyNameWithoutExtension)"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: load AssemblyNameWithoutExtension"; + + string filename = AppDomain.CurrentDomain.BaseDirectory + args[0] + ".dll"; + Client.RegisterAllCommands(Assembly.LoadFile(filename)); + return "Assembly " + filename + " loaded."; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/LogPacketCommand.cs b/Programs/examples/TestClient/Commands/System/LogPacketCommand.cs new file mode 100644 index 0000000..1226f0e --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/LogPacketCommand.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class PacketLogCommand : Command + { + private TestClient m_client; + private bool m_isLogging; + private int m_packetsToLogRemaining; + private StreamWriter m_logStreamWriter; + + public PacketLogCommand(TestClient testClient) + { + Name = "logpacket"; + Description = "Logs a given number of packets to a file. For example, packetlog 10 tenpackets.xml"; + Category = CommandCategory.TestClient; + + m_client = testClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length != 2) + return string.Format("Usage: {0} no-of-packets filename", Name); + + string rawNumberOfPackets = args[0]; + string path = args[1]; + int numberOfPackets; + + if (!int.TryParse(args[0], out numberOfPackets) || numberOfPackets <= 0) + return string.Format( + "{0} is not a valid number of packets for {1}", rawNumberOfPackets, m_client.Self.Name); + + lock (this) + { + if (m_isLogging) + return string.Format( + "Still waiting to finish logging {0} packets for {1}", + m_packetsToLogRemaining, m_client.Self.Name); + + try + { + m_logStreamWriter = new StreamWriter(path); + } + catch (Exception e) + { + return string.Format("Could not open file with path [{0}], exception {1}", path, e); + } + + m_isLogging = true; + } + + m_packetsToLogRemaining = numberOfPackets; + m_client.Network.RegisterCallback(PacketType.Default, HandlePacket); + return string.Format("Now logging {0} packets for {1}", m_packetsToLogRemaining, m_client.Self.Name); + } + + /// + /// Logs the packet received for this client. + /// + /// + /// This handler assumes that packets are processed one at a time. + /// + /// Sender. + /// Arguments. + private void HandlePacket(object sender, PacketReceivedEventArgs args) + { +// Console.WriteLine( +// "Received packet {0} from {1} for {2}", args.Packet.Type, args.Simulator.Name, m_client.Self.Name); + + lock (this) + { + if (!m_isLogging) + return; + + m_logStreamWriter.WriteLine("Received: {0}", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff")); + + try + { + m_logStreamWriter.WriteLine(PacketDecoder.PacketToString(args.Packet)); + } + catch (Exception e) + { + m_logStreamWriter.WriteLine("Failed to write decode of {0}, exception {1}", args.Packet.Type, e); + } + + if (--m_packetsToLogRemaining <= 0) + { + m_client.Network.UnregisterCallback(PacketType.Default, HandlePacket); + m_logStreamWriter.Close(); + Console.WriteLine("Finished logging packets for {0}", m_client.Self.Name); + m_isLogging = false; + } + } + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Commands/System/LoginCommand.cs b/Programs/examples/TestClient/Commands/System/LoginCommand.cs new file mode 100644 index 0000000..4a0253e --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/LoginCommand.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class LoginCommand : Command + { + public LoginCommand(TestClient testClient) + { + Name = "login"; + Description = "Logs in another avatar. Usage: login firstname lastname password [simname] [loginuri]"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // This is a dummy command. Calls to it should be intercepted and handled specially + return "This command should not be executed directly"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/LogoutCommand.cs b/Programs/examples/TestClient/Commands/System/LogoutCommand.cs new file mode 100644 index 0000000..aad2e96 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/LogoutCommand.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class LogoutCommand : Command + { + public LogoutCommand(TestClient testClient) + { + Name = "logout"; + Description = "Log this avatar out"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + string name = Client.ToString(); + Client.ClientManager.Logout(Client); + return "Logged " + name + " out"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/MD5Command.cs b/Programs/examples/TestClient/Commands/System/MD5Command.cs new file mode 100644 index 0000000..ed4aa37 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/MD5Command.cs @@ -0,0 +1,23 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class MD5Command : Command + { + public MD5Command(TestClient testClient) + { + Name = "md5"; + Description = "Creates an MD5 hash from a given password. Usage: md5 [password]"; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length == 1) + return Utils.MD5(args[0]); + else + return "Usage: md5 [password]"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/QuitCommand.cs b/Programs/examples/TestClient/Commands/System/QuitCommand.cs new file mode 100644 index 0000000..c6b30d8 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/QuitCommand.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class QuitCommand: Command + { + public QuitCommand(TestClient testClient) + { + Name = "quit"; + Description = "Log all avatars out and shut down"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + // This is a dummy command. Calls to it should be intercepted and handled specially + return "This command should not be executed directly"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/SetMasterCommand.cs b/Programs/examples/TestClient/Commands/System/SetMasterCommand.cs new file mode 100644 index 0000000..c5dd082 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/SetMasterCommand.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class SetMasterCommand: Command + { + public DateTime Created = DateTime.Now; + private UUID resolvedMasterKey = UUID.Zero; + private ManualResetEvent keyResolution = new ManualResetEvent(false); + private UUID query = UUID.Zero; + + public SetMasterCommand(TestClient testClient) + { + Name = "setmaster"; + Description = "Sets the user name of the master user. The master user can IM to run commands. Usage: setmaster [name]"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + string masterName = String.Empty; + for (int ct = 0; ct < args.Length;ct++) + masterName = masterName + args[ct] + " "; + masterName = masterName.TrimEnd(); + + if (masterName.Length == 0) + return "Usage: setmaster [name]"; + + EventHandler callback = KeyResolvHandler; + Client.Directory.DirPeopleReply += callback; + + query = Client.Directory.StartPeopleSearch(masterName, 0); + + if (keyResolution.WaitOne(TimeSpan.FromMinutes(1), false)) + { + Client.MasterKey = resolvedMasterKey; + keyResolution.Reset(); + Client.Directory.DirPeopleReply -= callback; + } + else + { + keyResolution.Reset(); + Client.Directory.DirPeopleReply -= callback; + return "Unable to obtain UUID for \"" + masterName + "\". Master unchanged."; + } + + // Send an Online-only IM to the new master + Client.Self.InstantMessage( + Client.MasterKey, "You are now my master. IM me with \"help\" for a command list."); + + return String.Format("Master set to {0} ({1})", masterName, Client.MasterKey.ToString()); + } + + private void KeyResolvHandler(object sender, DirPeopleReplyEventArgs e) + { + if (query != e.QueryID) + return; + + resolvedMasterKey = e.MatchedPeople[0].AgentID; + keyResolution.Set(); + query = UUID.Zero; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/SetMasterKeyCommand.cs b/Programs/examples/TestClient/Commands/System/SetMasterKeyCommand.cs new file mode 100644 index 0000000..38064a2 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/SetMasterKeyCommand.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class SetMasterKeyCommand : Command + { + public DateTime Created = DateTime.Now; + + public SetMasterKeyCommand(TestClient testClient) + { + Name = "setMasterKey"; + Description = "Sets the key of the master user. The master user can IM to run commands."; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + Client.MasterKey = UUID.Parse(args[0]); + + lock (Client.Network.Simulators) + { + for (int i = 0; i < Client.Network.Simulators.Count; i++) + { + Avatar master = Client.Network.Simulators[i].ObjectsAvatars.Find( + delegate(Avatar avatar) + { + return avatar.ID == Client.MasterKey; + } + ); + + if (master != null) + { + Client.Self.InstantMessage(master.ID, + "You are now my master. IM me with \"help\" for a command list."); + break; + } + } + } + + return "Master set to " + Client.MasterKey.ToString(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/ShowEffectsCommand.cs b/Programs/examples/TestClient/Commands/System/ShowEffectsCommand.cs new file mode 100644 index 0000000..0c68a3a --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/ShowEffectsCommand.cs @@ -0,0 +1,75 @@ +using System; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class ShowEffectsCommand : Command + { + bool ShowEffects = false; + + public ShowEffectsCommand(TestClient testClient) + { + Name = "showeffects"; + Description = "Prints out information for every viewer effect that is received. Usage: showeffects [on/off]"; + Category = CommandCategory.Other; + + testClient.Avatars.ViewerEffect += new EventHandler(Avatars_ViewerEffect); + testClient.Avatars.ViewerEffectPointAt += new EventHandler(Avatars_ViewerEffectPointAt); + testClient.Avatars.ViewerEffectLookAt += new EventHandler(Avatars_ViewerEffectLookAt); + } + + void Avatars_ViewerEffectLookAt(object sender, ViewerEffectLookAtEventArgs e) + { + if (ShowEffects) + Console.WriteLine( + "ViewerEffect [LookAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}", + e.SourceID.ToString(), e.TargetID.ToString(), e.TargetPosition, e.LookType, e.Duration, + e.EffectID.ToString()); + } + + void Avatars_ViewerEffectPointAt(object sender, ViewerEffectPointAtEventArgs e) + { + if (ShowEffects) + Console.WriteLine( + "ViewerEffect [PointAt]: SourceID: {0} TargetID: {1} TargetPos: {2} Type: {3} Duration: {4} ID: {5}", + e.SourceID.ToString(), e.TargetID.ToString(), e.TargetPosition, e.PointType, e.Duration, + e.EffectID.ToString()); + } + + void Avatars_ViewerEffect(object sender, ViewerEffectEventArgs e) + { + if (ShowEffects) + Console.WriteLine( + "ViewerEffect [{0}]: SourceID: {1} TargetID: {2} TargetPos: {3} Duration: {4} ID: {5}", + e.Type, e.SourceID.ToString(), e.TargetID.ToString(), e.TargetPosition, e.Duration, + e.EffectID.ToString()); + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length == 0) + { + ShowEffects = true; + return "Viewer effects will be shown on the console"; + } + else if (args.Length == 1) + { + if (args[0] == "on") + { + ShowEffects = true; + return "Viewer effects will be shown on the console"; + } + else + { + ShowEffects = false; + return "Viewer effects will not be shown"; + } + } + else + { + return "Usage: showeffects [on/off]"; + } + } + + } +} diff --git a/Programs/examples/TestClient/Commands/System/SleepCommand.cs b/Programs/examples/TestClient/Commands/System/SleepCommand.cs new file mode 100644 index 0000000..eea20ca --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/SleepCommand.cs @@ -0,0 +1,44 @@ +using System; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class SleepCommand : Command + { + uint sleepSerialNum = 1; + + public SleepCommand(TestClient testClient) + { + Name = "sleep"; + Description = "Uses AgentPause/AgentResume and sleeps for a given number of seconds. Usage: sleep [seconds]"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + int seconds; + if (args.Length != 1 || !Int32.TryParse(args[0], out seconds)) + return "Usage: sleep [seconds]"; + + AgentPausePacket pause = new AgentPausePacket(); + pause.AgentData.AgentID = Client.Self.AgentID; + pause.AgentData.SessionID = Client.Self.SessionID; + pause.AgentData.SerialNum = sleepSerialNum++; + + Client.Network.SendPacket(pause); + + // Sleep + System.Threading.Thread.Sleep(seconds * 1000); + + AgentResumePacket resume = new AgentResumePacket(); + resume.AgentData.AgentID = Client.Self.AgentID; + resume.AgentData.SessionID = Client.Self.SessionID; + resume.AgentData.SerialNum = pause.AgentData.SerialNum; + + Client.Network.SendPacket(resume); + + return "Paused, slept for " + seconds + " second(s), and resumed"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/System/WaitForLoginCommand.cs b/Programs/examples/TestClient/Commands/System/WaitForLoginCommand.cs new file mode 100644 index 0000000..d33c4b0 --- /dev/null +++ b/Programs/examples/TestClient/Commands/System/WaitForLoginCommand.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.TestClient +{ + public class WaitForLoginCommand : Command + { + public WaitForLoginCommand(TestClient testClient) + { + Name = "waitforlogin"; + Description = "Waits until all bots that are currently attempting to login have succeeded or failed"; + Category = CommandCategory.TestClient; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + while (ClientManager.Instance.PendingLogins > 0) + { + System.Threading.Thread.Sleep(1000); + Logger.Log("Pending logins: " + ClientManager.Instance.PendingLogins, Helpers.LogLevel.Info); + } + + return "All pending logins have completed, currently tracking " + ClientManager.Instance.Clients.Count + " bots"; + } + } +} diff --git a/Programs/examples/TestClient/Commands/Voice/ParcelVoiceInfo.cs b/Programs/examples/TestClient/Commands/Voice/ParcelVoiceInfo.cs new file mode 100644 index 0000000..5701108 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Voice/ParcelVoiceInfo.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class ParcelVoiceInfoCommand : Command + { + private AutoResetEvent ParcelVoiceInfoEvent = new AutoResetEvent(false); + private string VoiceRegionName = null; + private int VoiceLocalID = -1; + private string VoiceChannelURI = null; + + public ParcelVoiceInfoCommand(TestClient testClient) + { + Name = "voiceparcel"; + Description = "obtain parcel voice info. Usage: voiceparcel"; + Category = CommandCategory.Other; + + Client = testClient; + } + + private bool registered = false; + + private bool IsVoiceManagerRunning() + { + if (null == Client.VoiceManager) return false; + + if (!registered) + { + Client.VoiceManager.OnParcelVoiceInfo += Voice_OnParcelVoiceInfo; + registered = true; + } + return true; + } + + + public override string Execute(string[] args, UUID fromAgentID) + { + if (!IsVoiceManagerRunning()) + return String.Format("VoiceManager not running for {0}", fromAgentID); + + if (!Client.VoiceManager.RequestParcelVoiceInfo()) + { + return "RequestParcelVoiceInfo failed. Not available for the current grid?"; + } + ParcelVoiceInfoEvent.WaitOne(30 * 1000, false); + + if (String.IsNullOrEmpty(VoiceRegionName) && -1 == VoiceLocalID) + { + return String.Format("Parcel Voice Info request for {0} failed.", Client.Self.Name); + } + + return String.Format("Parcel Voice Info request for {0}: region name \"{1}\", parcel local id {2}, channel URI {3}", + Client.Self.Name, VoiceRegionName, VoiceLocalID, VoiceChannelURI); + } + + void Voice_OnParcelVoiceInfo(string regionName, int localID, string channelURI) + { + VoiceRegionName = regionName; + VoiceLocalID = localID; + VoiceChannelURI = channelURI; + + ParcelVoiceInfoEvent.Set(); + } + } +} diff --git a/Programs/examples/TestClient/Commands/Voice/VoiceAcountCommand.cs b/Programs/examples/TestClient/Commands/Voice/VoiceAcountCommand.cs new file mode 100644 index 0000000..4c62b5b --- /dev/null +++ b/Programs/examples/TestClient/Commands/Voice/VoiceAcountCommand.cs @@ -0,0 +1,67 @@ + +using System; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Packets; + +namespace OpenMetaverse.TestClient +{ + public class VoiceAccountCommand : Command + { + private AutoResetEvent ProvisionEvent = new AutoResetEvent(false); + private string VoiceAccount = null; + private string VoicePassword = null; + + public VoiceAccountCommand(TestClient testClient) + { + Name = "voiceaccount"; + Description = "obtain voice account info. Usage: voiceaccount"; + Category = CommandCategory.Voice; + + Client = testClient; + } + + private bool registered = false; + + private bool IsVoiceManagerRunning() + { + if (null == Client.VoiceManager) return false; + + if (!registered) + { + Client.VoiceManager.OnProvisionAccount += Voice_OnProvisionAccount; + registered = true; + } + return true; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (!IsVoiceManagerRunning()) + return String.Format("VoiceManager not running for {0}", Client.Self.Name); + + if (!Client.VoiceManager.RequestProvisionAccount()) + { + return "RequestProvisionAccount failed. Not available for the current grid?"; + } + ProvisionEvent.WaitOne(30 * 1000, false); + + if (String.IsNullOrEmpty(VoiceAccount) && String.IsNullOrEmpty(VoicePassword)) + { + return String.Format("Voice account information lookup for {0} failed.", Client.Self.Name); + } + + return String.Format("Voice Account for {0}: user \"{1}\", password \"{2}\"", + Client.Self.Name, VoiceAccount, VoicePassword); + } + + void Voice_OnProvisionAccount(string username, string password) + { + VoiceAccount = username; + VoicePassword = password; + + ProvisionEvent.Set(); + } + } +} \ No newline at end of file diff --git a/Programs/examples/TestClient/Parsing.cs b/Programs/examples/TestClient/Parsing.cs new file mode 100644 index 0000000..b5b7f06 --- /dev/null +++ b/Programs/examples/TestClient/Parsing.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient +{ + class Parsing + { + public static string[] ParseArguments(string str) + { + List list = new List(); + string current = String.Empty; + string trimmed = null; + bool withinQuote = false; + bool escaped = false; + + foreach (char c in str) + { + if (c == '"') + { + if (escaped) + { + current += '"'; + escaped = false; + } + else + { + current += '"'; + withinQuote = !withinQuote; + } + } + else if (c == ' ' || c == '\t') + { + if (escaped || withinQuote) + { + current += c; + escaped = false; + } + else + { + trimmed = current.Trim(); + if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) + { + trimmed = trimmed.Remove(0, 1); + trimmed = trimmed.Remove(trimmed.Length - 1); + trimmed = trimmed.Trim(); + } + if (trimmed.Length > 0) + list.Add(trimmed); + current = String.Empty; + } + } + else if (c == '\\') + { + if (escaped) + { + current += '\\'; + escaped = false; + } + else + { + escaped = true; + } + } + else + { + if (escaped) + throw new FormatException(c.ToString() + " is not an escapable character."); + current += c; + } + } + + trimmed = current.Trim(); + + if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) + { + trimmed = trimmed.Remove(0, 1); + trimmed = trimmed.Remove(trimmed.Length - 1); + trimmed = trimmed.Trim(); + } + + if (trimmed.Length > 0) + list.Add(trimmed); + + return list.ToArray(); + } + } +} diff --git a/Programs/examples/TestClient/Program.cs b/Programs/examples/TestClient/Program.cs new file mode 100644 index 0000000..d15133e --- /dev/null +++ b/Programs/examples/TestClient/Program.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.IO; +using CommandLine.Utility; + +namespace OpenMetaverse.TestClient +{ + public class CommandLineArgumentsException : Exception + { + } + + public class Program + { + public static string LoginURI; + + private static void Usage() + { + Console.WriteLine("Usage: " + Environment.NewLine + + "TestClient.exe [--first firstname --last lastname --pass password] [--file userlist.txt] [--loginuri=\"uri\"] [--startpos \"sim/x/y/z\"] [--master \"master name\"] [--masterkey \"master uuid\"] [--gettextures] [--scriptfile \"filename\"]"); + } + + static void Main(string[] args) + { + Arguments arguments = new Arguments(args); + + List accounts = new List(); + LoginDetails account; + bool groupCommands = false; + string masterName = String.Empty; + UUID masterKey = UUID.Zero; + string file = String.Empty; + bool getTextures = false; + bool noGUI = false; // true if to not prompt for input + string scriptFile = String.Empty; + + if (arguments["groupcommands"] != null) + groupCommands = true; + + if (arguments["masterkey"] != null) + masterKey = UUID.Parse(arguments["masterkey"]); + + if (arguments["master"] != null) + masterName = arguments["master"]; + + if (arguments["loginuri"] != null) + LoginURI = arguments["loginuri"]; + if (String.IsNullOrEmpty(LoginURI)) + LoginURI = Settings.AGNI_LOGIN_SERVER; + Logger.Log("Using login URI " + LoginURI, Helpers.LogLevel.Info); + + if (arguments["gettextures"] != null) + getTextures = true; + + if (arguments["nogui"] != null) + noGUI = true; + + if (arguments["scriptfile"] != null) + { + scriptFile = arguments["scriptfile"]; + if (!File.Exists(scriptFile)) + { + Logger.Log(String.Format("File {0} Does not exist", scriptFile), Helpers.LogLevel.Error); + return; + } + } + + if (arguments["file"] != null) + { + file = arguments["file"]; + + if (!File.Exists(file)) + { + Logger.Log(String.Format("File {0} Does not exist", file), Helpers.LogLevel.Error); + return; + } + + // Loading names from a file + try + { + using (StreamReader reader = new StreamReader(file)) + { + string line; + int lineNumber = 0; + + while ((line = reader.ReadLine()) != null) + { + lineNumber++; + string[] tokens = line.Trim().Split(new char[] { ' ', ',' }); + + if (tokens.Length >= 3) + { + account = new LoginDetails(); + account.FirstName = tokens[0]; + account.LastName = tokens[1]; + account.Password = tokens[2]; + + if (tokens.Length >= 4) // Optional starting position + { + char sep = '/'; + string[] startbits = tokens[3].Split(sep); + account.StartLocation = NetworkManager.StartLocation(startbits[0], Int32.Parse(startbits[1]), + Int32.Parse(startbits[2]), Int32.Parse(startbits[3])); + } + + accounts.Add(account); + } + else + { + Logger.Log("Invalid data on line " + lineNumber + + ", must be in the format of: FirstName LastName Password [Sim/StartX/StartY/StartZ]", + Helpers.LogLevel.Warning); + } + } + } + } + catch (Exception ex) + { + Logger.Log("Error reading from " + args[1], Helpers.LogLevel.Error, ex); + return; + } + } + else if (arguments["first"] != null && arguments["last"] != null && arguments["pass"] != null) + { + // Taking a single login off the command-line + account = new LoginDetails(); + account.FirstName = arguments["first"]; + account.LastName = arguments["last"]; + account.Password = arguments["pass"]; + + accounts.Add(account); + } + else if (arguments["help"] != null) + { + Usage(); + return; + } + + foreach (LoginDetails a in accounts) + { + a.GroupCommands = groupCommands; + a.MasterName = masterName; + a.MasterKey = masterKey; + a.URI = LoginURI; + + if (arguments["startpos"] != null) + { + char sep = '/'; + string[] startbits = arguments["startpos"].Split(sep); + a.StartLocation = NetworkManager.StartLocation(startbits[0], Int32.Parse(startbits[1]), + Int32.Parse(startbits[2]), Int32.Parse(startbits[3])); + } + } + + // Login the accounts and run the input loop + ClientManager.Instance.Start(accounts, getTextures); + + if (!String.IsNullOrEmpty(scriptFile)) + ClientManager.Instance.DoCommandAll("script " + scriptFile, UUID.Zero); + + // Then Run the ClientManager normally + ClientManager.Instance.Run(noGUI); + } + } +} diff --git a/Programs/examples/TestClient/Properties/AssemblyInfo.cs b/Programs/examples/TestClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..471a306 --- /dev/null +++ b/Programs/examples/TestClient/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestClient")] +[assembly: AssemblyCopyright("Copyright © 2006")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0563f706-7fa9-42f6-bf23-c6acd1175964")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Programs/examples/TestClient/TestClient.cs b/Programs/examples/TestClient/TestClient.cs new file mode 100644 index 0000000..abce396 --- /dev/null +++ b/Programs/examples/TestClient/TestClient.cs @@ -0,0 +1,272 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Reflection; +using System.Xml; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.Utilities; + +namespace OpenMetaverse.TestClient +{ + public class TestClient : GridClient + { + public UUID GroupID = UUID.Zero; + public Dictionary GroupMembers; + public Dictionary Appearances = new Dictionary(); + public Dictionary Commands = new Dictionary(); + public bool Running = true; + public bool GroupCommands = false; + public string MasterName = String.Empty; + public UUID MasterKey = UUID.Zero; + public bool AllowObjectMaster = false; + public ClientManager ClientManager; + public VoiceManager VoiceManager; + // Shell-like inventory commands need to be aware of the 'current' inventory folder. + public InventoryFolder CurrentDirectory = null; + + private System.Timers.Timer updateTimer; + private UUID GroupMembersRequestID; + public Dictionary GroupsCache = null; + private ManualResetEvent GroupsEvent = new ManualResetEvent(false); + + /// + /// + /// + public TestClient(ClientManager manager) + { + ClientManager = manager; + + updateTimer = new System.Timers.Timer(500); + updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed); + + RegisterAllCommands(Assembly.GetExecutingAssembly()); + + Settings.LOG_LEVEL = Helpers.LogLevel.Debug; + Settings.LOG_RESENDS = false; + Settings.STORE_LAND_PATCHES = true; + Settings.ALWAYS_DECODE_OBJECTS = true; + Settings.ALWAYS_REQUEST_OBJECTS = true; + Settings.SEND_AGENT_UPDATES = true; + Settings.USE_ASSET_CACHE = true; + + Network.RegisterCallback(PacketType.AgentDataUpdate, AgentDataUpdateHandler); + Network.LoginProgress += LoginHandler; + Objects.AvatarUpdate += new EventHandler(Objects_AvatarUpdate); + Objects.TerseObjectUpdate += new EventHandler(Objects_TerseObjectUpdate); + Network.SimChanged += new EventHandler(Network_SimChanged); + Self.IM += Self_IM; + Groups.GroupMembersReply += GroupMembersHandler; + Inventory.InventoryObjectOffered += Inventory_OnInventoryObjectReceived; + + Network.RegisterCallback(PacketType.AvatarAppearance, AvatarAppearanceHandler); + Network.RegisterCallback(PacketType.AlertMessage, AlertMessageHandler); + + VoiceManager = new VoiceManager(this); + + updateTimer.Start(); + } + + void Objects_TerseObjectUpdate(object sender, TerseObjectUpdateEventArgs e) + { + if (e.Prim.LocalID == Self.LocalID) + { + SetDefaultCamera(); + } + } + + void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e) + { + if (e.Avatar.LocalID == Self.LocalID) + { + SetDefaultCamera(); + } + } + + void Network_SimChanged(object sender, SimChangedEventArgs e) + { + Self.Movement.SetFOVVerticalAngle(Utils.TWO_PI - 0.05f); + } + + public void SetDefaultCamera() + { + // SetCamera 5m behind the avatar + Self.Movement.Camera.LookAt( + Self.SimPosition + new Vector3(-5, 0, 0) * Self.Movement.BodyRotation, + Self.SimPosition + ); + } + + + void Self_IM(object sender, InstantMessageEventArgs e) + { + bool groupIM = e.IM.GroupIM && GroupMembers != null && GroupMembers.ContainsKey(e.IM.FromAgentID) ? true : false; + + if (e.IM.FromAgentID == MasterKey || (GroupCommands && groupIM)) + { + // Received an IM from someone that is authenticated + Console.WriteLine("<{0} ({1})> {2}: {3} (@{4}:{5})", e.IM.GroupIM ? "GroupIM" : "IM", e.IM.Dialog, e.IM.FromAgentName, e.IM.Message, + e.IM.RegionID, e.IM.Position); + + if (e.IM.Dialog == InstantMessageDialog.RequestTeleport) + { + Console.WriteLine("Accepting teleport lure."); + Self.TeleportLureRespond(e.IM.FromAgentID, e.IM.IMSessionID, true); + } + else if ( + e.IM.Dialog == InstantMessageDialog.MessageFromAgent || + e.IM.Dialog == InstantMessageDialog.MessageFromObject) + { + ClientManager.Instance.DoCommandAll(e.IM.Message, e.IM.FromAgentID); + } + } + else + { + // Received an IM from someone that is not the bot's master, ignore + Console.WriteLine("<{0} ({1})> {2} (not master): {3} (@{4}:{5})", e.IM.GroupIM ? "GroupIM" : "IM", e.IM.Dialog, e.IM.FromAgentName, e.IM.Message, + e.IM.RegionID, e.IM.Position); + return; + } + } + + /// + /// Initialize everything that needs to be initialized once we're logged in. + /// + /// The status of the login + /// Error message on failure, MOTD on success. + public void LoginHandler(object sender, LoginProgressEventArgs e) + { + if (e.Status == LoginStatus.Success) + { + // Start in the inventory root folder. + CurrentDirectory = Inventory.Store.RootFolder; + } + } + + public void RegisterAllCommands(Assembly assembly) + { + foreach (Type t in assembly.GetTypes()) + { + try + { + if (t.IsSubclassOf(typeof(Command))) + { + ConstructorInfo info = t.GetConstructor(new Type[] { typeof(TestClient) }); + Command command = (Command)info.Invoke(new object[] { this }); + RegisterCommand(command); + } + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + } + } + + public void RegisterCommand(Command command) + { + command.Client = this; + if (!Commands.ContainsKey(command.Name.ToLower())) + { + Commands.Add(command.Name.ToLower(), command); + } + } + + public void ReloadGroupsCache() + { + Groups.CurrentGroups += Groups_CurrentGroups; + Groups.RequestCurrentGroups(); + GroupsEvent.WaitOne(10000, false); + Groups.CurrentGroups -= Groups_CurrentGroups; + GroupsEvent.Reset(); + } + + void Groups_CurrentGroups(object sender, CurrentGroupsEventArgs e) + { + if (null == GroupsCache) + GroupsCache = e.Groups; + else + lock (GroupsCache) { GroupsCache = e.Groups; } + GroupsEvent.Set(); + } + + public UUID GroupName2UUID(String groupName) + { + UUID tryUUID; + if (UUID.TryParse(groupName,out tryUUID)) + return tryUUID; + if (null == GroupsCache) { + ReloadGroupsCache(); + if (null == GroupsCache) + return UUID.Zero; + } + lock(GroupsCache) { + if (GroupsCache.Count > 0) { + foreach (Group currentGroup in GroupsCache.Values) + if (currentGroup.Name.ToLower() == groupName.ToLower()) + return currentGroup.ID; + } + } + return UUID.Zero; + } + + private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + foreach (Command c in Commands.Values) + if (c.Active) + c.Think(); + } + + private void AgentDataUpdateHandler(object sender, PacketReceivedEventArgs e) + { + AgentDataUpdatePacket p = (AgentDataUpdatePacket)e.Packet; + if (p.AgentData.AgentID == e.Simulator.Client.Self.AgentID && p.AgentData.ActiveGroupID != UUID.Zero) + { + GroupID = p.AgentData.ActiveGroupID; + + GroupMembersRequestID = e.Simulator.Client.Groups.RequestGroupMembers(GroupID); + } + } + + private void GroupMembersHandler(object sender, GroupMembersReplyEventArgs e) + { + if (e.RequestID != GroupMembersRequestID) return; + + GroupMembers = e.Members; + } + + private void AvatarAppearanceHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet; + + lock (Appearances) Appearances[appearance.Sender.ID] = appearance; + } + + private void AlertMessageHandler(object sender, PacketReceivedEventArgs e) + { + Packet packet = e.Packet; + + AlertMessagePacket message = (AlertMessagePacket)packet; + + Logger.Log("[AlertMessage] " + Utils.BytesToString(message.AlertData.Message), Helpers.LogLevel.Info, this); + } + + private void Inventory_OnInventoryObjectReceived(object sender, InventoryObjectOfferedEventArgs e) + { + if (MasterKey != UUID.Zero) + { + if (e.Offer.FromAgentID != MasterKey) + return; + } + else if (GroupMembers != null && !GroupMembers.ContainsKey(e.Offer.FromAgentID)) + { + return; + } + + e.Accept = true; + return; + } + } +} diff --git a/Programs/examples/TestClient/TestClient.exe.build b/Programs/examples/TestClient/TestClient.exe.build new file mode 100644 index 0000000..1020b9b --- /dev/null +++ b/Programs/examples/TestClient/TestClient.exe.build @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Programs/examples/TestClient/TestClient.mdp b/Programs/examples/TestClient/TestClient.mdp new file mode 100644 index 0000000..74aabfb --- /dev/null +++ b/Programs/examples/TestClient/TestClient.mdp @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/README.txt b/data/README.txt new file mode 100644 index 0000000..ba25eaa --- /dev/null +++ b/data/README.txt @@ -0,0 +1,4 @@ +message_template.msg differes from the official Linden Lab viewer source code. + +When updating from the official viewer, copy the file over, and than apply +patches in *.patch files. diff --git a/data/ca-bundle.crt b/data/ca-bundle.crt new file mode 100644 index 0000000..1eba867 --- /dev/null +++ b/data/ca-bundle.crt @@ -0,0 +1,4371 @@ +## +## $Id: ca-bundle.crt,v 1.2 2003/03/24 11:06:57 bagder Exp $ +## +## ca-bundle.crt -- Bundle of CA Root Certificates +## Last Modified: Thu Mar 2 09:32:46 CET 2000 +## +## This is a bundle of X.509 certificates of public +## Certificate Authorities (CA). These were automatically +## extracted from Netscape Communicator 4.72's certificate database +## (the file `cert7.db'). It contains the certificates in both +## plain text and PEM format and therefore can be directly used +## with an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## (SKIPME) +## + +ABAecom (sub., Am. Bankers Assn.) Root CA +========================================= +MD5 Fingerprint: 82:12:F7:89:E1:0B:91:60:A4:B6:22:9F:94:68:11:92 +PEM Data: +-----BEGIN CERTIFICATE----- +MIID+DCCAuCgAwIBAgIRANAeQJAAACdLAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw +gYwxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFoMRcwFQYDVQQHEw5TYWx0IExh +a2UgQ2l0eTEYMBYGA1UEChMPWGNlcnQgRVogYnkgRFNUMRgwFgYDVQQDEw9YY2Vy +dCBFWiBieSBEU1QxITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAe +Fw05OTA3MTQxNjE0MThaFw0wOTA3MTExNjE0MThaMIGMMQswCQYDVQQGEwJVUzEN +MAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxGDAWBgNVBAoT +D1hjZXJ0IEVaIGJ5IERTVDEYMBYGA1UEAxMPWGNlcnQgRVogYnkgRFNUMSEwHwYJ +KoZIhvcNAQkBFhJjYUBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCtVBjetL/3reh0qu2LfI/C1HUa1YS5tmL8ie/kl2GS+x24 +4VpHNJ6eBiL70+o4y7iLB/caoBd3B1owHNQpOCDXJ0DYUJNDv9IYoil2BXKqa7Zp +mKt5Hhxl9WqL/MUWqqJy2mDtTm4ZJXoKHTDjUJtCPETrobAgHtsCfv49H7/QAIrb +QHamGKUVp1e2UsIBF5h3j4qBxhq0airmr6nWAKzP2BVJfNsbof6B+of505DBAsD5 +0ELpkWglX8a/hznplQBgKL+DLMDnXrbXNhbnYId26OcnsiUNi3rlqh3lWc3OCw5v +xsic4xDZhTnTt5v6xrp8dNJddVardKSiUb9SfO5xAgMBAAGjUzBRMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAUCCBsZuuBCmxc1bWmPEHdHJaRJ3cwHQYDVR0O +BBYEFAggbGbrgQpsXNW1pjxB3RyWkSd3MA0GCSqGSIb3DQEBBQUAA4IBAQBah1iP +Lat2IWtUDNnxQfZOzSue4x+boy1/2St9WMhnpCn16ezVvZY/o3P4xFs2fNBjLDQ5 +m0i4PW/2FMWeY+anNG7T6DOzxzwYbiOuQ5KZP5jFaTDxNjutuTCC1rZZFpYCCykS +YbQRifcML5SQhZgonFNsfmPdc/QZ/0qB0bJSI/08SjTOWhvgUIrtT4GV2GDn5MQN +u1g+WPdOaG8+Z8nLepcWJ+xCYRR2uwDF6wg9FX9LtiJdhzuQ9PPA/jez6dliDMDD +Wa9gvR8N26E0HzDEPYutsB0Ek+1f1eS/IDAE9EjpMwHRLpAnUrOb3jocq6mXf5vr +wo3CbezcE9NGxXl8 +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: + d0:1e:40:90:00:00:27:4b:00:00:00:01:00:00:00:04 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, ST=Utah, L=Salt Lake City, O=Xcert EZ by DST, CN=Xcert EZ by DST/Email=ca@digsigtrust.com + Validity + Not Before: Jul 14 16:14:18 1999 GMT + Not After : Jul 11 16:14:18 2009 GMT + Subject: C=US, ST=Utah, L=Salt Lake City, O=Xcert EZ by DST, CN=Xcert EZ by DST/Email=ca@digsigtrust.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ad:54:18:de:b4:bf:f7:ad:e8:74:aa:ed:8b:7c: + 8f:c2:d4:75:1a:d5:84:b9:b6:62:fc:89:ef:e4:97: + 61:92:fb:1d:b8:e1:5a:47:34:9e:9e:06:22:fb:d3: + ea:38:cb:b8:8b:07:f7:1a:a0:17:77:07:5a:30:1c: + d4:29:38:20:d7:27:40:d8:50:93:43:bf:d2:18:a2: + 29:76:05:72:aa:6b:b6:69:98:ab:79:1e:1c:65:f5: + 6a:8b:fc:c5:16:aa:a2:72:da:60:ed:4e:6e:19:25: + 7a:0a:1d:30:e3:50:9b:42:3c:44:eb:a1:b0:20:1e: + db:02:7e:fe:3d:1f:bf:d0:00:8a:db:40:76:a6:18: + a5:15:a7:57:b6:52:c2:01:17:98:77:8f:8a:81:c6: + 1a:b4:6a:2a:e6:af:a9:d6:00:ac:cf:d8:15:49:7c: + db:1b:a1:fe:81:fa:87:f9:d3:90:c1:02:c0:f9:d0: + 42:e9:91:68:25:5f:c6:bf:87:39:e9:95:00:60:28: + bf:83:2c:c0:e7:5e:b6:d7:36:16:e7:60:87:76:e8: + e7:27:b2:25:0d:8b:7a:e5:aa:1d:e5:59:cd:ce:0b: + 0e:6f:c6:c8:9c:e3:10:d9:85:39:d3:b7:9b:fa:c6: + ba:7c:74:d2:5d:75:56:ab:74:a4:a2:51:bf:52:7c: + ee:71 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:08:20:6C:66:EB:81:0A:6C:5C:D5:B5:A6:3C:41:DD:1C:96:91:27:77 + + X509v3 Subject Key Identifier: + 08:20:6C:66:EB:81:0A:6C:5C:D5:B5:A6:3C:41:DD:1C:96:91:27:77 + Signature Algorithm: sha1WithRSAEncryption + 5a:87:58:8f:2d:ab:76:21:6b:54:0c:d9:f1:41:f6:4e:cd:2b: + 9e:e3:1f:9b:a3:2d:7f:d9:2b:7d:58:c8:67:a4:29:f5:e9:ec: + d5:bd:96:3f:a3:73:f8:c4:5b:36:7c:d0:63:2c:34:39:9b:48: + b8:3d:6f:f6:14:c5:9e:63:e6:a7:34:6e:d3:e8:33:b3:c7:3c: + 18:6e:23:ae:43:92:99:3f:98:c5:69:30:f1:36:3b:ad:b9:30: + 82:d6:b6:59:16:96:02:0b:29:12:61:b4:11:89:f7:0c:2f:94: + 90:85:98:28:9c:53:6c:7e:63:dd:73:f4:19:ff:4a:81:d1:b2: + 52:23:fd:3c:4a:34:ce:5a:1b:e0:50:8a:ed:4f:81:95:d8:60: + e7:e4:c4:0d:bb:58:3e:58:f7:4e:68:6f:3e:67:c9:cb:7a:97: + 16:27:ec:42:61:14:76:bb:00:c5:eb:08:3d:15:7f:4b:b6:22: + 5d:87:3b:90:f4:f3:c0:fe:37:b3:e9:d9:62:0c:c0:c3:59:af: + 60:bd:1f:0d:db:a1:34:1f:30:c4:3d:8b:ad:b0:1d:04:93:ed: + 5f:d5:e4:bf:20:30:04:f4:48:e9:33:01:d1:2e:90:27:52:b3: + 9b:de:3a:1c:ab:a9:97:7f:9b:eb:c2:8d:c2:6d:ec:dc:13:d3: + 46:c5:79:7c + +ANX Network CA by DST +===================== +MD5 Fingerprint: A8:ED:DE:EB:93:88:66:D8:2F:C3:BD:1D:BE:45:BE:4D +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDTTCCAragAwIBAgIENm6ibzANBgkqhkiG9w0BAQUFADBSMQswCQYDVQQGEwJV +UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMR0wGwYDVQQL +ExREU1QgKEFOWCBOZXR3b3JrKSBDQTAeFw05ODEyMDkxNTQ2NDhaFw0xODEyMDkx +NjE2NDhaMFIxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy +ZSBUcnVzdCBDby4xHTAbBgNVBAsTFERTVCAoQU5YIE5ldHdvcmspIENBMIGdMA0G +CSqGSIb3DQEBAQUAA4GLADCBhwKBgQC0SBGAWKDVpZkP9jcsRLZu0XzzKmueEbaI +IwRccSWeahJ3EW6/aDllqPay9qIYsokVoGe3eowiSGv2hDQftsr3G3LL8ltI04ce +InYTBLSsbJZ/5w4IyTJRMC3VgOghZ7rzXggkLAdZnZAa7kbJtaQelrRBkdR/0o04 +JrBvQ24JfQIBA6OCATAwggEsMBEGCWCGSAGG+EIBAQQEAwIABzB0BgNVHR8EbTBr +MGmgZ6BlpGMwYTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjEdMBsGA1UECxMURFNUIChBTlggTmV0d29yaykgQ0ExDTAL +BgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxNTQ2NDhagQ8yMDE4MTIw +OTE1NDY0OFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIwWVXDMFgpTZMKlhKqz +ZBdDP4I2MB0GA1UdDgQWBBSMFlVwzBYKU2TCpYSqs2QXQz+CNjAMBgNVHRMEBTAD +AQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +AEklyWCxDF+pORDTxTRVfc95wynr3vnCQPnoVsXwL+z02exIUbhjOF6TbhiWhbnK +UJykuOpmJmiThW9vTHHQvnoLPDG5975pnhDX0UDorBZxq66rOOFwscqSFuBdhaYY +gAYAnOGmGEJRp2hoWe8mlF+tMQz+KR4XAYQ3W+gSMqNd +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 913220207 (0x366ea26f) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Digital Signature Trust Co., OU=DST (ANX Network) CA + Validity + Not Before: Dec 9 15:46:48 1998 GMT + Not After : Dec 9 16:16:48 2018 GMT + Subject: C=US, O=Digital Signature Trust Co., OU=DST (ANX Network) CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b4:48:11:80:58:a0:d5:a5:99:0f:f6:37:2c:44: + b6:6e:d1:7c:f3:2a:6b:9e:11:b6:88:23:04:5c:71: + 25:9e:6a:12:77:11:6e:bf:68:39:65:a8:f6:b2:f6: + a2:18:b2:89:15:a0:67:b7:7a:8c:22:48:6b:f6:84: + 34:1f:b6:ca:f7:1b:72:cb:f2:5b:48:d3:87:1e:22: + 76:13:04:b4:ac:6c:96:7f:e7:0e:08:c9:32:51:30: + 2d:d5:80:e8:21:67:ba:f3:5e:08:24:2c:07:59:9d: + 90:1a:ee:46:c9:b5:a4:1e:96:b4:41:91:d4:7f:d2: + 8d:38:26:b0:6f:43:6e:09:7d + Exponent: 3 (0x3) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 CRL Distribution Points: + DirName:/C=US/O=Digital Signature Trust Co./OU=DST (ANX Network) CA/CN=CRL1 + + X509v3 Private Key Usage Period: + Not Before: Dec 9 15:46:48 1998 GMT, Not After: Dec 9 15:46:48 2018 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:8C:16:55:70:CC:16:0A:53:64:C2:A5:84:AA:B3:64:17:43:3F:82:36 + + X509v3 Subject Key Identifier: + 8C:16:55:70:CC:16:0A:53:64:C2:A5:84:AA:B3:64:17:43:3F:82:36 + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0 +..V4.0.... + Signature Algorithm: sha1WithRSAEncryption + 49:25:c9:60:b1:0c:5f:a9:39:10:d3:c5:34:55:7d:cf:79:c3: + 29:eb:de:f9:c2:40:f9:e8:56:c5:f0:2f:ec:f4:d9:ec:48:51: + b8:63:38:5e:93:6e:18:96:85:b9:ca:50:9c:a4:b8:ea:66:26: + 68:93:85:6f:6f:4c:71:d0:be:7a:0b:3c:31:b9:f7:be:69:9e: + 10:d7:d1:40:e8:ac:16:71:ab:ae:ab:38:e1:70:b1:ca:92:16: + e0:5d:85:a6:18:80:06:00:9c:e1:a6:18:42:51:a7:68:68:59: + ef:26:94:5f:ad:31:0c:fe:29:1e:17:01:84:37:5b:e8:12:32: + a3:5d + +American Express CA +=================== +MD5 Fingerprint: 1C:D5:8E:82:BE:70:55:8E:39:61:DF:AD:51:DB:6B:A0 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICkDCCAfkCAgCNMA0GCSqGSIb3DQEBBAUAMIGPMQswCQYDVQQGEwJVUzEnMCUG +A1UEChMeQW1lcmljYW4gRXhwcmVzcyBDb21wYW55LCBJbmMuMSYwJAYDVQQLEx1B +bWVyaWNhbiBFeHByZXNzIFRlY2hub2xvZ2llczEvMC0GA1UEAxMmQW1lcmljYW4g +RXhwcmVzcyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgwODE0MjIwMTAwWhcN +MDYwODE0MjM1OTAwWjCBjzELMAkGA1UEBhMCVVMxJzAlBgNVBAoTHkFtZXJpY2Fu +IEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1lcmljYW4gRXhwcmVz +cyBUZWNobm9sb2dpZXMxLzAtBgNVBAMTJkFtZXJpY2FuIEV4cHJlc3MgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ8kmS +hcr9FSm1BrZE7PyIo/KGzv8UTyQckvnCI8HOQ99dNMi4FOzVKnCRSZXXVs2U8amT +0Ggi3E19oApyKkfqJfCFAF82VGHPC/k3Wmed6R/pZD9wlWGn0DAC3iYopGYDBOkw ++48zB/lvYYeictvzaHhjZlmpybdm4RWySDYs+QIDAQABMA0GCSqGSIb3DQEBBAUA +A4GBAGgXYrhzi0xs60qlPqvlnS7SzYoHV/PGWZd2Fxf4Uo4nk9hY2Chs9KIEeorC +diSxArTfKPL386infiNIYYj0EWiuJl32oUtTJWrYKhQCDuCHIG6eGVxzkAsj4jGX +Iz/VIqLTBnvaN/XXtUFEF3pFAtmFRWbWjsfwegyZYiJpW+3S +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 141 (0x8d) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, O=American Express Company, Inc., OU=American Express Technologies, CN=American Express Certificate Authority + Validity + Not Before: Aug 14 22:01:00 1998 GMT + Not After : Aug 14 23:59:00 2006 GMT + Subject: C=US, O=American Express Company, Inc., OU=American Express Technologies, CN=American Express Certificate Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c9:f2:49:92:85:ca:fd:15:29:b5:06:b6:44:ec: + fc:88:a3:f2:86:ce:ff:14:4f:24:1c:92:f9:c2:23: + c1:ce:43:df:5d:34:c8:b8:14:ec:d5:2a:70:91:49: + 95:d7:56:cd:94:f1:a9:93:d0:68:22:dc:4d:7d:a0: + 0a:72:2a:47:ea:25:f0:85:00:5f:36:54:61:cf:0b: + f9:37:5a:67:9d:e9:1f:e9:64:3f:70:95:61:a7:d0: + 30:02:de:26:28:a4:66:03:04:e9:30:fb:8f:33:07: + f9:6f:61:87:a2:72:db:f3:68:78:63:66:59:a9:c9: + b7:66:e1:15:b2:48:36:2c:f9 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + 68:17:62:b8:73:8b:4c:6c:eb:4a:a5:3e:ab:e5:9d:2e:d2:cd: + 8a:07:57:f3:c6:59:97:76:17:17:f8:52:8e:27:93:d8:58:d8: + 28:6c:f4:a2:04:7a:8a:c2:76:24:b1:02:b4:df:28:f2:f7:f3: + a8:a7:7e:23:48:61:88:f4:11:68:ae:26:5d:f6:a1:4b:53:25: + 6a:d8:2a:14:02:0e:e0:87:20:6e:9e:19:5c:73:90:0b:23:e2: + 31:97:23:3f:d5:22:a2:d3:06:7b:da:37:f5:d7:b5:41:44:17: + 7a:45:02:d9:85:45:66:d6:8e:c7:f0:7a:0c:99:62:22:69:5b: + ed:d2 + +American Express Global CA +========================== +MD5 Fingerprint: 63:1B:66:93:8C:F3:66:CB:3C:79:57:DC:05:49:EA:DB +PEM Data: +-----BEGIN CERTIFICATE----- +MIIEBDCCAuygAwIBAgICAIUwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVT +MScwJQYDVQQKEx5BbWVyaWNhbiBFeHByZXNzIENvbXBhbnksIEluYy4xJjAkBgNV +BAsTHUFtZXJpY2FuIEV4cHJlc3MgVGVjaG5vbG9naWVzMTYwNAYDVQQDEy1BbWVy +aWNhbiBFeHByZXNzIEdsb2JhbCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgw +ODE0MTkwNjAwWhcNMTMwODE0MjM1OTAwWjCBljELMAkGA1UEBhMCVVMxJzAlBgNV +BAoTHkFtZXJpY2FuIEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1l +cmljYW4gRXhwcmVzcyBUZWNobm9sb2dpZXMxNjA0BgNVBAMTLUFtZXJpY2FuIEV4 +cHJlc3MgR2xvYmFsIENlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAPAkJmYu++tKc3FTiUfLJjxTkpRMysKFtQ34w1e9 +Lyofahi3V68MABb6oLaQpvcaoS5mJsdoo4qTaWa1RlYtHYLqkAwKIsKJUI0F89Sr +c0HwzxKsKLRvFJSWWUuekHWG3+JH6+HpT0N+h8onGGaetcFAZX38YW+tm3LPqV7Y +8/nabpEQ+ky16n4g3qk5L/WI5IpvNcYgnCuGRjMK/DFVpWusFkDpzTVZbzIEw3u1 +D3t3cPNIuypSgs6vKW3xEW9t5gcAAe+a8yYNpnkTZ6/4qxx1rJG1a75AsN6cDLFp +hRlxkRNFyt/R/eayypaDedvFuKpbepALeFY+xteflEgR9a0CAwEAAaNaMFgwEgYD +VR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0gBBAwDjAMBgoq +hkiG+Q8KAQUBMBkGA1UdDgQSBBBXRzV7NicRqAj8L0Yl6yRpMA0GCSqGSIb3DQEB +BQUAA4IBAQDHYUWoinG5vjTpIXshzVYTmNUwY+kYqkuSFb8LHbvskmnFLsNhi+gw +RcsQRsFzOFyLGdIr80DrfHKzLh4n43WVihybLsSVBYZy0FX0oZJSeVzb9Pjc5dcS +sUDHPIbkMWVKyjfG3nZXGWlMRmn8Kq0WN3qTrPchSy3766lQy8HRQAjaA2mHpzde +VcHF7cTjjgwml5tcV0ty4/IDBdACOyYDQJCevgtbSQx48dVMVSng9v1MA6lUAjLR +V1qFrEPtWzsWX6C/NdtLnnvo/+cNPDuom0lBRvVzTv+SZSGDE1Vx60k8f4gawhIo +JaFGS0E3l3/sjvHUoZbCILZerakcHhGg +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 133 (0x85) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=American Express Company, Inc., OU=American Express Technologies, CN=American Express Global Certificate Authority + Validity + Not Before: Aug 14 19:06:00 1998 GMT + Not After : Aug 14 23:59:00 2013 GMT + Subject: C=US, O=American Express Company, Inc., OU=American Express Technologies, CN=American Express Global Certificate Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:f0:24:26:66:2e:fb:eb:4a:73:71:53:89:47:cb: + 26:3c:53:92:94:4c:ca:c2:85:b5:0d:f8:c3:57:bd: + 2f:2a:1f:6a:18:b7:57:af:0c:00:16:fa:a0:b6:90: + a6:f7:1a:a1:2e:66:26:c7:68:a3:8a:93:69:66:b5: + 46:56:2d:1d:82:ea:90:0c:0a:22:c2:89:50:8d:05: + f3:d4:ab:73:41:f0:cf:12:ac:28:b4:6f:14:94:96: + 59:4b:9e:90:75:86:df:e2:47:eb:e1:e9:4f:43:7e: + 87:ca:27:18:66:9e:b5:c1:40:65:7d:fc:61:6f:ad: + 9b:72:cf:a9:5e:d8:f3:f9:da:6e:91:10:fa:4c:b5: + ea:7e:20:de:a9:39:2f:f5:88:e4:8a:6f:35:c6:20: + 9c:2b:86:46:33:0a:fc:31:55:a5:6b:ac:16:40:e9: + cd:35:59:6f:32:04:c3:7b:b5:0f:7b:77:70:f3:48: + bb:2a:52:82:ce:af:29:6d:f1:11:6f:6d:e6:07:00: + 01:ef:9a:f3:26:0d:a6:79:13:67:af:f8:ab:1c:75: + ac:91:b5:6b:be:40:b0:de:9c:0c:b1:69:85:19:71: + 91:13:45:ca:df:d1:fd:e6:b2:ca:96:83:79:db:c5: + b8:aa:5b:7a:90:0b:78:56:3e:c6:d7:9f:94:48:11: + f5:ad + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:5 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: 1.2.840.113807.10.1.5.1 + + X509v3 Subject Key Identifier: + 57:47:35:7B:36:27:11:A8:08:FC:2F:46:25:EB:24:69 + Signature Algorithm: sha1WithRSAEncryption + c7:61:45:a8:8a:71:b9:be:34:e9:21:7b:21:cd:56:13:98:d5: + 30:63:e9:18:aa:4b:92:15:bf:0b:1d:bb:ec:92:69:c5:2e:c3: + 61:8b:e8:30:45:cb:10:46:c1:73:38:5c:8b:19:d2:2b:f3:40: + eb:7c:72:b3:2e:1e:27:e3:75:95:8a:1c:9b:2e:c4:95:05:86: + 72:d0:55:f4:a1:92:52:79:5c:db:f4:f8:dc:e5:d7:12:b1:40: + c7:3c:86:e4:31:65:4a:ca:37:c6:de:76:57:19:69:4c:46:69: + fc:2a:ad:16:37:7a:93:ac:f7:21:4b:2d:fb:eb:a9:50:cb:c1: + d1:40:08:da:03:69:87:a7:37:5e:55:c1:c5:ed:c4:e3:8e:0c: + 26:97:9b:5c:57:4b:72:e3:f2:03:05:d0:02:3b:26:03:40:90: + 9e:be:0b:5b:49:0c:78:f1:d5:4c:55:29:e0:f6:fd:4c:03:a9: + 54:02:32:d1:57:5a:85:ac:43:ed:5b:3b:16:5f:a0:bf:35:db: + 4b:9e:7b:e8:ff:e7:0d:3c:3b:a8:9b:49:41:46:f5:73:4e:ff: + 92:65:21:83:13:55:71:eb:49:3c:7f:88:1a:c2:12:28:25:a1: + 46:4b:41:37:97:7f:ec:8e:f1:d4:a1:96:c2:20:b6:5e:ad:a9: + 1c:1e:11:a0 + +BelSign Object Publishing CA +============================ +MD5 Fingerprint: 8A:02:F8:DF:B8:E1:84:9F:5A:C2:60:24:65:D1:73:FB +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDAzCCAmygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBuzELMAkGA1UEBhMCQkUx +ETAPBgNVBAcTCEJydXNzZWxzMRMwEQYDVQQKEwpCZWxTaWduIE5WMTgwNgYDVQQL +Ey9CZWxTaWduIE9iamVjdCBQdWJsaXNoaW5nIENlcnRpZmljYXRlIEF1dGhvcml0 +eTElMCMGA1UEAxMcQmVsU2lnbiBPYmplY3QgUHVibGlzaGluZyBDQTEjMCEGCSqG +SIb3DQEJARYUd2VibWFzdGVyQGJlbHNpZ24uYmUwHhcNOTcwOTE5MjIwMzAwWhcN +MDcwOTE5MjIwMzAwWjCBuzELMAkGA1UEBhMCQkUxETAPBgNVBAcTCEJydXNzZWxz +MRMwEQYDVQQKEwpCZWxTaWduIE5WMTgwNgYDVQQLEy9CZWxTaWduIE9iamVjdCBQ +dWJsaXNoaW5nIENlcnRpZmljYXRlIEF1dGhvcml0eTElMCMGA1UEAxMcQmVsU2ln +biBPYmplY3QgUHVibGlzaGluZyBDQTEjMCEGCSqGSIb3DQEJARYUd2VibWFzdGVy +QGJlbHNpZ24uYmUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQuH7a/7oJA +3fm3LkHVngWxWtAmfGJVA5v8y2HeS+/+6Jn+h7mIz5DaDwk8dt8Xl7bLPyVF/bS8 +WAC+sFq2FIeP7mdkrR2Ig7tnn2VhAFgIgFCfgMkx9iqQHC33SmwQ9iNDXTgJYIhX +As0WbBj8zfuSKnfQnpOjXYhk0Mj4XVRRAgMBAAGjFTATMBEGCWCGSAGG+EIBAQQE +AwIABzANBgkqhkiG9w0BAQQFAAOBgQBjdhd8lvBTpV0BHFPOKcJ+daxMDaIIc7Rq +Mf0CBhSZ3FQEpL/IloafMUMyJVf2hfYluze+oXkjyVcGJXFrRU/49AJAFoIir1Tq +Mij2De6ZuksIUQ9uhiMhTC0liIHELg7xEyw4ipUCJMM6lWPkk45IuwhHcl+u5jpa +R9Zxxp6aUg== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=BE, L=Brussels, O=BelSign NV, OU=BelSign Object Publishing Certificate Authority, CN=BelSign Object Publishing CA/Email=webmaster@belsign.be + Validity + Not Before: Sep 19 22:03:00 1997 GMT + Not After : Sep 19 22:03:00 2007 GMT + Subject: C=BE, L=Brussels, O=BelSign NV, OU=BelSign Object Publishing Certificate Authority, CN=BelSign Object Publishing CA/Email=webmaster@belsign.be + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c4:2e:1f:b6:bf:ee:82:40:dd:f9:b7:2e:41:d5: + 9e:05:b1:5a:d0:26:7c:62:55:03:9b:fc:cb:61:de: + 4b:ef:fe:e8:99:fe:87:b9:88:cf:90:da:0f:09:3c: + 76:df:17:97:b6:cb:3f:25:45:fd:b4:bc:58:00:be: + b0:5a:b6:14:87:8f:ee:67:64:ad:1d:88:83:bb:67: + 9f:65:61:00:58:08:80:50:9f:80:c9:31:f6:2a:90: + 1c:2d:f7:4a:6c:10:f6:23:43:5d:38:09:60:88:57: + 02:cd:16:6c:18:fc:cd:fb:92:2a:77:d0:9e:93:a3: + 5d:88:64:d0:c8:f8:5d:54:51 + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Signature Algorithm: md5WithRSAEncryption + 63:76:17:7c:96:f0:53:a5:5d:01:1c:53:ce:29:c2:7e:75:ac: + 4c:0d:a2:08:73:b4:6a:31:fd:02:06:14:99:dc:54:04:a4:bf: + c8:96:86:9f:31:43:32:25:57:f6:85:f6:25:bb:37:be:a1:79: + 23:c9:57:06:25:71:6b:45:4f:f8:f4:02:40:16:82:22:af:54: + ea:32:28:f6:0d:ee:99:ba:4b:08:51:0f:6e:86:23:21:4c:2d: + 25:88:81:c4:2e:0e:f1:13:2c:38:8a:95:02:24:c3:3a:95:63: + e4:93:8e:48:bb:08:47:72:5f:ae:e6:3a:5a:47:d6:71:c6:9e: + 9a:52 + +BelSign Secure Server CA +======================== +MD5 Fingerprint: 3D:5E:82:C6:D9:AD:D9:8B:93:6B:0C:10:B9:49:0A:B1 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIC8zCCAlygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBszELMAkGA1UEBhMCQkUx +ETAPBgNVBAcTCEJydXNzZWxzMRMwEQYDVQQKEwpCZWxTaWduIE5WMTQwMgYDVQQL +EytCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSEw +HwYDVQQDExhCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ0ExIzAhBgkqhkiG9w0BCQEW +FHdlYm1hc3RlckBiZWxzaWduLmJlMB4XDTk3MDcxNjIyMDA1NFoXDTA3MDcxNjIy +MDA1NFowgbMxCzAJBgNVBAYTAkJFMREwDwYDVQQHEwhCcnVzc2VsczETMBEGA1UE +ChMKQmVsU2lnbiBOVjE0MDIGA1UECxMrQmVsU2lnbiBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRlIEF1dGhvcml0eTEhMB8GA1UEAxMYQmVsU2lnbiBTZWN1cmUgU2Vy +dmVyIENBMSMwIQYJKoZIhvcNAQkBFhR3ZWJtYXN0ZXJAYmVsc2lnbi5iZTCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1gESeJL4BEJ/yccig/x8R3AwK0kLPjZA +kCjaIXODU/LE0RZAwFP/rqbGJLMnbaWzPTl3XagG9ubpvGMRTgZlcAqdk/miQIt/ +SoQOjRax1swIZBIM4ChLyKWEkBf7EUYu1qeFGMsYrmOasFgG9ADP+MQJGjUMofnu +Sv1t3v4mpTsCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgCgMA0GCSqGSIb3DQEB +BAUAA4GBAGw9mcMF4h3K5S2qaIWLQDEgZhNo5lg6idCNdbLFYth9go/32TKBd/Y1 +W4UpzmeyubwrGXjP84f9RvGVdbIJVwMwwXrNckdxgMp9ncllPEcRIn36BwsoeKGT +6AVFSOIyMko96FMcELfHc4wHUOH5yStTQfWDjeUJOUqOA2KqQGOL +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=BE, L=Brussels, O=BelSign NV, OU=BelSign Secure Server Certificate Authority, CN=BelSign Secure Server CA/Email=webmaster@belsign.be + Validity + Not Before: Jul 16 22:00:54 1997 GMT + Not After : Jul 16 22:00:54 2007 GMT + Subject: C=BE, L=Brussels, O=BelSign NV, OU=BelSign Secure Server Certificate Authority, CN=BelSign Secure Server CA/Email=webmaster@belsign.be + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d6:01:12:78:92:f8:04:42:7f:c9:c7:22:83:fc: + 7c:47:70:30:2b:49:0b:3e:36:40:90:28:da:21:73: + 83:53:f2:c4:d1:16:40:c0:53:ff:ae:a6:c6:24:b3: + 27:6d:a5:b3:3d:39:77:5d:a8:06:f6:e6:e9:bc:63: + 11:4e:06:65:70:0a:9d:93:f9:a2:40:8b:7f:4a:84: + 0e:8d:16:b1:d6:cc:08:64:12:0c:e0:28:4b:c8:a5: + 84:90:17:fb:11:46:2e:d6:a7:85:18:cb:18:ae:63: + 9a:b0:58:06:f4:00:cf:f8:c4:09:1a:35:0c:a1:f9: + ee:4a:fd:6d:de:fe:26:a5:3b + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Cert Type: + SSL Client, S/MIME + Signature Algorithm: md5WithRSAEncryption + 6c:3d:99:c3:05:e2:1d:ca:e5:2d:aa:68:85:8b:40:31:20:66: + 13:68:e6:58:3a:89:d0:8d:75:b2:c5:62:d8:7d:82:8f:f7:d9: + 32:81:77:f6:35:5b:85:29:ce:67:b2:b9:bc:2b:19:78:cf:f3: + 87:fd:46:f1:95:75:b2:09:57:03:30:c1:7a:cd:72:47:71:80: + ca:7d:9d:c9:65:3c:47:11:22:7d:fa:07:0b:28:78:a1:93:e8: + 05:45:48:e2:32:32:4a:3d:e8:53:1c:10:b7:c7:73:8c:07:50: + e1:f9:c9:2b:53:41:f5:83:8d:e5:09:39:4a:8e:03:62:aa:40: + 63:8b + +Deutsche Telekom AG Root CA +=========================== +MD5 Fingerprint: 77:DE:04:94:77:D0:0C:5F:A7:B1:F4:30:18:87:FB:55 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICjjCCAfegAwIBAgIBBjANBgkqhkiG9w0BAQQFADBtMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEdMBsGA1UECxMUVGVsZVNlYyBU +cnVzdCBDZW50ZXIxITAfBgNVBAMTGERldXRzY2hlIFRlbGVrb20gUm9vdCBDQTAe +Fw05ODEyMDkwOTExMDBaFw0wNDEyMDkyMzU5MDBaMG0xCzAJBgNVBAYTAkRFMRww +GgYDVQQKExNEZXV0c2NoZSBUZWxla29tIEFHMR0wGwYDVQQLExRUZWxlU2VjIFRy +dXN0IENlbnRlcjEhMB8GA1UEAxMYRGV1dHNjaGUgVGVsZWtvbSBSb290IENBMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBSz5BbO5EtdpcffqVjAIVxRDe7sa +nG0vV2HX4vVEa+42QZb2ZM7hwbK5pBQEmFDocPiONZp9ScFhHVmu2gYYlX2tzuyp +vtEYD0CRdiqj5f3+iRX0V/fgVdp1rQD0LME1zLRDJlViRC4BJZyKW/DB0AA1eP41 +3pRAZHiDocw5iQIDAQABoz4wPDAPBgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQE +AwIBBjAZBgNVHQ4EEgQQLIdZH4sTgLL5hp0+En5YljANBgkqhkiG9w0BAQQFAAOB +gQAP/nO1B4hvoAuJ6spQH5TelCsLJ15P9RyVJtqMllStGZE3Q12ryYuzzW+YOT3t +3TXjcbftE5OD6IblKTMTE7w1e/0oL3BZ1dO0jSgTWTvI1XT5RcIHYKq4GFT5pWj/ +1wXVj7YFMS5BSvQQH2BHGguLGU2SVyDS71AZ6M3QcLy8Ng== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 6 (0x6) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=DE, O=Deutsche Telekom AG, OU=TeleSec Trust Center, CN=Deutsche Telekom Root CA + Validity + Not Before: Dec 9 09:11:00 1998 GMT + Not After : Dec 9 23:59:00 2004 GMT + Subject: C=DE, O=Deutsche Telekom AG, OU=TeleSec Trust Center, CN=Deutsche Telekom Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:dd:05:2c:f9:05:b3:b9:12:d7:69:71:f7:ea:56: + 30:08:57:14:43:7b:bb:1a:9c:6d:2f:57:61:d7:e2: + f5:44:6b:ee:36:41:96:f6:64:ce:e1:c1:b2:b9:a4: + 14:04:98:50:e8:70:f8:8e:35:9a:7d:49:c1:61:1d: + 59:ae:da:06:18:95:7d:ad:ce:ec:a9:be:d1:18:0f: + 40:91:76:2a:a3:e5:fd:fe:89:15:f4:57:f7:e0:55: + da:75:ad:00:f4:2c:c1:35:cc:b4:43:26:55:62:44: + 2e:01:25:9c:8a:5b:f0:c1:d0:00:35:78:fe:35:de: + 94:40:64:78:83:a1:cc:39:89 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:TRUE, pathlen:5 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 2C:87:59:1F:8B:13:80:B2:F9:86:9D:3E:12:7E:58:96 + Signature Algorithm: md5WithRSAEncryption + 0f:fe:73:b5:07:88:6f:a0:0b:89:ea:ca:50:1f:94:de:94:2b: + 0b:27:5e:4f:f5:1c:95:26:da:8c:96:54:ad:19:91:37:43:5d: + ab:c9:8b:b3:cd:6f:98:39:3d:ed:dd:35:e3:71:b7:ed:13:93: + 83:e8:86:e5:29:33:13:13:bc:35:7b:fd:28:2f:70:59:d5:d3: + b4:8d:28:13:59:3b:c8:d5:74:f9:45:c2:07:60:aa:b8:18:54: + f9:a5:68:ff:d7:05:d5:8f:b6:05:31:2e:41:4a:f4:10:1f:60: + 47:1a:0b:8b:19:4d:92:57:20:d2:ef:50:19:e8:cd:d0:70:bc: + bc:36 + +Digital Signature Trust Co. Global CA 1 +======================================= +MD5 Fingerprint: 25:7A:BA:83:2E:B6:A2:0B:DA:FE:F5:02:0F:08:D7:AD +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV +UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL +EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ +BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x +ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg +bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ +j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV +Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG +SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx +JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI +RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw +MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5 +fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i ++DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG +SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN +QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+ +gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 913315222 (0x36701596) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Digital Signature Trust Co., OU=DSTCA E1 + Validity + Not Before: Dec 10 18:10:23 1998 GMT + Not After : Dec 10 18:40:23 2018 GMT + Subject: C=US, O=Digital Signature Trust Co., OU=DSTCA E1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a0:6c:81:a9:cf:34:1e:24:dd:fe:86:28:cc:de: + 83:2f:f9:5e:d4:42:d2:e8:74:60:66:13:98:06:1c: + a9:51:12:69:6f:31:55:b9:49:72:00:08:7e:d3:a5: + 62:44:37:24:99:8f:d9:83:48:8f:99:6d:95:13:bb: + 43:3b:2e:49:4e:88:37:c1:bb:58:7f:fe:e1:bd:f8: + bb:61:cd:f3:47:c0:99:a6:f1:f3:91:e8:78:7c:00: + cb:61:c9:44:27:71:69:55:4a:7e:49:4d:ed:a2:a3: + be:02:4c:00:ca:02:a8:ee:01:02:31:64:0f:52:2d: + 13:74:76:36:b5:7a:b4:2d:71 + Exponent: 3 (0x3) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 CRL Distribution Points: + DirName:/C=US/O=Digital Signature Trust Co./OU=DSTCA E1/CN=CRL1 + + X509v3 Private Key Usage Period: + Not Before: Dec 10 18:10:23 1998 GMT, Not After: Dec 10 18:10:23 2018 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:6A:79:7E:91:69:46:18:13:0A:02:77:A5:59:5B:60:98:25:0E:A2:F8 + + X509v3 Subject Key Identifier: + 6A:79:7E:91:69:46:18:13:0A:02:77:A5:59:5B:60:98:25:0E:A2:F8 + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0 +..V4.0.... + Signature Algorithm: sha1WithRSAEncryption + 22:12:d8:7a:1d:dc:81:06:b6:09:65:b2:87:c8:1f:5e:b4:2f: + e9:c4:1e:f2:3c:c1:bb:04:90:11:4a:83:4e:7e:93:b9:4d:42: + c7:92:26:a0:5c:34:9a:38:72:f8:fd:6b:16:3e:20:ee:82:8b: + 31:2a:93:36:85:23:88:8a:3c:03:68:d3:c9:09:0f:4d:fc:6c: + a4:da:28:72:93:0e:89:80:b0:7d:fe:80:6f:65:6d:18:33:97: + 8b:c2:6b:89:ee:60:3d:c8:9b:ef:7f:2b:32:62:73:93:cb:3c: + e3:7b:e2:76:78:45:bc:a1:93:04:bb:86:9f:3a:5b:43:7a:c3: + 8a:65 + +Digital Signature Trust Co. Global CA 2 +======================================= +MD5 Fingerprint: 6C:C9:A7:6E:47:F1:0C:E3:53:3B:78:4C:4D:C2:6A:C5 +PEM Data: +-----BEGIN CERTIFICATE----- +MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw +CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp +dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE +CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B +CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx +ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO +U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 +IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx +ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf +WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK +xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE +zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F +5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv +OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG +9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz +ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME +lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG +Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q +gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k +Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + d0:1e:40:8b:00:00:02:7c:00:00:00:02:00:00:00:01 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=DSTCA X1, CN=DST RootCA X1/Email=ca@digsigtrust.com + Validity + Not Before: Dec 1 18:18:55 1998 GMT + Not After : Nov 28 18:18:55 2008 GMT + Subject: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=DSTCA X1, CN=DST RootCA X1/Email=ca@digsigtrust.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:d2:c6:26:b6:e7:a5:3d:c1:c4:68:d5:50:6f:53: + c5:6f:49:13:09:b8:af:2c:48:8d:14:6a:a3:17:5f: + 5a:f9:d3:2e:75:2f:d8:28:62:d1:93:2f:fc:4d:d4: + ab:87:e5:08:c7:99:e7:92:3f:75:bd:eb:25:b4:15: + c1:9b:19:3d:d2:44:8d:d7:74:20:6d:37:02:8f:69: + 93:5b:8a:c4:19:9d:f4:b2:0e:fc:16:6c:b9:b1:05: + 92:83:d1:85:2c:60:94:3e:45:55:a0:d9:ab:08:21: + e6:60:e8:3b:74:f2:99:50:51:68:d0:03:2d:b1:80: + be:a3:d8:52:b0:44:cd:43:4a:70:8e:58:85:95:e1: + 4e:2c:d6:2d:41:6f:d6:84:e7:c8:98:44:ca:47:db: + 2c:24:a5:69:26:cf:6b:b8:27:62:c3:f4:c9:7a:92: + 23:ed:13:67:82:ae:45:2e:45:e5:7e:72:3f:85:9d: + 94:62:10:e6:3c:91:a1:ad:77:00:e0:15:ec:f3:84: + 80:72:7a:8e:6e:60:97:c7:24:59:10:34:83:5b:e1: + a5:a4:69:b6:57:35:1c:78:59:c6:d3:2f:3a:73:67: + ee:94:ca:04:13:05:62:06:70:23:b3:f4:7c:ee:45: + d9:64:0b:5b:49:aa:a4:43:ce:26:c4:44:12:6c:b8: + dd:79 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + a2:37:b2:3f:69:fb:d7:86:79:54:49:31:95:33:2b:f3:d1:09: + 14:49:62:60:86:a5:b0:11:e2:50:c2:1d:06:57:3e:2d:e8:33: + 64:be:9b:aa:ad:5f:1b:4d:d4:99:95:a2:8b:9a:c9:62:72:b5: + 69:ea:d9:58:ab:35:ed:15:a2:43:d6:b6:bc:07:79:65:64:73: + 7d:d7:79:ca:7b:d5:5a:51:c6:e1:53:04:96:8d:38:cf:a3:17: + ac:39:71:6b:01:c3:8b:53:3c:63:e9:ee:79:c0:e4:be:92:32: + 64:7a:b3:1f:97:94:62:bd:ea:b2:20:15:95:fb:97:f2:78:2f: + 63:36:40:38:e3:46:0f:1d:dd:ac:95:ca:e7:4b:90:7b:b1:4b: + a9:d4:c5:eb:9a:da:aa:d5:a3:94:14:46:8d:2d:1f:f3:3a:d6: + 93:3a:f6:3e:79:fc:e8:e6:b0:75:ed:ee:3d:c9:70:c7:5d:aa: + 81:4b:46:25:1c:c7:6c:15:e3:95:4e:0f:aa:32:37:94:0a:17: + 24:92:13:84:58:d2:63:6f:2b:f7:e6:5b:62:0b:13:17:b0:0d: + 52:4c:fe:fe:6f:5c:e2:91:6e:1d:fd:a4:62:d7:68:fa:8e:7a: + 4f:d2:08:da:93:dc:f0:92:11:7a:d0:dc:72:93:0c:73:93:62: + 85:68:d0:f4 + +Digital Signature Trust Co. Global CA 3 +======================================= +MD5 Fingerprint: 93:C2:8E:11:7B:D4:F3:03:19:BD:28:75:13:4A:45:4A +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV +UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL +EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ +BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x +ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/ +k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso +LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o +TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG +SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx +JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI +RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3 +MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C +TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5 +WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG +SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR +xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL +B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 913232846 (0x366ed3ce) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Digital Signature Trust Co., OU=DSTCA E2 + Validity + Not Before: Dec 9 19:17:26 1998 GMT + Not After : Dec 9 19:47:26 2018 GMT + Subject: C=US, O=Digital Signature Trust Co., OU=DSTCA E2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:bf:93:8f:17:92:ef:33:13:18:eb:10:7f:4e:16: + bf:ff:06:8f:2a:85:bc:5e:f9:24:a6:24:88:b6:03: + b7:c1:c3:5f:03:5b:d1:6f:ae:7e:42:ea:66:23:b8: + 63:83:56:fb:28:2d:e1:38:8b:b4:ee:a8:01:e1:ce: + 1c:b6:88:2a:22:46:85:fb:9f:a7:70:a9:47:14:3f: + ce:de:65:f0:a8:71:f7:4f:26:6c:8c:bc:c6:b5:ef: + de:49:27:ff:48:2a:7d:e8:4d:03:cc:c7:b2:52:c6: + 17:31:13:3b:b5:4d:db:c8:c4:f6:c3:0f:24:2a:da: + 0c:9d:e7:91:5b:80:cd:94:9d + Exponent: 3 (0x3) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 CRL Distribution Points: + DirName:/C=US/O=Digital Signature Trust Co./OU=DSTCA E2/CN=CRL1 + + X509v3 Private Key Usage Period: + Not Before: Dec 9 19:17:26 1998 GMT, Not After: Dec 9 19:17:26 2018 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:1E:82:4D:28:65:80:3C:C9:41:6E:AC:35:2E:5A:CB:DE:EE:F8:39:5B + + X509v3 Subject Key Identifier: + 1E:82:4D:28:65:80:3C:C9:41:6E:AC:35:2E:5A:CB:DE:EE:F8:39:5B + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0 +..V4.0.... + Signature Algorithm: sha1WithRSAEncryption + 47:8d:83:ad:62:f2:db:b0:9e:45:22:05:b9:a2:d6:03:0e:38: + 72:e7:9e:fc:7b:e6:93:b6:9a:a5:a2:94:c8:34:1d:91:d1:c5: + d7:f4:0a:25:0f:3d:78:81:9e:0f:b1:67:c4:90:4c:63:dd:5e: + a7:e2:ba:9f:f5:f7:4d:a5:31:7b:9c:29:2d:4c:fe:64:3e:ec: + b6:53:fe:ea:9b:ed:82:db:74:75:4b:07:79:6e:1e:d8:19:83: + 73:de:f5:3e:d0:b5:de:e7:4b:68:7d:43:2e:2a:20:e1:7e:a0: + 78:44:9e:08:f5:98:f9:c7:7f:1b:1b:d6:06:20:02:58:a1:c3: + a2:03 + +Digital Signature Trust Co. Global CA 4 +======================================= +MD5 Fingerprint: CD:3B:3D:62:5B:09:B8:09:36:87:9E:12:2F:71:64:BA +PEM Data: +-----BEGIN CERTIFICATE----- +MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw +CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp +dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE +CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B +CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy +MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO +U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 +IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx +ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV +p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw +BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl +5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi +3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+ +QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG +9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ +2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN +I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL +553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q +10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN +uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + d0:1e:40:8b:00:00:77:6d:00:00:00:01:00:00:00:04 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=DSTCA X2, CN=DST RootCA X2/Email=ca@digsigtrust.com + Validity + Not Before: Nov 30 22:46:16 1998 GMT + Not After : Nov 27 22:46:16 2008 GMT + Subject: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=DSTCA X2, CN=DST RootCA X2/Email=ca@digsigtrust.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:dc:75:f0:8c:c0:75:96:9a:c0:62:1f:26:f7:c4: + e1:9a:ea:e0:56:73:5b:99:cd:01:44:a8:08:b6:d5: + a7:da:1a:04:18:39:92:4a:78:a3:81:c2:f5:77:7a: + 50:b4:70:ff:9a:ab:c6:c7:ca:6e:83:4f:42:98:fb: + 26:0b:da:dc:6d:d6:a9:99:55:52:67:e9:28:03:92: + dc:e5:b0:05:9a:0f:15:f9:6b:59:72:56:f2:fa:39: + fc:aa:68:ee:0f:1f:10:83:2f:fc:9d:fa:17:96:dd: + 82:e3:e6:45:7d:c0:4b:80:44:1f:ed:2c:e0:84:fd: + 91:5c:92:54:69:25:e5:62:69:dc:e5:ee:00:52:bd: + 33:0b:ad:75:02:85:a7:64:50:2d:c5:19:19:30:c0: + 26:db:c9:d3:fd:2e:99:ad:59:b5:0b:4d:d4:41:ae: + 85:48:43:59:dc:b7:a8:e2:a2:de:c3:8f:d7:b8:a1: + 62:a6:68:50:52:e4:cf:31:a7:94:85:da:9f:46:32: + 17:56:e5:f2:eb:66:3d:12:ff:43:db:98:ef:77:cf: + cb:81:8d:34:b1:c6:50:4a:26:d1:e4:3e:41:50:af: + 6c:ae:22:34:2e:d5:6b:6e:83:ba:79:b8:76:65:48: + da:09:29:64:63:22:b9:fb:47:76:85:8c:86:44:cb: + 09:db + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + b5:36:0e:5d:e1:61:28:5a:11:65:c0:3f:83:03:79:4d:be:28: + a6:0b:07:02:52:85:cd:f8:91:d0:10:6c:b5:6a:20:5b:1c:90: + d9:30:3c:c6:48:9e:8a:5e:64:f9:a1:71:77:ef:04:27:1f:07: + eb:e4:26:f7:73:74:c9:44:18:1a:66:d3:e0:43:af:91:3b:d1: + cb:2c:d8:74:54:3a:1c:4d:ca:d4:68:cd:23:7c:1d:10:9e:45: + e9:f6:00:6e:a6:cd:19:ff:4f:2c:29:8f:57:4d:c4:77:92:be: + e0:4c:09:fb:5d:44:86:66:21:a8:b9:32:a2:56:d5:e9:8c:83: + 7c:59:3f:c4:f1:0b:e7:9d:ec:9e:bd:9c:18:0e:3e:c2:39:79: + 28:b7:03:0d:08:cb:c6:e7:d9:01:37:50:10:ec:cc:61:16:40: + d4:af:31:74:7b:fc:3f:31:a7:d0:47:73:33:39:1b:cc:4e:6a: + d7:49:83:11:06:fe:eb:82:58:33:32:4c:f0:56:ac:1e:9c:2f: + 56:9a:7b:c1:4a:1c:a5:fd:55:36:ce:fc:96:4d:f4:b0:f0:ec: + b7:6c:82:ed:2f:31:99:42:4c:a9:b2:0d:b8:15:5d:f1:df:ba: + c9:b5:4a:d4:64:98:b3:26:a9:30:c8:fd:a6:ec:ab:96:21:ad: + 7f:c2:78:b6 + +Entrust Worldwide by DST +======================== +MD5 Fingerprint: B4:65:22:0A:7C:AD:DF:41:B7:D5:44:D5:AD:FA:9A:75 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDRzCCArCgAwIBAgIENm3FGDANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJV +UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRswGQYDVQQL +ExJEU1QtRW50cnVzdCBHVEkgQ0EwHhcNOTgxMjA5MDAwMjI0WhcNMTgxMjA5MDAz +MjI0WjBQMQswCQYDVQQGEwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUg +VHJ1c3QgQ28uMRswGQYDVQQLExJEU1QtRW50cnVzdCBHVEkgQ0EwgZ0wDQYJKoZI +hvcNAQEBBQADgYsAMIGHAoGBALYd90uNDxPjEvUJ/gYyDq9MQfV91Ec9KgrfgwXe +3n3mAxb2UTrLRxpKrX7E/R20vnSKeN0Lg460hBPE+/htKa6h4Q8PQ+O1XmBp+oOU +/Hnm3Hbt0UQrjv0Su/4XdxcMie2n71F9xO04wzujevviTaBgtfL9E2XTxuw/vjWc +PSLvAgEDo4IBLjCCASowEQYJYIZIAYb4QgEBBAQDAgAHMHIGA1UdHwRrMGkwZ6Bl +oGOkYTBfMQswCQYDVQQGEwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUg +VHJ1c3QgQ28uMRswGQYDVQQLExJEU1QtRW50cnVzdCBHVEkgQ0ExDTALBgNVBAMT +BENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkwMDAyMjRagQ8yMDE4MTIwOTAwMDIy +NFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFJOaRMrQeFOAKUkE38evMz+ZdV+u +MB0GA1UdDgQWBBSTmkTK0HhTgClJBN/HrzM/mXVfrjAMBgNVHRMEBTADAQH/MBkG +CSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GBAGSJzAOn +3AryWCDn/RegKHLNh7DNmLUkR2MzMRAQsu+KV3KuTAPgZ5+sYEOEIsGpo+Wxp94J +1M8NeEYjW49Je/4TIpeU6nJI4SwgeJbpZkUZywllY2E/0UmYsXYQVdVjSmZLpAdr +3nt/ueaTWxoCW4AO3Y0Y1Iqjwmjxo+AY0U5M +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 913163544 (0x366dc518) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Digital Signature Trust Co., OU=DST-Entrust GTI CA + Validity + Not Before: Dec 9 00:02:24 1998 GMT + Not After : Dec 9 00:32:24 2018 GMT + Subject: C=US, O=Digital Signature Trust Co., OU=DST-Entrust GTI CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b6:1d:f7:4b:8d:0f:13:e3:12:f5:09:fe:06:32: + 0e:af:4c:41:f5:7d:d4:47:3d:2a:0a:df:83:05:de: + de:7d:e6:03:16:f6:51:3a:cb:47:1a:4a:ad:7e:c4: + fd:1d:b4:be:74:8a:78:dd:0b:83:8e:b4:84:13:c4: + fb:f8:6d:29:ae:a1:e1:0f:0f:43:e3:b5:5e:60:69: + fa:83:94:fc:79:e6:dc:76:ed:d1:44:2b:8e:fd:12: + bb:fe:17:77:17:0c:89:ed:a7:ef:51:7d:c4:ed:38: + c3:3b:a3:7a:fb:e2:4d:a0:60:b5:f2:fd:13:65:d3: + c6:ec:3f:be:35:9c:3d:22:ef + Exponent: 3 (0x3) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 CRL Distribution Points: + DirName:/C=US/O=Digital Signature Trust Co./OU=DST-Entrust GTI CA/CN=CRL1 + + X509v3 Private Key Usage Period: + Not Before: Dec 9 00:02:24 1998 GMT, Not After: Dec 9 00:02:24 2018 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:93:9A:44:CA:D0:78:53:80:29:49:04:DF:C7:AF:33:3F:99:75:5F:AE + + X509v3 Subject Key Identifier: + 93:9A:44:CA:D0:78:53:80:29:49:04:DF:C7:AF:33:3F:99:75:5F:AE + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0 +..V4.0.... + Signature Algorithm: sha1WithRSAEncryption + 64:89:cc:03:a7:dc:0a:f2:58:20:e7:fd:17:a0:28:72:cd:87: + b0:cd:98:b5:24:47:63:33:31:10:10:b2:ef:8a:57:72:ae:4c: + 03:e0:67:9f:ac:60:43:84:22:c1:a9:a3:e5:b1:a7:de:09:d4: + cf:0d:78:46:23:5b:8f:49:7b:fe:13:22:97:94:ea:72:48:e1: + 2c:20:78:96:e9:66:45:19:cb:09:65:63:61:3f:d1:49:98:b1: + 76:10:55:d5:63:4a:66:4b:a4:07:6b:de:7b:7f:b9:e6:93:5b: + 1a:02:5b:80:0e:dd:8d:18:d4:8a:a3:c2:68:f1:a3:e0:18:d1: + 4e:4c + +Entrust.net Premium 2048 Secure Server CA +========================================= +MD5 Fingerprint: BA:21:EA:20:D6:DD:DB:8F:C1:57:8B:40:AD:A1:FC:FC +PEM Data: +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy +MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA +vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G +CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA +WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ +h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 +f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN +B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy +vUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 946059622 (0x3863b966) + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Validity + Not Before: Dec 24 17:50:51 1999 GMT + Not After : Dec 24 18:20:51 2019 GMT + Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ad:4d:4b:a9:12:86:b2:ea:a3:20:07:15:16:64: + 2a:2b:4b:d1:bf:0b:4a:4d:8e:ed:80:76:a5:67:b7: + 78:40:c0:73:42:c8:68:c0:db:53:2b:dd:5e:b8:76: + 98:35:93:8b:1a:9d:7c:13:3a:0e:1f:5b:b7:1e:cf: + e5:24:14:1e:b1:81:a9:8d:7d:b8:cc:6b:4b:03:f1: + 02:0c:dc:ab:a5:40:24:00:7f:74:94:a1:9d:08:29: + b3:88:0b:f5:87:77:9d:55:cd:e4:c3:7e:d7:6a:64: + ab:85:14:86:95:5b:97:32:50:6f:3d:c8:ba:66:0c: + e3:fc:bd:b8:49:c1:76:89:49:19:fd:c0:a8:bd:89: + a3:67:2f:c6:9f:bc:71:19:60:b8:2d:e9:2c:c9:90: + 76:66:7b:94:e2:af:78:d6:65:53:5d:3c:d6:9c:b2: + cf:29:03:f9:2f:a4:50:b2:d4:48:ce:05:32:55:8a: + fd:b2:64:4c:0e:e4:98:07:75:db:7f:df:b9:08:55: + 60:85:30:29:f9:7b:48:a4:69:86:e3:35:3f:1e:86: + 5d:7a:7a:15:bd:ef:00:8e:15:22:54:17:00:90:26: + 93:bc:0e:49:68:91:bf:f8:47:d3:9d:95:42:c1:0e: + 4d:df:6f:26:cf:c3:18:21:62:66:43:70:d6:d5:c0: + 07:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 Authority Key Identifier: + keyid:55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70 + + X509v3 Subject Key Identifier: + 55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70 + 1.2.840.113533.7.65.0: + 0...V5.0:4.0.... + Signature Algorithm: sha1WithRSAEncryption + 59:47:ac:21:84:8a:17:c9:9c:89:53:1e:ba:80:85:1a:c6:3c: + 4e:3e:b1:9c:b6:7c:c6:92:5d:18:64:02:e3:d3:06:08:11:61: + 7c:63:e3:2b:9d:31:03:70:76:d2:a3:28:a0:f4:bb:9a:63:73: + ed:6d:e5:2a:db:ed:14:a9:2b:c6:36:11:d0:2b:eb:07:8b:a5: + da:9e:5c:19:9d:56:12:f5:54:29:c8:05:ed:b2:12:2a:8d:f4: + 03:1b:ff:e7:92:10:87:b0:3a:b5:c3:9d:05:37:12:a3:c7:f4: + 15:b9:d5:a4:39:16:9b:53:3a:23:91:f1:a8:82:a2:6a:88:68: + c1:79:02:22:bc:aa:a6:d6:ae:df:b0:14:5f:b8:87:d0:dd:7c: + 7f:7b:ff:af:1c:cf:e6:db:07:ad:5e:db:85:9d:d0:2b:0d:33: + db:04:d1:e6:49:40:13:2b:76:fb:3e:e9:9c:89:0f:15:ce:18: + b0:85:78:21:4f:6b:4f:0e:fa:36:67:cd:07:f2:ff:08:d0:e2: + de:d9:bf:2a:af:b8:87:86:21:3c:04:ca:b7:94:68:7f:cf:3c: + e9:98:d7:38:ff:ec:c0:d9:50:f0:2e:4b:58:ae:46:6f:d0:2e: + c3:60:da:72:55:72:bd:4c:45:9e:61:ba:bf:84:81:92:03:d1: + d2:69:7c:c5 + +Entrust.net Secure Personal CA +============================== +MD5 Fingerprint: 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u +ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh +Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU +MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D +bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq +RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G +CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo +6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux +5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm +AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC +ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50 +cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m +by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp +IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg +Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg +KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV +HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E +BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE +FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7 +pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz +wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a +EkP/TOYGJqibGapEPHayXOw= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 939758062 (0x380391ee) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, O=Entrust.net, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab., OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Client Certification Authority + Validity + Not Before: Oct 12 19:24:30 1999 GMT + Not After : Oct 12 19:54:30 2019 GMT + Subject: C=US, O=Entrust.net, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab., OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Client Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c8:3a:99:5e:31:17:df:ac:27:6f:90:7b:e4:19: + ff:45:a3:34:c2:db:c1:a8:4f:f0:68:ea:84:fd:9f: + 75:79:cf:c1:8a:51:94:af:c7:57:03:47:64:9e:ad: + 82:1b:5a:da:7f:37:78:47:bb:37:98:12:96:ce:c6: + 13:7d:ef:d2:0c:30:51:a9:39:9e:55:f8:fb:b1:e7: + 30:de:83:b2:ba:3e:f1:d5:89:3b:3b:85:ba:aa:74: + 2c:fe:3f:31:6e:af:91:95:6e:06:d4:07:4d:4b:2c: + 56:47:18:04:52:da:0e:10:93:bf:63:90:9b:e1:df: + 8c:e6:02:a4:e6:4f:5e:f7:8b + Exponent: 3 (0x3) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 CRL Distribution Points: + DirName:/C=US/O=Entrust.net/OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab./OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Client Certification Authority/CN=CRL1 + URI:http://www.entrust.net/CRL/Client1.crl + + X509v3 Private Key Usage Period: + Not Before: Oct 12 19:24:30 1999 GMT, Not After: Oct 12 19:24:30 2019 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:C4:FB:9C:29:7B:97:CD:4C:96:FC:EE:5B:B3:CA:99:74:8B:95:EA:4C + + X509v3 Subject Key Identifier: + C4:FB:9C:29:7B:97:CD:4C:96:FC:EE:5B:B3:CA:99:74:8B:95:EA:4C + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0 +..V4.0.... + Signature Algorithm: md5WithRSAEncryption + 3f:ae:8a:f1:d7:66:03:05:9e:3e:fa:ea:1c:46:bb:a4:5b:8f: + 78:9a:12:48:99:f9:f4:35:de:0c:36:07:02:6b:10:3a:89:14: + 81:9c:31:a6:7c:b2:41:b2:6a:e7:07:01:a1:4b:f9:9f:25:3b: + 96:ca:99:c3:3e:a1:51:1c:f3:c3:2e:44:f7:b0:67:46:aa:92: + e5:3b:da:1c:19:14:38:30:d5:e2:a2:31:25:2e:f1:ec:45:38: + ed:f8:06:58:03:73:62:b0:10:31:8f:40:bf:64:e0:5c:3e:c5: + 4f:1f:da:12:43:ff:4c:e6:06:26:a8:9b:19:aa:44:3c:76:b2: + 5c:ec + +Entrust.net Secure Server CA +============================ +MD5 Fingerprint: DF:F2:80:73:CC:F1:E6:61:73:FC:F5:42:E9:C5:7C:EE +PEM Data: +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u +ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc +KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u +ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 +MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE +ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j +b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg +U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ +I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 +wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC +AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb +oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 +BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p +dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk +MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp +b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 +MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi +E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa +MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI +hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN +95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd +2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 927650371 (0x374ad243) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority + Validity + Not Before: May 25 16:09:40 1999 GMT + Not After : May 25 16:39:40 2019 GMT + Subject: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:cd:28:83:34:54:1b:89:f3:0f:af:37:91:31:ff: + af:31:60:c9:a8:e8:b2:10:68:ed:9f:e7:93:36:f1: + 0a:64:bb:47:f5:04:17:3f:23:47:4d:c5:27:19:81: + 26:0c:54:72:0d:88:2d:d9:1f:9a:12:9f:bc:b3:71: + d3:80:19:3f:47:66:7b:8c:35:28:d2:b9:0a:df:24: + da:9c:d6:50:79:81:7a:5a:d3:37:f7:c2:4a:d8:29: + 92:26:64:d1:e4:98:6c:3a:00:8a:f5:34:9b:65:f8: + ed:e3:10:ff:fd:b8:49:58:dc:a0:de:82:39:6b:81: + b1:16:19:61:b9:54:b6:e6:43 + Exponent: 3 (0x3) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 CRL Distribution Points: + DirName:/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority/CN=CRL1 + URI:http://www.entrust.net/CRL/net1.crl + + X509v3 Private Key Usage Period: + Not Before: May 25 16:09:40 1999 GMT, Not After: May 25 16:09:40 2019 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A + + X509v3 Subject Key Identifier: + F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0 +..V4.0.... + Signature Algorithm: sha1WithRSAEncryption + 90:dc:30:02:fa:64:74:c2:a7:0a:a5:7c:21:8d:34:17:a8:fb: + 47:0e:ff:25:7c:8d:13:0a:fb:e4:98:b5:ef:8c:f8:c5:10:0d: + f7:92:be:f1:c3:d5:d5:95:6a:04:bb:2c:ce:26:36:65:c8:31: + c6:e7:ee:3f:e3:57:75:84:7a:11:ef:46:4f:18:f4:d3:98:bb: + a8:87:32:ba:72:f6:3c:e2:3d:9f:d7:1d:d9:c3:60:43:8c:58: + 0e:22:96:2f:62:a3:2c:1f:ba:ad:05:ef:ab:32:78:87:a0:54: + 73:19:b5:5c:05:f9:52:3e:6d:2d:45:0b:f7:0a:93:ea:ed:06: + f9:b2 + +Equifax Premium CA +================== +MD5 Fingerprint: A9:E9:A8:9D:0E:73:E3:B1:2F:37:0D:E8:48:3F:86:ED +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDIzCCAoygAwIBAgIENeHvHjANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEuMCwGA1UECxMlRXF1aWZheCBQcmVtaXVtIENl +cnRpZmljYXRlIEF1dGhvcml0eTAeFw05ODA4MjQyMjU0MjNaFw0xODA4MjQyMjU0 +MjNaME8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVF +cXVpZmF4IFByZW1pdW0gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDOoQaOBswIC8GGqN4g1Q0O0Q3En+pq2bPCMkdAb4qI +pAm9OCwd5svmpPM269rrvPxkswf2Lbyqzp8ZSGhK/PWiRX4JEPWPs0lcIwY56hOL +uAvNkR12X9k3oUT7X5DyZ7PNGJlDH3YSawLylYM4Q8L2YjTKyXhdX9LYupr/vhBg +WwIDAQABo4IBCjCCAQYwcQYDVR0fBGowaDBmoGSgYqRgMF4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVFcXVpZmF4IFByZW1pdW0gQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIw +MTgwODI0MjI1NDIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUFe6yKFmrbuX4 +z4uB9CThrj91G5gwHQYDVR0OBBYEFBXusihZq27l+M+LgfQk4a4/dRuYMAwGA1Ud +EwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEB +BQUAA4GBAL0LnCepA9so3JipS9DRjqeoGlqR4Jzx9xh8LiKeNh/JqLXNRkpu+jUH +G4YI65/iqPmdQS06rlxctl80BOv8KmCw+3TkhellOJbuFcfGd2MSvYpoH6tsfdrK +XBPO6snrCVzFc+cSAdXZUwee4A+W8Iu0u0VIn4bFGVWgy5bFA/xI +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 903999262 (0x35e1ef1e) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Equifax, OU=Equifax Premium Certificate Authority + Validity + Not Before: Aug 24 22:54:23 1998 GMT + Not After : Aug 24 22:54:23 2018 GMT + Subject: C=US, O=Equifax, OU=Equifax Premium Certificate Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ce:a1:06:8e:06:cc:08:0b:c1:86:a8:de:20:d5: + 0d:0e:d1:0d:c4:9f:ea:6a:d9:b3:c2:32:47:40:6f: + 8a:88:a4:09:bd:38:2c:1d:e6:cb:e6:a4:f3:36:eb: + da:eb:bc:fc:64:b3:07:f6:2d:bc:aa:ce:9f:19:48: + 68:4a:fc:f5:a2:45:7e:09:10:f5:8f:b3:49:5c:23: + 06:39:ea:13:8b:b8:0b:cd:91:1d:76:5f:d9:37:a1: + 44:fb:5f:90:f2:67:b3:cd:18:99:43:1f:76:12:6b: + 02:f2:95:83:38:43:c2:f6:62:34:ca:c9:78:5d:5f: + d2:d8:ba:9a:ff:be:10:60:5b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 CRL Distribution Points: + DirName:/C=US/O=Equifax/OU=Equifax Premium Certificate Authority/CN=CRL1 + + X509v3 Private Key Usage Period: + Not After: Aug 24 22:54:23 2018 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:15:EE:B2:28:59:AB:6E:E5:F8:CF:8B:81:F4:24:E1:AE:3F:75:1B:98 + + X509v3 Subject Key Identifier: + 15:EE:B2:28:59:AB:6E:E5:F8:CF:8B:81:F4:24:E1:AE:3F:75:1B:98 + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0...V3.0c.... + Signature Algorithm: sha1WithRSAEncryption + bd:0b:9c:27:a9:03:db:28:dc:98:a9:4b:d0:d1:8e:a7:a8:1a: + 5a:91:e0:9c:f1:f7:18:7c:2e:22:9e:36:1f:c9:a8:b5:cd:46: + 4a:6e:fa:35:07:1b:86:08:eb:9f:e2:a8:f9:9d:41:2d:3a:ae: + 5c:5c:b6:5f:34:04:eb:fc:2a:60:b0:fb:74:e4:85:e9:65:38: + 96:ee:15:c7:c6:77:63:12:bd:8a:68:1f:ab:6c:7d:da:ca:5c: + 13:ce:ea:c9:eb:09:5c:c5:73:e7:12:01:d5:d9:53:07:9e:e0: + 0f:96:f0:8b:b4:bb:45:48:9f:86:c5:19:55:a0:cb:96:c5:03: + fc:48 + +Equifax Secure CA +================= +MD5 Fingerprint: 67:CB:9D:C0:13:24:8A:82:9B:B2:17:1E:D1:1B:EC:D4 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 903804111 (0x35def4cf) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority + Validity + Not Before: Aug 22 16:41:51 1998 GMT + Not After : Aug 22 16:41:51 2018 GMT + Subject: C=US, O=Equifax, OU=Equifax Secure Certificate Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c1:5d:b1:58:67:08:62:ee:a0:9a:2d:1f:08:6d: + 91:14:68:98:0a:1e:fe:da:04:6f:13:84:62:21:c3: + d1:7c:ce:9f:05:e0:b8:01:f0:4e:34:ec:e2:8a:95: + 04:64:ac:f1:6b:53:5f:05:b3:cb:67:80:bf:42:02: + 8e:fe:dd:01:09:ec:e1:00:14:4f:fc:fb:f0:0c:dd: + 43:ba:5b:2b:e1:1f:80:70:99:15:57:93:16:f1:0f: + 97:6a:b7:c2:68:23:1c:cc:4d:59:30:ac:51:1e:3b: + af:2b:d6:ee:63:45:7b:c5:d9:5f:50:d2:e3:50:0f: + 3a:88:e7:bf:14:fd:e0:c7:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 CRL Distribution Points: + DirName:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority/CN=CRL1 + + X509v3 Private Key Usage Period: + Not After: Aug 22 16:41:51 2018 GMT + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 + + X509v3 Subject Key Identifier: + 48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 + X509v3 Basic Constraints: + CA:TRUE + 1.2.840.113533.7.65.0: + 0...V3.0c.... + Signature Algorithm: sha1WithRSAEncryption + 58:ce:29:ea:fc:f7:de:b5:ce:02:b9:17:b5:85:d1:b9:e3:e0: + 95:cc:25:31:0d:00:a6:92:6e:7f:b6:92:63:9e:50:95:d1:9a: + 6f:e4:11:de:63:85:6e:98:ee:a8:ff:5a:c8:d3:55:b2:66:71: + 57:de:c0:21:eb:3d:2a:a7:23:49:01:04:86:42:7b:fc:ee:7f: + a2:16:52:b5:67:67:d3:40:db:3b:26:58:b2:28:77:3d:ae:14: + 77:61:d6:fa:2a:66:27:a0:0d:fa:a7:73:5c:ea:70:f1:94:21: + 65:44:5f:fa:fc:ef:29:68:a9:a2:87:79:ef:79:ef:4f:ac:07: + 77:38 + +GTE CyberTrust Global Root +========================== +MD5 Fingerprint: CA:3D:D3:68:F1:03:5C:D0:32:FA:B8:2B:59:E8:5A:DB +PEM Data: +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv +bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv +b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds +b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH +iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS +r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 +04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r +GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 +3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P +lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 421 (0x1a5) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root + Validity + Not Before: Aug 13 00:29:00 1998 GMT + Not After : Aug 13 23:59:00 2018 GMT + Subject: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:95:0f:a0:b6:f0:50:9c:e8:7a:c7:88:cd:dd:17: + 0e:2e:b0:94:d0:1b:3d:0e:f6:94:c0:8a:94:c7:06: + c8:90:97:c8:b8:64:1a:7a:7e:6c:3c:53:e1:37:28: + 73:60:7f:b2:97:53:07:9f:53:f9:6d:58:94:d2:af: + 8d:6d:88:67:80:e6:ed:b2:95:cf:72:31:ca:a5:1c: + 72:ba:5c:02:e7:64:42:e7:f9:a9:2c:d6:3a:0d:ac: + 8d:42:aa:24:01:39:e6:9c:3f:01:85:57:0d:58:87: + 45:f8:d3:85:aa:93:69:26:85:70:48:80:3f:12:15: + c7:79:b4:1f:05:2f:3b:62:99 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + 6d:eb:1b:09:e9:5e:d9:51:db:67:22:61:a4:2a:3c:48:77:e3: + a0:7c:a6:de:73:a2:14:03:85:3d:fb:ab:0e:30:c5:83:16:33: + 81:13:08:9e:7b:34:4e:df:40:c8:74:d7:b9:7d:dc:f4:76:55: + 7d:9b:63:54:18:e9:f0:ea:f3:5c:b1:d9:8b:42:1e:b9:c0:95: + 4e:ba:fa:d5:e2:7c:f5:68:61:bf:8e:ec:05:97:5f:5b:b0:d7: + a3:85:34:c4:24:a7:0d:0f:95:93:ef:cb:94:d8:9e:1f:9d:5c: + 85:6d:c7:aa:ae:4f:1f:22:b5:cd:95:ad:ba:a7:cc:f9:ab:0b: + 7a:7f + +GTE CyberTrust Japan Root CA +============================ +MD5 Fingerprint: DE:AB:FF:43:2A:65:37:06:9B:28:B5:7A:E8:84:D3:8E +PEM Data: +-----BEGIN CERTIFICATE----- +MIICETCCAXoCAU4wDQYJKoZIhvcNAQEEBQAwUTELMAkGA1UEBhMCSlAxHzAdBgNV +BAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xITAfBgNVBAMTGEN5YmVyVHJ1c3Qg +SkFQQU4gUm9vdCBDQTAeFw05ODA4MDQwNzU3MDBaFw0wMzA4MDQyMzU5MDBaMFEx +CzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFuLCBJbmMuMSEw +HwYDVQQDExhDeWJlclRydXN0IEpBUEFOIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEB +BQADgY0AMIGJAoGBALet/MpHEHaJ/Wes5HMGfIFLHda1fA5Hr+ymVHWoxP1lr+fI +sbFsNDWN97lkVygLIVredP7ceC6GRhJMfxEf3JO9X75mmIa4t+xtSdOQ2eF5AFZo +uq1sHyw7H8ksjEOwBELqgXOmzjN1RQ2KRXIvqldV5AfDQ+J1Og+8PNCEzrrvAgMB +AAEwDQYJKoZIhvcNAQEEBQADgYEAt6ZkowyAPBzE2O5BO+WGpJ5gXdYBMqhqZC0g +cEC6ck5m+gdlTgOOC/1W4K07IKcy+rISHoDfHuN6GMxX2+bJNGDvdesQFtCkLnDY +JCO4pXdzQvkHOt0BbAiTBzUmECVgKf8J5WSfabkWSfNc3SRjRpMNsFM2dbxIILsZ +to/QIv0= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 78 (0x4e) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=JP, O=CyberTrust Japan, Inc., CN=CyberTrust JAPAN Root CA + Validity + Not Before: Aug 4 07:57:00 1998 GMT + Not After : Aug 4 23:59:00 2003 GMT + Subject: C=JP, O=CyberTrust Japan, Inc., CN=CyberTrust JAPAN Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b7:ad:fc:ca:47:10:76:89:fd:67:ac:e4:73:06: + 7c:81:4b:1d:d6:b5:7c:0e:47:af:ec:a6:54:75:a8: + c4:fd:65:af:e7:c8:b1:b1:6c:34:35:8d:f7:b9:64: + 57:28:0b:21:5a:de:74:fe:dc:78:2e:86:46:12:4c: + 7f:11:1f:dc:93:bd:5f:be:66:98:86:b8:b7:ec:6d: + 49:d3:90:d9:e1:79:00:56:68:ba:ad:6c:1f:2c:3b: + 1f:c9:2c:8c:43:b0:04:42:ea:81:73:a6:ce:33:75: + 45:0d:8a:45:72:2f:aa:57:55:e4:07:c3:43:e2:75: + 3a:0f:bc:3c:d0:84:ce:ba:ef + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + b7:a6:64:a3:0c:80:3c:1c:c4:d8:ee:41:3b:e5:86:a4:9e:60: + 5d:d6:01:32:a8:6a:64:2d:20:70:40:ba:72:4e:66:fa:07:65: + 4e:03:8e:0b:fd:56:e0:ad:3b:20:a7:32:fa:b2:12:1e:80:df: + 1e:e3:7a:18:cc:57:db:e6:c9:34:60:ef:75:eb:10:16:d0:a4: + 2e:70:d8:24:23:b8:a5:77:73:42:f9:07:3a:dd:01:6c:08:93: + 07:35:26:10:25:60:29:ff:09:e5:64:9f:69:b9:16:49:f3:5c: + dd:24:63:46:93:0d:b0:53:36:75:bc:48:20:bb:19:b6:8f:d0: + 22:fd + +GTE CyberTrust Japan Secure Server CA +===================================== +MD5 Fingerprint: DD:0D:0D:B4:78:4B:7D:CE:30:0A:A6:35:C6:AB:4C:88 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICIzCCAYwCAU8wDQYJKoZIhvcNAQEEBQAwWjELMAkGA1UEBhMCSlAxHzAdBgNV +BAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xKjAoBgNVBAMTIUN5YmVyVHJ1c3Qg +SkFQQU4gU2VjdXJlIFNlcnZlciBDQTAeFw05ODA4MDQwODA2MzJaFw0wMzA4MDQy +MzU5MDBaMFoxCzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFu +LCBJbmMuMSowKAYDVQQDEyFDeWJlclRydXN0IEpBUEFOIFNlY3VyZSBTZXJ2ZXIg +Q0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKwmo6G4b2rALBL52zEFkuf9 ++tSBtLjVKtWQ+vBDZfwSFcrs27lh3jNjN0+vADx/kjcbGHPlnzyI8RoTRP558sMm +lQ8L8J4UByFsV8Jdw+JRsM2LX81fhjj4eZc57Oi/Ui6xXqqprozt7tfIty4xi7Q5 +kjt8gScHGgFEL0lzILbJAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAaB17Eu5aeSkx +ygGsi1CpJ5ksAPw4Ghz/wtXwE/4bpzn1gBTrUfrAjXuEG1musTVRbqE+1xvsoJ7f +4KWCluOxP9io8ct5gI738ESZfhT1I6MR42hLBTZuiOOrhqo4UwNCO9O5+eC/BenT +X8NKp7b9t12QSfiasq1mpoIAk65g/yA= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 79 (0x4f) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=JP, O=CyberTrust Japan, Inc., CN=CyberTrust JAPAN Secure Server CA + Validity + Not Before: Aug 4 08:06:32 1998 GMT + Not After : Aug 4 23:59:00 2003 GMT + Subject: C=JP, O=CyberTrust Japan, Inc., CN=CyberTrust JAPAN Secure Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ac:26:a3:a1:b8:6f:6a:c0:2c:12:f9:db:31:05: + 92:e7:fd:fa:d4:81:b4:b8:d5:2a:d5:90:fa:f0:43: + 65:fc:12:15:ca:ec:db:b9:61:de:33:63:37:4f:af: + 00:3c:7f:92:37:1b:18:73:e5:9f:3c:88:f1:1a:13: + 44:fe:79:f2:c3:26:95:0f:0b:f0:9e:14:07:21:6c: + 57:c2:5d:c3:e2:51:b0:cd:8b:5f:cd:5f:86:38:f8: + 79:97:39:ec:e8:bf:52:2e:b1:5e:aa:a9:ae:8c:ed: + ee:d7:c8:b7:2e:31:8b:b4:39:92:3b:7c:81:27:07: + 1a:01:44:2f:49:73:20:b6:c9 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + 68:1d:7b:12:ee:5a:79:29:31:ca:01:ac:8b:50:a9:27:99:2c: + 00:fc:38:1a:1c:ff:c2:d5:f0:13:fe:1b:a7:39:f5:80:14:eb: + 51:fa:c0:8d:7b:84:1b:59:ae:b1:35:51:6e:a1:3e:d7:1b:ec: + a0:9e:df:e0:a5:82:96:e3:b1:3f:d8:a8:f1:cb:79:80:8e:f7: + f0:44:99:7e:14:f5:23:a3:11:e3:68:4b:05:36:6e:88:e3:ab: + 86:aa:38:53:03:42:3b:d3:b9:f9:e0:bf:05:e9:d3:5f:c3:4a: + a7:b6:fd:b7:5d:90:49:f8:9a:b2:ad:66:a6:82:00:93:ae:60: + ff:20 + +GTE CyberTrust Root 2 +===================== +MD5 Fingerprint: BA:ED:17:57:9A:4B:FF:7C:F9:C9:1F:A2:CD:1A:D6:87 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICUDCCAbkCAgGbMA0GCSqGSIb3DQEBBAUAMHAxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv +bHV0aW9ucywgSW5jLjEeMBwGA1UEAxMVR1RFIEN5YmVyVHJ1c3QgUm9vdCAyMB4X +DTk4MDgxMTExMzUwN1oXDTA4MDgxMTExMjIxNlowcDELMAkGA1UEBhMCVVMxGDAW +BgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1c3Qg +U29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290IDIw +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANksTE4vaRoj41a6886EwAnAefFE +XzMfFZF/iogouCRFzI8YzR900bWPcUzWMfZzloSUQMWpg2Akfa9vNLdLTMIJgDtF +BJ7EPMQndXsADKFkR7UUXYJLUTpYu0RMPdPlBjjoYVyYeLuAs5zacoJioN+cX+v5 +T3fCzGAYAGs0giWzAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAo2SRbxDt526iQkCU +eM74FAjR+kOF60bNkhTQ7y4tNjkY2brJJ4gp6UgXb/jBqshhbS39QC11QzCXOfgU +ZL1v72OoK0LfsloNJex7N9jOkSmCFvnoYqLhdsQCfd0li5jh9g1gjPZZkEBRRNHC ++xkkHhc5a3QhFTPWVdeCHnAsJ6g= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 411 (0x19b) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 2 + Validity + Not Before: Aug 11 11:35:07 1998 GMT + Not After : Aug 11 11:22:16 2008 GMT + Subject: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d9:2c:4c:4e:2f:69:1a:23:e3:56:ba:f3:ce:84: + c0:09:c0:79:f1:44:5f:33:1f:15:91:7f:8a:88:28: + b8:24:45:cc:8f:18:cd:1f:74:d1:b5:8f:71:4c:d6: + 31:f6:73:96:84:94:40:c5:a9:83:60:24:7d:af:6f: + 34:b7:4b:4c:c2:09:80:3b:45:04:9e:c4:3c:c4:27: + 75:7b:00:0c:a1:64:47:b5:14:5d:82:4b:51:3a:58: + bb:44:4c:3d:d3:e5:06:38:e8:61:5c:98:78:bb:80: + b3:9c:da:72:82:62:a0:df:9c:5f:eb:f9:4f:77:c2: + cc:60:18:00:6b:34:82:25:b3 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + a3:64:91:6f:10:ed:e7:6e:a2:42:40:94:78:ce:f8:14:08:d1: + fa:43:85:eb:46:cd:92:14:d0:ef:2e:2d:36:39:18:d9:ba:c9: + 27:88:29:e9:48:17:6f:f8:c1:aa:c8:61:6d:2d:fd:40:2d:75: + 43:30:97:39:f8:14:64:bd:6f:ef:63:a8:2b:42:df:b2:5a:0d: + 25:ec:7b:37:d8:ce:91:29:82:16:f9:e8:62:a2:e1:76:c4:02: + 7d:dd:25:8b:98:e1:f6:0d:60:8c:f6:59:90:40:51:44:d1:c2: + fb:19:24:1e:17:39:6b:74:21:15:33:d6:55:d7:82:1e:70:2c: + 27:a8 + +GTE CyberTrust Root 3 +===================== +MD5 Fingerprint: DB:81:96:57:AE:64:61:EF:77:A7:83:C4:51:24:3C:87 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICUDCCAbkCAgGXMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv +bHV0aW9ucywgSW5jLjEeMBwGA1UEAxMVR1RFIEN5YmVyVHJ1c3QgUm9vdCAzMB4X +DTk4MDgxMDE5NTkwOFoXDTA4MDgxMDE5MzYzOVowcDELMAkGA1UEBhMCVVMxGDAW +BgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1c3Qg +U29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290IDMw +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHzsSsLztwU2TSXYlASVmOETFP6 +wIXP+sHdD955E39T+6oOYN3iYr/G7k6ZNKpoQzWZ+KP982O9AVRqnrI6lix7eCjG +WrWNGhUY/eOMLqJQCVtx1g21GB8ZjgQpk5N4q18U53NC8gMMV6IbUDsLu1ngoDoD +7icbWky5sAjKuRqJAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAheutlCAG6bKiazvy +ZuvjS7gSJgXl9JGo3IfcmPSUwfRhvdWcbFFzlV7QvdfmRdw8z0aE1ee57ORnY24A +KHdxXUoF6bl8hszCRLveKUja6t29F58dUQGo6BResVf3/9qPzpX+Le0yEnf/fGph +la4xcgYI8PnzDY7i76hTXZEDg94= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 407 (0x197) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 3 + Validity + Not Before: Aug 10 19:59:08 1998 GMT + Not After : Aug 10 19:36:39 2008 GMT + Subject: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:e1:f3:b1:2b:0b:ce:dc:14:d9:34:97:62:50:12: + 56:63:84:4c:53:fa:c0:85:cf:fa:c1:dd:0f:de:79: + 13:7f:53:fb:aa:0e:60:dd:e2:62:bf:c6:ee:4e:99: + 34:aa:68:43:35:99:f8:a3:fd:f3:63:bd:01:54:6a: + 9e:b2:3a:96:2c:7b:78:28:c6:5a:b5:8d:1a:15:18: + fd:e3:8c:2e:a2:50:09:5b:71:d6:0d:b5:18:1f:19: + 8e:04:29:93:93:78:ab:5f:14:e7:73:42:f2:03:0c: + 57:a2:1b:50:3b:0b:bb:59:e0:a0:3a:03:ee:27:1b: + 5a:4c:b9:b0:08:ca:b9:1a:89 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 85:eb:ad:94:20:06:e9:b2:a2:6b:3b:f2:66:eb:e3:4b:b8:12: + 26:05:e5:f4:91:a8:dc:87:dc:98:f4:94:c1:f4:61:bd:d5:9c: + 6c:51:73:95:5e:d0:bd:d7:e6:45:dc:3c:cf:46:84:d5:e7:b9: + ec:e4:67:63:6e:00:28:77:71:5d:4a:05:e9:b9:7c:86:cc:c2: + 44:bb:de:29:48:da:ea:dd:bd:17:9f:1d:51:01:a8:e8:14:5e: + b1:57:f7:ff:da:8f:ce:95:fe:2d:ed:32:12:77:ff:7c:6a:61: + 95:ae:31:72:06:08:f0:f9:f3:0d:8e:e2:ef:a8:53:5d:91:03: + 83:de + +GTE CyberTrust Root 4 +===================== +MD5 Fingerprint: 33:43:02:B1:B9:E0:73:B1:B1:20:CA:CB:C7:84:03:50 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDVTCCAj0CAgGoMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv +bHV0aW9ucywgSW5jLjEeMBwGA1UEAxMVR1RFIEN5YmVyVHJ1c3QgUm9vdCA0MB4X +DTk4MDgxMzEzNTEwMFoXDTEzMDgxMzIzNTkwMFowcDELMAkGA1UEBhMCVVMxGDAW +BgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1c3Qg +U29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290IDQw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6nSJuf9pmPDlCsaMqb9P3 +vK6sMVrXEZBHuZ0ZLvnzGyKgw+GnusT8XgqUS5haSybkH/Tc8/6OiNxsLXx3hyZQ +wF5OqCih6hdpT03GAQ7amg0GViYVtqRdejWvje14Uob5OKuzAdPaBZaxtlCrwKGu +F1P6QzkgcWUj223Etu2YRYPX0vbiqWv7+XXM78WrcZY16N+OkZuoEHUft84Tjmuz +lneXGpEvxyxpmfAPKmgAmHZEG4wo0uuO9IO0f6QlXmw72cZo1WG41F4xB7VbkDVS +V3sXIO0tuB6OiDk+Usvf8FyxZbulErSQY79xnTLB2r9QSpW+BjrEK+vNmHZETQvl +AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAEOvHIfJSbpliTRJPOoHO0eiedSgO5Bs +3n+oVMPoTEAyvMjsHOXZrEC6/Iw/wnOc9GTq36ntTlvIAWDuOW1DJ/N/qgjS/k5v +FDJNfeQ0gKU1xNZGULQ7oC1lH09lfjQoLcCndn0xyQ0zFvYgGSARULsDzHBtlrfv +TKfaNhXPu03UltyITWyY7blz/ihXoO1k+AqBKXP29pcyhzm0ge/ZTRoHNPe6QjXe +V9xc1vfF6wonDIGmwtBoTv2SW0iD9haKjzZb7TFsP0F6cfeSPzGkCkBM84biYcE8 +SYEtpbjvupcPvCsdm4ny0o4eTYbywqv2LZnAGyoNobZP+SxYTT19Nwo= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 424 (0x1a8) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 4 + Validity + Not Before: Aug 13 13:51:00 1998 GMT + Not After : Aug 13 23:59:00 2013 GMT + Subject: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ba:9d:22:6e:7f:da:66:3c:39:42:b1:a3:2a:6f: + d3:f7:bc:ae:ac:31:5a:d7:11:90:47:b9:9d:19:2e: + f9:f3:1b:22:a0:c3:e1:a7:ba:c4:fc:5e:0a:94:4b: + 98:5a:4b:26:e4:1f:f4:dc:f3:fe:8e:88:dc:6c:2d: + 7c:77:87:26:50:c0:5e:4e:a8:28:a1:ea:17:69:4f: + 4d:c6:01:0e:da:9a:0d:06:56:26:15:b6:a4:5d:7a: + 35:af:8d:ed:78:52:86:f9:38:ab:b3:01:d3:da:05: + 96:b1:b6:50:ab:c0:a1:ae:17:53:fa:43:39:20:71: + 65:23:db:6d:c4:b6:ed:98:45:83:d7:d2:f6:e2:a9: + 6b:fb:f9:75:cc:ef:c5:ab:71:96:35:e8:df:8e:91: + 9b:a8:10:75:1f:b7:ce:13:8e:6b:b3:96:77:97:1a: + 91:2f:c7:2c:69:99:f0:0f:2a:68:00:98:76:44:1b: + 8c:28:d2:eb:8e:f4:83:b4:7f:a4:25:5e:6c:3b:d9: + c6:68:d5:61:b8:d4:5e:31:07:b5:5b:90:35:52:57: + 7b:17:20:ed:2d:b8:1e:8e:88:39:3e:52:cb:df:f0: + 5c:b1:65:bb:a5:12:b4:90:63:bf:71:9d:32:c1:da: + bf:50:4a:95:be:06:3a:c4:2b:eb:cd:98:76:44:4d: + 0b:e5 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 43:af:1c:87:c9:49:ba:65:89:34:49:3c:ea:07:3b:47:a2:79: + d4:a0:3b:90:6c:de:7f:a8:54:c3:e8:4c:40:32:bc:c8:ec:1c: + e5:d9:ac:40:ba:fc:8c:3f:c2:73:9c:f4:64:ea:df:a9:ed:4e: + 5b:c8:01:60:ee:39:6d:43:27:f3:7f:aa:08:d2:fe:4e:6f:14: + 32:4d:7d:e4:34:80:a5:35:c4:d6:46:50:b4:3b:a0:2d:65:1f: + 4f:65:7e:34:28:2d:c0:a7:76:7d:31:c9:0d:33:16:f6:20:19: + 20:11:50:bb:03:cc:70:6d:96:b7:ef:4c:a7:da:36:15:cf:bb: + 4d:d4:96:dc:88:4d:6c:98:ed:b9:73:fe:28:57:a0:ed:64:f8: + 0a:81:29:73:f6:f6:97:32:87:39:b4:81:ef:d9:4d:1a:07:34: + f7:ba:42:35:de:57:dc:5c:d6:f7:c5:eb:0a:27:0c:81:a6:c2: + d0:68:4e:fd:92:5b:48:83:f6:16:8a:8f:36:5b:ed:31:6c:3f: + 41:7a:71:f7:92:3f:31:a4:0a:40:4c:f3:86:e2:61:c1:3c:49: + 81:2d:a5:b8:ef:ba:97:0f:bc:2b:1d:9b:89:f2:d2:8e:1e:4d: + 86:f2:c2:ab:f6:2d:99:c0:1b:2a:0d:a1:b6:4f:f9:2c:58:4d: + 3d:7d:37:0a + +GTE CyberTrust Root 5 +===================== +MD5 Fingerprint: 7D:6C:86:E4:FC:4D:D1:0B:00:BA:22:BB:4E:7C:6A:8E +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgICAbYwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVVMx +GDAWBgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1 +c3QgU29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290 +IDUwHhcNOTgwODE0MTQ1MDAwWhcNMTMwODE0MjM1OTAwWjBwMQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xHjAcBgNVBAMTFUdURSBDeWJlclRydXN0IFJv +b3QgNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwSbj+KfHqXAewe +uzlaAvR4RKJIG457SVJ6uHtHs6+Um2+7lvoramVcuByUc76/iQoigO5X/IwFu3Cf +lzkE2qOHXKjlyq/AM5rVN1xLrOSA0KYjYPv9ci6UncfOwgQy73hgXe2thw9FZR48 +mgqavl0dmezn8tHGehfZrZtUln/EfGC/haoVNR1A2hG87FQhKC0joajwzy3N3fx+ +D17hZQdWywe00lboXjHMGGPEhtIthc+Tkqtt/mg5+95zvYb45EZ66p8My/QZ/mO8 +0Sx7iDM29uThnAxTgWAc2i6rlqkWiBNQmbK9Vd8VMH7o5Zj7cH5stQf8/Ea30O03 +ln4y/iECAwEAAaNaMFgwEgYDVR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMC +AQYwFwYDVR0gBBAwDjAMBgoqhkiG+GMBAgEDMBkGA1UdDgQSBBB2CkkhOEyf3vjE +ScdxcZGdMA0GCSqGSIb3DQEBBQUAA4IBAQBBOtQYW9q43iEc4Y4J5fFoNP/elvQH +9ac886xKsZv6kvqb7eYyIapKdsXcTzjl39WG5NXIdn2Y17HNj021kSNsi4rr6nzv +FJTExvAfSi0ycWMrY5EmAgm2gB3t4sy4f9uHY8jh0GwmsTUdQGYQG82VVBgzYewT +T9oT95mvPtDPjqZyorPDBZrJJ32SzH5SjbOrcG2eiZ9N6xp1wpiq1QIW1wyKvyXk +6y28mOlYOBl8uTf+2+KZCHMGx5eDan0QAS8yuRcFSmXmL86+XlOmgumaUwqEdC2D +ysiUFnZflGEo8IWnObvXi9moshMdVAk0JH0ggX1mfqKQdFwQxr3sqxvC +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 438 (0x1b6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 5 + Validity + Not Before: Aug 14 14:50:00 1998 GMT + Not After : Aug 14 23:59:00 2013 GMT + Subject: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Root 5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:bc:12:6e:3f:8a:7c:7a:97:01:ec:1e:bb:39:5a: + 02:f4:78:44:a2:48:1b:8e:7b:49:52:7a:b8:7b:47: + b3:af:94:9b:6f:bb:96:fa:2b:6a:65:5c:b8:1c:94: + 73:be:bf:89:0a:22:80:ee:57:fc:8c:05:bb:70:9f: + 97:39:04:da:a3:87:5c:a8:e5:ca:af:c0:33:9a:d5: + 37:5c:4b:ac:e4:80:d0:a6:23:60:fb:fd:72:2e:94: + 9d:c7:ce:c2:04:32:ef:78:60:5d:ed:ad:87:0f:45: + 65:1e:3c:9a:0a:9a:be:5d:1d:99:ec:e7:f2:d1:c6: + 7a:17:d9:ad:9b:54:96:7f:c4:7c:60:bf:85:aa:15: + 35:1d:40:da:11:bc:ec:54:21:28:2d:23:a1:a8:f0: + cf:2d:cd:dd:fc:7e:0f:5e:e1:65:07:56:cb:07:b4: + d2:56:e8:5e:31:cc:18:63:c4:86:d2:2d:85:cf:93: + 92:ab:6d:fe:68:39:fb:de:73:bd:86:f8:e4:46:7a: + ea:9f:0c:cb:f4:19:fe:63:bc:d1:2c:7b:88:33:36: + f6:e4:e1:9c:0c:53:81:60:1c:da:2e:ab:96:a9:16: + 88:13:50:99:b2:bd:55:df:15:30:7e:e8:e5:98:fb: + 70:7e:6c:b5:07:fc:fc:46:b7:d0:ed:37:96:7e:32: + fe:21 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:5 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: 1.2.840.113763.1.2.1.3 + + X509v3 Subject Key Identifier: + 76:0A:49:21:38:4C:9F:DE:F8:C4:49:C7:71:71:91:9D + Signature Algorithm: sha1WithRSAEncryption + 41:3a:d4:18:5b:da:b8:de:21:1c:e1:8e:09:e5:f1:68:34:ff: + de:96:f4:07:f5:a7:3c:f3:ac:4a:b1:9b:fa:92:fa:9b:ed:e6: + 32:21:aa:4a:76:c5:dc:4f:38:e5:df:d5:86:e4:d5:c8:76:7d: + 98:d7:b1:cd:8f:4d:b5:91:23:6c:8b:8a:eb:ea:7c:ef:14:94: + c4:c6:f0:1f:4a:2d:32:71:63:2b:63:91:26:02:09:b6:80:1d: + ed:e2:cc:b8:7f:db:87:63:c8:e1:d0:6c:26:b1:35:1d:40:66: + 10:1b:cd:95:54:18:33:61:ec:13:4f:da:13:f7:99:af:3e:d0: + cf:8e:a6:72:a2:b3:c3:05:9a:c9:27:7d:92:cc:7e:52:8d:b3: + ab:70:6d:9e:89:9f:4d:eb:1a:75:c2:98:aa:d5:02:16:d7:0c: + 8a:bf:25:e4:eb:2d:bc:98:e9:58:38:19:7c:b9:37:fe:db:e2: + 99:08:73:06:c7:97:83:6a:7d:10:01:2f:32:b9:17:05:4a:65: + e6:2f:ce:be:5e:53:a6:82:e9:9a:53:0a:84:74:2d:83:ca:c8: + 94:16:76:5f:94:61:28:f0:85:a7:39:bb:d7:8b:d9:a8:b2:13: + 1d:54:09:34:24:7d:20:81:7d:66:7e:a2:90:74:5c:10:c6:bd: + ec:ab:1b:c2 + +GTE CyberTrust Root CA +====================== +MD5 Fingerprint: C4:D7:F0:B2:A3:C5:7D:61:67:F0:04:CD:43:D3:BA:58 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv +b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU +cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv +RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M +ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5 +1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz +dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl +IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy +bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 419 (0x1a3) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, O=GTE Corporation, CN=GTE CyberTrust Root + Validity + Not Before: Feb 23 23:01:00 1996 GMT + Not After : Feb 23 23:59:00 2006 GMT + Subject: C=US, O=GTE Corporation, CN=GTE CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b8:e6:4f:ba:db:98:7c:71:7c:af:44:b7:d3:0f: + 46:d9:64:e5:93:c1:42:8e:c7:ba:49:8d:35:2d:7a: + e7:8b:bd:e5:05:31:59:c6:b1:2f:0a:0c:fb:9f:a7: + 3f:a2:09:66:84:56:1e:37:29:1b:87:e9:7e:0c:ca: + 9a:9f:a5:7f:f5:15:94:a3:d5:a2:46:82:d8:68:4c: + d1:37:15:06:68:af:bd:f8:b0:b3:f0:29:f5:95:5a: + 09:16:61:77:0a:22:25:d4:4f:45:aa:c7:bd:e5:96: + df:f9:d4:a8:8e:42:cc:24:c0:1e:91:27:4a:b5:6d: + 06:80:63:39:c4:a2:5e:38:03 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + 12:b3:75:c6:5f:1d:e1:61:55:80:00:d4:81:4b:7b:31:0f:23: + 63:e7:3d:f3:03:f9:f4:36:a8:bb:d9:e3:a5:97:4d:ea:2b:29: + e0:d6:6a:73:81:e6:c0:89:a3:d3:f1:e0:a5:a5:22:37:9a:63: + c2:48:20:b4:db:72:e3:c8:f6:d9:7c:be:b1:af:53:da:14:b4: + 21:b8:d6:d5:96:e3:fe:4e:0c:59:62:b6:9a:4a:f9:42:dd:8c: + 6f:81:a9:71:ff:f4:0a:72:6d:6d:44:0e:9d:f3:74:74:a8:d5: + 34:49:e9:5e:9e:e9:b4:7a:e1:e5:5a:1f:84:30:9c:d3:9f:a5: + 25:d8 + +GlobalSign Partners CA +====================== +MD5 Fingerprint: 3C:75:CD:4C:BD:A9:D0:8A:79:4F:50:16:37:84:F4:2B +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDnjCCAoagAwIBAgILAgAAAAAA1ni50a8wDQYJKoZIhvcNAQEEBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw +MDBaFw0wOTAxMjgxMjAwMDBaMF8xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRQwEgYDVQQLEwtQYXJ0bmVycyBDQTEfMB0GA1UEAxMWR2xv +YmFsU2lnbiBQYXJ0bmVycyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBANIs+DKsShJ6N8gpkaWujG4eDsA0M4jlM3EWHHiEaMMYNFAuFj6xlIJPsZqf +APjGETXGaXuYAq0ABohs50wzKACIJ0Yfh7NxdWO8MruI3mYYDlAGk7T2vBQ3MD0i +3z3/dX7ZChrFn7P80KyzCHqJ0wHoAFznSgs9TXsmordiBovaRt2TFz8/WwJLC7aI +IBGSAK27xy7U40Wu9YlafI2krYVkMsAnjMbyioCShiRWWY10aKKDQrOePVBBhm8g +bvb9ztMZ4zLMj+2aXm0fKPVSrG4YXvg90ZLlumwBiEsK8i3eZTMFQqBMqjF2vv2/ +gXj5cRxGXi0VlS0wWY5MQdFiqz0CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgAGMB0G +A1UdDgQWBBRDJI1wFQhiVZxPDEAXXYZeD6JM+zAfBgNVHSMEGDAWgBRge2YaRQ2X +yolQL30EzTSo//z9SzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IB +AQBm7bSIaRGZgiGDrKFti5uErQ8tyB6Mynt+rarUjt4H1p5Fx6W4nAc5YCVVGsBP +GeXPFylJiRg1ZuXrKEBOV8mvs+S4IAWjO5VQkUmUKX0s5YhBpUWIXp2CJ/fS71u1 +T5++/jVlLFVkn+FR2iJhd7pYTo/GeVlZbjCAok+QbiELrdBoOZAQm+0iZW8eETjm +f4zS8zltR9Uh6Op1OkHRrfYWnV0LIb3zH2MGJR3BHzVxLOsgGdXBsOw95W/tAgc/ +E3tmktZEwZj3X1CLelvCb22w0fjldKBAN6MlD+Q9ymQxk5BcMHu5OTGaXkzNuUFP +UOQ9OK7IZtnHO11RR6ybq/Kt +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: + 02:00:00:00:00:00:d6:78:b9:d1:af + Signature Algorithm: md5WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Jan 28 12:00:00 1999 GMT + Not After : Jan 28 12:00:00 2009 GMT + Subject: C=BE, O=GlobalSign nv-sa, OU=Partners CA, CN=GlobalSign Partners CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:d2:2c:f8:32:ac:4a:12:7a:37:c8:29:91:a5:ae: + 8c:6e:1e:0e:c0:34:33:88:e5:33:71:16:1c:78:84: + 68:c3:18:34:50:2e:16:3e:b1:94:82:4f:b1:9a:9f: + 00:f8:c6:11:35:c6:69:7b:98:02:ad:00:06:88:6c: + e7:4c:33:28:00:88:27:46:1f:87:b3:71:75:63:bc: + 32:bb:88:de:66:18:0e:50:06:93:b4:f6:bc:14:37: + 30:3d:22:df:3d:ff:75:7e:d9:0a:1a:c5:9f:b3:fc: + d0:ac:b3:08:7a:89:d3:01:e8:00:5c:e7:4a:0b:3d: + 4d:7b:26:a2:b7:62:06:8b:da:46:dd:93:17:3f:3f: + 5b:02:4b:0b:b6:88:20:11:92:00:ad:bb:c7:2e:d4: + e3:45:ae:f5:89:5a:7c:8d:a4:ad:85:64:32:c0:27: + 8c:c6:f2:8a:80:92:86:24:56:59:8d:74:68:a2:83: + 42:b3:9e:3d:50:41:86:6f:20:6e:f6:fd:ce:d3:19: + e3:32:cc:8f:ed:9a:5e:6d:1f:28:f5:52:ac:6e:18: + 5e:f8:3d:d1:92:e5:ba:6c:01:88:4b:0a:f2:2d:de: + 65:33:05:42:a0:4c:aa:31:76:be:fd:bf:81:78:f9: + 71:1c:46:5e:2d:15:95:2d:30:59:8e:4c:41:d1:62: + ab:3d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 43:24:8D:70:15:08:62:55:9C:4F:0C:40:17:5D:86:5E:0F:A2:4C:FB + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 66:ed:b4:88:69:11:99:82:21:83:ac:a1:6d:8b:9b:84:ad:0f: + 2d:c8:1e:8c:ca:7b:7e:ad:aa:d4:8e:de:07:d6:9e:45:c7:a5: + b8:9c:07:39:60:25:55:1a:c0:4f:19:e5:cf:17:29:49:89:18: + 35:66:e5:eb:28:40:4e:57:c9:af:b3:e4:b8:20:05:a3:3b:95: + 50:91:49:94:29:7d:2c:e5:88:41:a5:45:88:5e:9d:82:27:f7: + d2:ef:5b:b5:4f:9f:be:fe:35:65:2c:55:64:9f:e1:51:da:22: + 61:77:ba:58:4e:8f:c6:79:59:59:6e:30:80:a2:4f:90:6e:21: + 0b:ad:d0:68:39:90:10:9b:ed:22:65:6f:1e:11:38:e6:7f:8c: + d2:f3:39:6d:47:d5:21:e8:ea:75:3a:41:d1:ad:f6:16:9d:5d: + 0b:21:bd:f3:1f:63:06:25:1d:c1:1f:35:71:2c:eb:20:19:d5: + c1:b0:ec:3d:e5:6f:ed:02:07:3f:13:7b:66:92:d6:44:c1:98: + f7:5f:50:8b:7a:5b:c2:6f:6d:b0:d1:f8:e5:74:a0:40:37:a3: + 25:0f:e4:3d:ca:64:31:93:90:5c:30:7b:b9:39:31:9a:5e:4c: + cd:b9:41:4f:50:e4:3d:38:ae:c8:66:d9:c7:3b:5d:51:47:ac: + 9b:ab:f2:ad + +GlobalSign Primary Class 1 CA +============================= +MD5 Fingerprint: 5C:AC:59:01:A4:86:53:CB:10:66:B5:D6:D6:71:FF:01 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4N88wDQYJKoZIhvcNAQEEBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MTUxMjAw +MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDEgQ0ExJjAkBgNV +BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAxIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAvSA1R9Eo1gijEjkjRw29cCFSDlcxlaY0V2vsfkN5 +wwZSSM28taGZvdgfMrzP125ybS53IpCCTkuPmgwBQprZcFm2nR/mY9EMrR1O+IWB ++a7vn6ZSYUR5GnVF4GFWRW1CjD1yy6akErea9dZg0GBQs46mpuy09BLNf6jO77Ph +hTD+csTm53eznlhB1lGDiAfGtmlPNt7RC0g/vdafIXRkbycGPkv9Dqabv6RIV4yQ +7okYCwKBGL5n/lNgiCe6o3M0S1pWtN5zBe2Yll3sSudA/EsJYuvQ4zFPhdF6q1ln +K/uID+uqg701/WEn7GYOQlf3acIM7/xqwm5J2o9BOK5IqQIDAQABo2MwYTAOBgNV +HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFPzgZvZaNZnrQB7SuB5DvJiOH4rDMB8GA1Ud +IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQEEBQADggEBAJujCETO8pCdcfMyswVqterPKZjeVT6gFn0GekTWr9L6 +E1iM+BzHqx20G+9paJhcCDmP4Pf7SMwh57gz2wWqNCRsSuXpe2Deg7MfCr5BdfzM +MEi3wSYdBDOqtnjtKsu6VpcybvcxlS5G8hTuJ8f3Yom5XFrTOIpk9Te08bM0ctXV +IT1L13iT1zFmNR6j2EdJbxyt4YB/+JgkbHOsDsIadwKjJge3x2tdvILVKkgdY89Q +Mqb7HBhHFQpbDFw4JJoEmKgISF98NIdjqy2NTAB3lBt2uvUWGKMVry+U9ikAdsEV +F9PpN0121MtLKVkkrNpKoOpj3l9Usfrz0UXLxWS0cyE= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: + 02:00:00:00:00:00:d6:78:b8:37:cf + Signature Algorithm: md5WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Sep 15 12:00:00 1998 GMT + Not After : Jan 28 12:00:00 2009 GMT + Subject: C=BE, O=GlobalSign nv-sa, OU=Primary Class 1 CA, CN=GlobalSign Primary Class 1 CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:bd:20:35:47:d1:28:d6:08:a3:12:39:23:47:0d: + bd:70:21:52:0e:57:31:95:a6:34:57:6b:ec:7e:43: + 79:c3:06:52:48:cd:bc:b5:a1:99:bd:d8:1f:32:bc: + cf:d7:6e:72:6d:2e:77:22:90:82:4e:4b:8f:9a:0c: + 01:42:9a:d9:70:59:b6:9d:1f:e6:63:d1:0c:ad:1d: + 4e:f8:85:81:f9:ae:ef:9f:a6:52:61:44:79:1a:75: + 45:e0:61:56:45:6d:42:8c:3d:72:cb:a6:a4:12:b7: + 9a:f5:d6:60:d0:60:50:b3:8e:a6:a6:ec:b4:f4:12: + cd:7f:a8:ce:ef:b3:e1:85:30:fe:72:c4:e6:e7:77: + b3:9e:58:41:d6:51:83:88:07:c6:b6:69:4f:36:de: + d1:0b:48:3f:bd:d6:9f:21:74:64:6f:27:06:3e:4b: + fd:0e:a6:9b:bf:a4:48:57:8c:90:ee:89:18:0b:02: + 81:18:be:67:fe:53:60:88:27:ba:a3:73:34:4b:5a: + 56:b4:de:73:05:ed:98:96:5d:ec:4a:e7:40:fc:4b: + 09:62:eb:d0:e3:31:4f:85:d1:7a:ab:59:67:2b:fb: + 88:0f:eb:aa:83:bd:35:fd:61:27:ec:66:0e:42:57: + f7:69:c2:0c:ef:fc:6a:c2:6e:49:da:8f:41:38:ae: + 48:a9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + FC:E0:66:F6:5A:35:99:EB:40:1E:D2:B8:1E:43:BC:98:8E:1F:8A:C3 + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 9b:a3:08:44:ce:f2:90:9d:71:f3:32:b3:05:6a:b5:ea:cf:29: + 98:de:55:3e:a0:16:7d:06:7a:44:d6:af:d2:fa:13:58:8c:f8: + 1c:c7:ab:1d:b4:1b:ef:69:68:98:5c:08:39:8f:e0:f7:fb:48: + cc:21:e7:b8:33:db:05:aa:34:24:6c:4a:e5:e9:7b:60:de:83: + b3:1f:0a:be:41:75:fc:cc:30:48:b7:c1:26:1d:04:33:aa:b6: + 78:ed:2a:cb:ba:56:97:32:6e:f7:31:95:2e:46:f2:14:ee:27: + c7:f7:62:89:b9:5c:5a:d3:38:8a:64:f5:37:b4:f1:b3:34:72: + d5:d5:21:3d:4b:d7:78:93:d7:31:66:35:1e:a3:d8:47:49:6f: + 1c:ad:e1:80:7f:f8:98:24:6c:73:ac:0e:c2:1a:77:02:a3:26: + 07:b7:c7:6b:5d:bc:82:d5:2a:48:1d:63:cf:50:32:a6:fb:1c: + 18:47:15:0a:5b:0c:5c:38:24:9a:04:98:a8:08:48:5f:7c:34: + 87:63:ab:2d:8d:4c:00:77:94:1b:76:ba:f5:16:18:a3:15:af: + 2f:94:f6:29:00:76:c1:15:17:d3:e9:37:4d:76:d4:cb:4b:29: + 59:24:ac:da:4a:a0:ea:63:de:5f:54:b1:fa:f3:d1:45:cb:c5: + 64:b4:73:21 + +GlobalSign Primary Class 2 CA +============================= +MD5 Fingerprint: A9:A9:42:59:7E:BE:5A:94:E4:2C:C6:8B:1C:2A:44:B6 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4jY0wDQYJKoZIhvcNAQEEBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw +MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDIgQ0ExJjAkBgNV +BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAyIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAkoz+7/RFjhdBbvzYvyFvqwadUsEsAJ0/joW4f0qP +vaBjKspJJ65agvR04lWS/8LRqnmitvrVnYIET8ayxl5jpzq62O7rim+ftrsoQcAi ++05IGgaS17/Xz7nZvThPOw1EblVB/vwJ29i/844h8egStfYTpdPGTJMisAL/7h0M +xKhrT3VoVujcKBJQ96gknS4kOfsJBd7lo2RJIdBofnEwkbFg4Dn0UPh6TZgAa3x5 +uk7OSuK6Nh23xTYVlZxkQupfxLr1QAW+4TpZvYSnGbjeTVNQzgfR0lHT7w2BbObn +bctdfD98zOxPgycl/3BQ9oNZdYQGZlgs3omNAKZJ+aVDdwIDAQABo2MwYTAOBgNV +HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFHznsrEs3rGna+l2DOGj/U5sx7n2MB8GA1Ud +IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQEEBQADggEBAGPdWc6KeaqYnU7FiWQ3foqTZy8Q6m8nw413bfJcVpQZ +GmlgMEZdj/JtRTyONZd8L7hR4uiJvYjPJxwINFyIwWgk25GF5M/7+0ON6CUBG8QO +9wBCSIYfJAhYWoyN8mtHLGiRsWlC/Q2NySbmkoamZG6Sxc4+PH1x4yOkq8fVqKnf +gqc76IbVw08Y40TQ4NzzxWgu/qUvBYTIfkdCU2uHSv4y/14+cIy3qBXMF8L/RuzQ +7C20bhIoqflA6evUZpdTqWlVwKmqsi7N0Wn0vvi7fGnuVKbbnvtapj7+mu+UUUt1 +7tjU4ZrxAlYTiQ6nQouWi4UMG4W+Jq6rppm8IvFz30I= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: + 02:00:00:00:00:00:d6:78:b8:8d:8d + Signature Algorithm: md5WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Jan 28 12:00:00 1999 GMT + Not After : Jan 28 12:00:00 2009 GMT + Subject: C=BE, O=GlobalSign nv-sa, OU=Primary Class 2 CA, CN=GlobalSign Primary Class 2 CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:92:8c:fe:ef:f4:45:8e:17:41:6e:fc:d8:bf:21: + 6f:ab:06:9d:52:c1:2c:00:9d:3f:8e:85:b8:7f:4a: + 8f:bd:a0:63:2a:ca:49:27:ae:5a:82:f4:74:e2:55: + 92:ff:c2:d1:aa:79:a2:b6:fa:d5:9d:82:04:4f:c6: + b2:c6:5e:63:a7:3a:ba:d8:ee:eb:8a:6f:9f:b6:bb: + 28:41:c0:22:fb:4e:48:1a:06:92:d7:bf:d7:cf:b9: + d9:bd:38:4f:3b:0d:44:6e:55:41:fe:fc:09:db:d8: + bf:f3:8e:21:f1:e8:12:b5:f6:13:a5:d3:c6:4c:93: + 22:b0:02:ff:ee:1d:0c:c4:a8:6b:4f:75:68:56:e8: + dc:28:12:50:f7:a8:24:9d:2e:24:39:fb:09:05:de: + e5:a3:64:49:21:d0:68:7e:71:30:91:b1:60:e0:39: + f4:50:f8:7a:4d:98:00:6b:7c:79:ba:4e:ce:4a:e2: + ba:36:1d:b7:c5:36:15:95:9c:64:42:ea:5f:c4:ba: + f5:40:05:be:e1:3a:59:bd:84:a7:19:b8:de:4d:53: + 50:ce:07:d1:d2:51:d3:ef:0d:81:6c:e6:e7:6d:cb: + 5d:7c:3f:7c:cc:ec:4f:83:27:25:ff:70:50:f6:83: + 59:75:84:06:66:58:2c:de:89:8d:00:a6:49:f9:a5: + 43:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7C:E7:B2:B1:2C:DE:B1:A7:6B:E9:76:0C:E1:A3:FD:4E:6C:C7:B9:F6 + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 63:dd:59:ce:8a:79:aa:98:9d:4e:c5:89:64:37:7e:8a:93:67: + 2f:10:ea:6f:27:c3:8d:77:6d:f2:5c:56:94:19:1a:69:60:30: + 46:5d:8f:f2:6d:45:3c:8e:35:97:7c:2f:b8:51:e2:e8:89:bd: + 88:cf:27:1c:08:34:5c:88:c1:68:24:db:91:85:e4:cf:fb:fb: + 43:8d:e8:25:01:1b:c4:0e:f7:00:42:48:86:1f:24:08:58:5a: + 8c:8d:f2:6b:47:2c:68:91:b1:69:42:fd:0d:8d:c9:26:e6:92: + 86:a6:64:6e:92:c5:ce:3e:3c:7d:71:e3:23:a4:ab:c7:d5:a8: + a9:df:82:a7:3b:e8:86:d5:c3:4f:18:e3:44:d0:e0:dc:f3:c5: + 68:2e:fe:a5:2f:05:84:c8:7e:47:42:53:6b:87:4a:fe:32:ff: + 5e:3e:70:8c:b7:a8:15:cc:17:c2:ff:46:ec:d0:ec:2d:b4:6e: + 12:28:a9:f9:40:e9:eb:d4:66:97:53:a9:69:55:c0:a9:aa:b2: + 2e:cd:d1:69:f4:be:f8:bb:7c:69:ee:54:a6:db:9e:fb:5a:a6: + 3e:fe:9a:ef:94:51:4b:75:ee:d8:d4:e1:9a:f1:02:56:13:89: + 0e:a7:42:8b:96:8b:85:0c:1b:85:be:26:ae:ab:a6:99:bc:22: + f1:73:df:42 + +GlobalSign Primary Class 3 CA +============================= +MD5 Fingerprint: 98:12:A3:4B:95:A9:96:64:94:E7:50:8C:3E:E1:83:5A +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgILAgAAAAAA1ni41sMwDQYJKoZIhvcNAQEEBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw +MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDMgQ0ExJjAkBgNV +BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAzIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAkV5WZdbAwAScv0fEXHt6MQH5WJaZ4xyEL9xWj631 +WYHVQ2ZdWpOMdcqp5xHBURAUYMks1HuvxneGq3onrm+VuQvKtkb7fhr0DRRt0slO +sq7wVPZcQEw2SHToVIxlZhCnvSu3II0FSa14fdIkI1Dj8LR5mwE5/6870y3u4UmN +jS88akFFL5vjPeES5JF1ns+gPjySgW+KLhjc4PKMjP2H2Qf0QJTJTk9D32dWb70D +UHyZZ6S5PJFsAm6E1vxG98xvGD4X8O8LZBZX5qyG8UiqQ8HJJ3hzREXihX26/7Ph ++xsFpEs7mRIlAVAUaq9d6sgM7uTa7EuLXGgTldzDtTA61wIDAQABo2MwYTAOBgNV +HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFMw2zBe0RZEv7c87MEh3+7UUmb7jMB8GA1Ud +IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQEEBQADggEBAFeyVMy9lRdkYIm2U5EMRZLDPahsw8yyGPV4QXTYfaMn +r3cNWT6UHWn6idMMvRoB9D/o4Hcagiha5mLXt+M2yQ6feuPC08xZiQzvFovwNnci +yqS2t8FCZwFAY8znOGSHWxSWZnstFO69SW3/d9DiTlvTgMJND8q4nYGXpzRux+Oc +SOW0qkX19mVMSPISwtKTjMIVJPMrUv/jCK64btYsEs85yxIq56l7X5g9o+HMpmOJ +XH0xdfnV1l3y0NQ9355xqA7c5CCXeOZ/U6QNUU+OOwOuow1aTcN55zVYcELJXqFe +tNkio0RTNaTQz3OAxc+fVph2+RRMd4eCydx+XTTVNnU= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: + 02:00:00:00:00:00:d6:78:b8:d6:c3 + Signature Algorithm: md5WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Jan 28 12:00:00 1999 GMT + Not After : Jan 28 12:00:00 2009 GMT + Subject: C=BE, O=GlobalSign nv-sa, OU=Primary Class 3 CA, CN=GlobalSign Primary Class 3 CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:91:5e:56:65:d6:c0:c0:04:9c:bf:47:c4:5c:7b: + 7a:31:01:f9:58:96:99:e3:1c:84:2f:dc:56:8f:ad: + f5:59:81:d5:43:66:5d:5a:93:8c:75:ca:a9:e7:11: + c1:51:10:14:60:c9:2c:d4:7b:af:c6:77:86:ab:7a: + 27:ae:6f:95:b9:0b:ca:b6:46:fb:7e:1a:f4:0d:14: + 6d:d2:c9:4e:b2:ae:f0:54:f6:5c:40:4c:36:48:74: + e8:54:8c:65:66:10:a7:bd:2b:b7:20:8d:05:49:ad: + 78:7d:d2:24:23:50:e3:f0:b4:79:9b:01:39:ff:af: + 3b:d3:2d:ee:e1:49:8d:8d:2f:3c:6a:41:45:2f:9b: + e3:3d:e1:12:e4:91:75:9e:cf:a0:3e:3c:92:81:6f: + 8a:2e:18:dc:e0:f2:8c:8c:fd:87:d9:07:f4:40:94: + c9:4e:4f:43:df:67:56:6f:bd:03:50:7c:99:67:a4: + b9:3c:91:6c:02:6e:84:d6:fc:46:f7:cc:6f:18:3e: + 17:f0:ef:0b:64:16:57:e6:ac:86:f1:48:aa:43:c1: + c9:27:78:73:44:45:e2:85:7d:ba:ff:b3:e1:fb:1b: + 05:a4:4b:3b:99:12:25:01:50:14:6a:af:5d:ea:c8: + 0c:ee:e4:da:ec:4b:8b:5c:68:13:95:dc:c3:b5:30: + 3a:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + CC:36:CC:17:B4:45:91:2F:ED:CF:3B:30:48:77:FB:B5:14:99:BE:E3 + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 57:b2:54:cc:bd:95:17:64:60:89:b6:53:91:0c:45:92:c3:3d: + a8:6c:c3:cc:b2:18:f5:78:41:74:d8:7d:a3:27:af:77:0d:59: + 3e:94:1d:69:fa:89:d3:0c:bd:1a:01:f4:3f:e8:e0:77:1a:82: + 28:5a:e6:62:d7:b7:e3:36:c9:0e:9f:7a:e3:c2:d3:cc:59:89: + 0c:ef:16:8b:f0:36:77:22:ca:a4:b6:b7:c1:42:67:01:40:63: + cc:e7:38:64:87:5b:14:96:66:7b:2d:14:ee:bd:49:6d:ff:77: + d0:e2:4e:5b:d3:80:c2:4d:0f:ca:b8:9d:81:97:a7:34:6e:c7: + e3:9c:48:e5:b4:aa:45:f5:f6:65:4c:48:f2:12:c2:d2:93:8c: + c2:15:24:f3:2b:52:ff:e3:08:ae:b8:6e:d6:2c:12:cf:39:cb: + 12:2a:e7:a9:7b:5f:98:3d:a3:e1:cc:a6:63:89:5c:7d:31:75: + f9:d5:d6:5d:f2:d0:d4:3d:df:9e:71:a8:0e:dc:e4:20:97:78: + e6:7f:53:a4:0d:51:4f:8e:3b:03:ae:a3:0d:5a:4d:c3:79:e7: + 35:58:70:42:c9:5e:a1:5e:b4:d9:22:a3:44:53:35:a4:d0:cf: + 73:80:c5:cf:9f:56:98:76:f9:14:4c:77:87:82:c9:dc:7e:5d: + 34:d5:36:75 + +GlobalSign Root CA +================== +MD5 Fingerprint: AB:BF:EA:E3:6B:29:A6:CC:A6:78:35:99:EF:AD:2B:80 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU +YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7 +5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q +gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR +rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7 +ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o +Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: + 02:00:00:00:00:00:d6:78:b7:94:05 + Signature Algorithm: md5WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Sep 1 12:00:00 1998 GMT + Not After : Jan 28 12:00:00 2014 GMT + Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:da:0e:e6:99:8d:ce:a3:e3:4f:8a:7e:fb:f1:8b: + 83:25:6b:ea:48:1f:f1:2a:b0:b9:95:11:04:bd:f0: + 63:d1:e2:67:66:cf:1c:dd:cf:1b:48:2b:ee:8d:89: + 8e:9a:af:29:80:65:ab:e9:c7:2d:12:cb:ab:1c:4c: + 70:07:a1:3d:0a:30:cd:15:8d:4f:f8:dd:d4:8c:50: + 15:1c:ef:50:ee:c4:2e:f7:fc:e9:52:f2:91:7d:e0: + 6d:d5:35:30:8e:5e:43:73:f2:41:e9:d5:6a:e3:b2: + 89:3a:56:39:38:6f:06:3c:88:69:5b:2a:4d:c5:a7: + 54:b8:6c:89:cc:9b:f9:3c:ca:e5:fd:89:f5:12:3c: + 92:78:96:d6:dc:74:6e:93:44:61:d1:8d:c7:46:b2: + 75:0e:86:e8:19:8a:d5:6d:6c:d5:78:16:95:a2:e9: + c8:0a:38:eb:f2:24:13:4f:73:54:93:13:85:3a:1b: + bc:1e:34:b5:8b:05:8c:b9:77:8b:b1:db:1f:20:91: + ab:09:53:6e:90:ce:7b:37:74:b9:70:47:91:22:51: + 63:16:79:ae:b1:ae:41:26:08:c8:19:2b:d1:46:aa: + 48:d6:64:2a:d7:83:34:ff:2c:2a:c1:6c:19:43:4a: + 07:85:e7:d3:7c:f6:21:68:ef:ea:f2:52:9f:7f:93: + 90:cf + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + ae:aa:9f:fc:b7:d2:cb:1f:5f:39:29:28:18:9e:34:c9:6c:4f: + 6f:1a:f0:64:a2:70:4a:4f:13:86:9b:60:28:9e:e8:81:49:98: + 7d:0a:bb:e5:b0:9d:3d:36:db:8f:05:51:ff:09:31:2a:1f:dd: + 89:77:9e:0f:2e:6c:95:04:ed:86:cb:b4:00:3f:84:02:4d:80: + 6a:2a:2d:78:0b:ae:6f:2b:a2:83:44:83:1f:cd:50:82:4c:24: + af:bd:f7:a5:b4:c8:5a:0f:f4:e7:47:5e:49:8e:37:96:fe:9a: + 88:05:3a:d9:c0:db:29:87:e6:19:96:47:a7:3a:a6:8c:8b:3c: + 77:fe:46:63:a7:53:da:21:d1:ac:7e:49:a2:4b:e6:c3:67:59: + 2f:b3:8a:0e:bb:2c:bd:a9:aa:42:7c:35:c1:d8:7f:d5:a7:31: + 3a:4e:63:43:39:af:08:b0:61:34:8c:d3:98:a9:43:34:f6:0f: + 87:29:3b:9d:c2:56:58:98:77:c3:f7:1b:ac:f6:9d:f8:3e:aa: + a7:54:45:f0:f5:f9:d5:31:65:fe:6b:58:9c:71:b3:1e:d7:52: + ea:32:17:fc:40:60:1d:c9:79:24:b2:f6:6c:fd:a8:66:0e:82: + dd:98:cb:da:c2:44:4f:2e:a0:7b:f2:f7:6b:2c:76:11:84:46: + 8a:78:a3:e3 + +National Retail Federation by DST +================================= +MD5 Fingerprint: AD:8E:0F:9E:01:6B:A0:C5:74:D5:0C:D3:68:65:4F:1E +PEM Data: +-----BEGIN CERTIFICATE----- +MIIEAjCCAuoCEQDQHkCKAAACfAAAAAMAAAABMA0GCSqGSIb3DQEBBQUAMIG+MQsw +CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp +dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEjMCEGA1UE +CxMaTmF0aW9uYWwgUmV0YWlsIEZlZGVyYXRpb24xGTAXBgNVBAMTEERTVCAoTlJG +KSBSb290Q0ExITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05 +ODEyMTExNjE0MTZaFw0wODEyMDgxNjE0MTZaMIG+MQswCQYDVQQGEwJ1czENMAsG +A1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp +Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEjMCEGA1UECxMaTmF0aW9uYWwgUmV0 +YWlsIEZlZGVyYXRpb24xGTAXBgNVBAMTEERTVCAoTlJGKSBSb290Q0ExITAfBgkq +hkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBANmsm3f6UNPM3LlArLlyagCHI/wPliHQJq/k4rVf+tOmfSEw +LswXgo+YdPxnpKbfiJeiQin1p9sRk/teIzDCqrwi50Eb5e0l3sg/295XRXhARoOy +1Ro93w9FbdVjAnXYL8Zuq5WRdDcNy00JXNHUWzra3Q7Ia5nY1TnM34VVxJJTAqPh +94DJcKPa3DPEf6JHCBw1lh+hAxwwg/TEzP+Yw7BGRKLAv63b0oH2TJgsp14k84bK +Y9W6ffCawErQG1ju7Klnz2kCbCLAYCws0cgg6sgt+92cu8tRTNznVwQ7VJsRpTJ0 +7HQB85AVWy98LJNluWZntIGINeWekRh/gahByMsCAwEAATANBgkqhkiG9w0BAQUF +AAOCAQEAhF4LO+ygjRyb0DwdcWnkGn9kvoFlYcWMatd8AHTgemJV7SR84GHj8t0U +5hFugw7h6qmegK2aIL/gV37V0LWEYy3ZGOS9GzUsXq5hdqpnhTs44TGBHzF/5tf4 +W9K7Y3mGxIzF3gqu19H8AXT/trYNYoFnHLsm+CSA4Fxe2KSKOo99y/+So/18qTJp +B1hYYUKZUgOxOD3GcW9s8uh9BqrBfFPLGi2IT8mpp6xpb/ekH9h0gfVKv7FVt9N3 +OKdvwkrI4nOJ01dy4UMvcjz2H7f4BEpuwemUF+SXF/QOE4ZvjavoXy20/2zWorQf +7LmUaqoSTxrd9Xe1JYzyigrx/FJbWA== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + d0:1e:40:8a:00:00:02:7c:00:00:00:03:00:00:00:01 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=National Retail Federation, CN=DST (NRF) RootCA/Email=ca@digsigtrust.com + Validity + Not Before: Dec 11 16:14:16 1998 GMT + Not After : Dec 8 16:14:16 2008 GMT + Subject: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=National Retail Federation, CN=DST (NRF) RootCA/Email=ca@digsigtrust.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:d9:ac:9b:77:fa:50:d3:cc:dc:b9:40:ac:b9:72: + 6a:00:87:23:fc:0f:96:21:d0:26:af:e4:e2:b5:5f: + fa:d3:a6:7d:21:30:2e:cc:17:82:8f:98:74:fc:67: + a4:a6:df:88:97:a2:42:29:f5:a7:db:11:93:fb:5e: + 23:30:c2:aa:bc:22:e7:41:1b:e5:ed:25:de:c8:3f: + db:de:57:45:78:40:46:83:b2:d5:1a:3d:df:0f:45: + 6d:d5:63:02:75:d8:2f:c6:6e:ab:95:91:74:37:0d: + cb:4d:09:5c:d1:d4:5b:3a:da:dd:0e:c8:6b:99:d8: + d5:39:cc:df:85:55:c4:92:53:02:a3:e1:f7:80:c9: + 70:a3:da:dc:33:c4:7f:a2:47:08:1c:35:96:1f:a1: + 03:1c:30:83:f4:c4:cc:ff:98:c3:b0:46:44:a2:c0: + bf:ad:db:d2:81:f6:4c:98:2c:a7:5e:24:f3:86:ca: + 63:d5:ba:7d:f0:9a:c0:4a:d0:1b:58:ee:ec:a9:67: + cf:69:02:6c:22:c0:60:2c:2c:d1:c8:20:ea:c8:2d: + fb:dd:9c:bb:cb:51:4c:dc:e7:57:04:3b:54:9b:11: + a5:32:74:ec:74:01:f3:90:15:5b:2f:7c:2c:93:65: + b9:66:67:b4:81:88:35:e5:9e:91:18:7f:81:a8:41: + c8:cb + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 84:5e:0b:3b:ec:a0:8d:1c:9b:d0:3c:1d:71:69:e4:1a:7f:64: + be:81:65:61:c5:8c:6a:d7:7c:00:74:e0:7a:62:55:ed:24:7c: + e0:61:e3:f2:dd:14:e6:11:6e:83:0e:e1:ea:a9:9e:80:ad:9a: + 20:bf:e0:57:7e:d5:d0:b5:84:63:2d:d9:18:e4:bd:1b:35:2c: + 5e:ae:61:76:aa:67:85:3b:38:e1:31:81:1f:31:7f:e6:d7:f8: + 5b:d2:bb:63:79:86:c4:8c:c5:de:0a:ae:d7:d1:fc:01:74:ff: + b6:b6:0d:62:81:67:1c:bb:26:f8:24:80:e0:5c:5e:d8:a4:8a: + 3a:8f:7d:cb:ff:92:a3:fd:7c:a9:32:69:07:58:58:61:42:99: + 52:03:b1:38:3d:c6:71:6f:6c:f2:e8:7d:06:aa:c1:7c:53:cb: + 1a:2d:88:4f:c9:a9:a7:ac:69:6f:f7:a4:1f:d8:74:81:f5:4a: + bf:b1:55:b7:d3:77:38:a7:6f:c2:4a:c8:e2:73:89:d3:57:72: + e1:43:2f:72:3c:f6:1f:b7:f8:04:4a:6e:c1:e9:94:17:e4:97: + 17:f4:0e:13:86:6f:8d:ab:e8:5f:2d:b4:ff:6c:d6:a2:b4:1f: + ec:b9:94:6a:aa:12:4f:1a:dd:f5:77:b5:25:8c:f2:8a:0a:f1: + fc:52:5b:58 + +TC TrustCenter, Germany, Class 1 CA +=================================== +MD5 Fingerprint: 64:3F:F8:3E:52:14:4A:59:BA:93:56:04:0B:23:02:D1 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIENTCCA56gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBvDELMAkGA1UEBhMCREUx +EDAOBgNVBAgTB0hhbWJ1cmcxEDAOBgNVBAcTB0hhbWJ1cmcxOjA4BgNVBAoTMVRD +IFRydXN0Q2VudGVyIGZvciBTZWN1cml0eSBpbiBEYXRhIE5ldHdvcmtzIEdtYkgx +IjAgBgNVBAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDEgQ0ExKTAnBgkqhkiG9w0B +CQEWGmNlcnRpZmljYXRlQHRydXN0Y2VudGVyLmRlMB4XDTk4MDMwOTEzNTYzM1oX +DTA1MTIzMTEzNTYzM1owgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQIEwdIYW1idXJn +MRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3Ig +U2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVz +dENlbnRlciBDbGFzcyAxIENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0 +cnVzdGNlbnRlci5kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsCnrtHaz +rte2W7Re573jsZxJBFdboavZfxMb/bphq9jncd8tAJRdUUh9I+91YoSQPAofWRF0 +L46Apf0wAj0pUs1yGkkhnLzLUo5IoWOWyBCFMGlXdEXAWobG1T3gaFd9MWokjUWX +PjF+aGYybiRt7DI2yUHK8DFEyKNhyhugNh8CAwEAAaOCAUMwggE/MEAGCWCGSAGG ++EIBAwQzFjFodHRwczovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL2NoZWNr +LXJldi5jZ2k/MEAGCWCGSAGG+EIBBAQzFjFodHRwczovL3d3dy50cnVzdGNlbnRl +ci5kZS9jZ2ktYmluL2NoZWNrLXJldi5jZ2k/MDwGCWCGSAGG+EIBBwQvFi1odHRw +czovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL1JlbmV3LmNnaT8wPgYJYIZI +AYb4QgEIBDEWL2h0dHA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvZ3VpZGVsaW5lcy9p +bmRleC5odG1sMCgGCWCGSAGG+EIBDQQbFhlUQyBUcnVzdENlbnRlciBDbGFzcyAx +IENBMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQQFAAOBgQAFQlImpAwn +AUSsXCUowkRCVAi5HcU+bFlmxLNOUKf4+JZ1oZZ16BY4oM1dbvp5pxt7HR7DALlm +vlrWYg/n8nu470zgwD9Zrjm3hAmeq/GpLmtp4q3M8up4CQUgOEJxGH7Hspfm1QIF +BlajX/GqwsRP/vfvFg+d7KqFzz0pJPEEzQ== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 1 CA/Email=certificate@trustcenter.de + Validity + Not Before: Mar 9 13:56:33 1998 GMT + Not After : Dec 31 13:56:33 2005 GMT + Subject: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 1 CA/Email=certificate@trustcenter.de + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b0:29:eb:b4:76:b3:ae:d7:b6:5b:b4:5e:e7:bd: + e3:b1:9c:49:04:57:5b:a1:ab:d9:7f:13:1b:fd:ba: + 61:ab:d8:e7:71:df:2d:00:94:5d:51:48:7d:23:ef: + 75:62:84:90:3c:0a:1f:59:11:74:2f:8e:80:a5:fd: + 30:02:3d:29:52:cd:72:1a:49:21:9c:bc:cb:52:8e: + 48:a1:63:96:c8:10:85:30:69:57:74:45:c0:5a:86: + c6:d5:3d:e0:68:57:7d:31:6a:24:8d:45:97:3e:31: + 7e:68:66:32:6e:24:6d:ec:32:36:c9:41:ca:f0:31: + 44:c8:a3:61:ca:1b:a0:36:1f + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape CA Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape Renewal Url: + https://www.trustcenter.de/cgi-bin/Renew.cgi? + Netscape CA Policy Url: + http://www.trustcenter.de/guidelines/index.html + Netscape Comment: + TC TrustCenter Class 1 CA + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Signature Algorithm: md5WithRSAEncryption + 05:42:52:26:a4:0c:27:01:44:ac:5c:25:28:c2:44:42:54:08: + b9:1d:c5:3e:6c:59:66:c4:b3:4e:50:a7:f8:f8:96:75:a1:96: + 75:e8:16:38:a0:cd:5d:6e:fa:79:a7:1b:7b:1d:1e:c3:00:b9: + 66:be:5a:d6:62:0f:e7:f2:7b:b8:ef:4c:e0:c0:3f:59:ae:39: + b7:84:09:9e:ab:f1:a9:2e:6b:69:e2:ad:cc:f2:ea:78:09:05: + 20:38:42:71:18:7e:c7:b2:97:e6:d5:02:05:06:56:a3:5f:f1: + aa:c2:c4:4f:fe:f7:ef:16:0f:9d:ec:aa:85:cf:3d:29:24:f1: + 04:cd + +TC TrustCenter, Germany, Class 2 CA +=================================== +MD5 Fingerprint: E1:E9:96:53:77:E1:F0:38:A0:02:AB:94:C6:95:7B:FC +PEM Data: +-----BEGIN CERTIFICATE----- +MIIENTCCA56gAwIBAgIBAzANBgkqhkiG9w0BAQQFADCBvDELMAkGA1UEBhMCREUx +EDAOBgNVBAgTB0hhbWJ1cmcxEDAOBgNVBAcTB0hhbWJ1cmcxOjA4BgNVBAoTMVRD +IFRydXN0Q2VudGVyIGZvciBTZWN1cml0eSBpbiBEYXRhIE5ldHdvcmtzIEdtYkgx +IjAgBgNVBAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExKTAnBgkqhkiG9w0B +CQEWGmNlcnRpZmljYXRlQHRydXN0Y2VudGVyLmRlMB4XDTk4MDMwOTEzNTc0NFoX +DTA1MTIzMTEzNTc0NFowgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQIEwdIYW1idXJn +MRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3Ig +U2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVz +dENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0 +cnVzdGNlbnRlci5kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2jjo7TIA +KXGDAQ2/jAHc2satOaSpii/Vi1xoX1DGYvVmvcqRIuyqHVHXPbNRsoNOXctJsPBM +VeVrLceFCzAckk6C1MoC7fdvvtzg4xS4BVPymvRWi1qehZPRtIJWrk27qEtXFrz+ ++Fie+CmNsHvNeMlPrItnDPGc+/xXm1dcTw0CAwEAAaOCAUMwggE/MEAGCWCGSAGG ++EIBAwQzFjFodHRwczovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL2NoZWNr +LXJldi5jZ2k/MEAGCWCGSAGG+EIBBAQzFjFodHRwczovL3d3dy50cnVzdGNlbnRl +ci5kZS9jZ2ktYmluL2NoZWNrLXJldi5jZ2k/MDwGCWCGSAGG+EIBBwQvFi1odHRw +czovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL1JlbmV3LmNnaT8wPgYJYIZI +AYb4QgEIBDEWL2h0dHA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvZ3VpZGVsaW5lcy9p +bmRleC5odG1sMCgGCWCGSAGG+EIBDQQbFhlUQyBUcnVzdENlbnRlciBDbGFzcyAy +IENBMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQQFAAOBgQCJG/Tv6Tji +bAz2zW9JzinM+6YP+Y0+lUbW/EcyibLIBmF60ucNEwKUC9mLVkf0u+fFX3v0Y0yu +fDTqDaKpsyyF8+P+J1QQkrCPksGYQhhwSNtOLOsNJGjk0fe+Cakph7vo2tw+o4hC +MfXR43+u2I4AWnSYsE/G/yN7XHMAeMnbTg== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 2 CA/Email=certificate@trustcenter.de + Validity + Not Before: Mar 9 13:57:44 1998 GMT + Not After : Dec 31 13:57:44 2005 GMT + Subject: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 2 CA/Email=certificate@trustcenter.de + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:da:38:e8:ed:32:00:29:71:83:01:0d:bf:8c:01: + dc:da:c6:ad:39:a4:a9:8a:2f:d5:8b:5c:68:5f:50: + c6:62:f5:66:bd:ca:91:22:ec:aa:1d:51:d7:3d:b3: + 51:b2:83:4e:5d:cb:49:b0:f0:4c:55:e5:6b:2d:c7: + 85:0b:30:1c:92:4e:82:d4:ca:02:ed:f7:6f:be:dc: + e0:e3:14:b8:05:53:f2:9a:f4:56:8b:5a:9e:85:93: + d1:b4:82:56:ae:4d:bb:a8:4b:57:16:bc:fe:f8:58: + 9e:f8:29:8d:b0:7b:cd:78:c9:4f:ac:8b:67:0c:f1: + 9c:fb:fc:57:9b:57:5c:4f:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape CA Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape Renewal Url: + https://www.trustcenter.de/cgi-bin/Renew.cgi? + Netscape CA Policy Url: + http://www.trustcenter.de/guidelines/index.html + Netscape Comment: + TC TrustCenter Class 2 CA + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Signature Algorithm: md5WithRSAEncryption + 89:1b:f4:ef:e9:38:e2:6c:0c:f6:cd:6f:49:ce:29:cc:fb:a6: + 0f:f9:8d:3e:95:46:d6:fc:47:32:89:b2:c8:06:61:7a:d2:e7: + 0d:13:02:94:0b:d9:8b:56:47:f4:bb:e7:c5:5f:7b:f4:63:4c: + ae:7c:34:ea:0d:a2:a9:b3:2c:85:f3:e3:fe:27:54:10:92:b0: + 8f:92:c1:98:42:18:70:48:db:4e:2c:eb:0d:24:68:e4:d1:f7: + be:09:a9:29:87:bb:e8:da:dc:3e:a3:88:42:31:f5:d1:e3:7f: + ae:d8:8e:00:5a:74:98:b0:4f:c6:ff:23:7b:5c:73:00:78:c9: + db:4e + +TC TrustCenter, Germany, Class 3 CA +=================================== +MD5 Fingerprint: 62:AB:B6:15:4A:B4:B0:16:77:FF:AE:CF:16:16:2B:8C +PEM Data: +-----BEGIN CERTIFICATE----- +MIIENTCCA56gAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBvDELMAkGA1UEBhMCREUx +EDAOBgNVBAgTB0hhbWJ1cmcxEDAOBgNVBAcTB0hhbWJ1cmcxOjA4BgNVBAoTMVRD +IFRydXN0Q2VudGVyIGZvciBTZWN1cml0eSBpbiBEYXRhIE5ldHdvcmtzIEdtYkgx +IjAgBgNVBAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExKTAnBgkqhkiG9w0B +CQEWGmNlcnRpZmljYXRlQHRydXN0Y2VudGVyLmRlMB4XDTk4MDMwOTEzNTg0OVoX +DTA1MTIzMTEzNTg0OVowgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQIEwdIYW1idXJn +MRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3Ig +U2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVz +dENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0 +cnVzdGNlbnRlci5kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtrTBNQUu +DY3soEBqHA4nplCSa1AbB94u53bM4Nr8hKhejGNqK03ZTgJ2EcEL8o15ygC28bAO +1/ukFz2vq2l6lie/rzOhmipZqsS1NwjyEqUxtkP1MpZxKCirjSiG37vu4wx9MNbD +UquPXSeca8Cj5wVrV0lEs27qZM/SjnpQd3cCAwEAAaOCAUMwggE/MEAGCWCGSAGG ++EIBAwQzFjFodHRwczovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL2NoZWNr +LXJldi5jZ2k/MEAGCWCGSAGG+EIBBAQzFjFodHRwczovL3d3dy50cnVzdGNlbnRl +ci5kZS9jZ2ktYmluL2NoZWNrLXJldi5jZ2k/MDwGCWCGSAGG+EIBBwQvFi1odHRw +czovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL1JlbmV3LmNnaT8wPgYJYIZI +AYb4QgEIBDEWL2h0dHA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvZ3VpZGVsaW5lcy9p +bmRleC5odG1sMCgGCWCGSAGG+EIBDQQbFhlUQyBUcnVzdENlbnRlciBDbGFzcyAz +IENBMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQQFAAOBgQCEhlBieaAn +4SW6CbE0DxMJ7S3Ko+aV+TCszRelzj2Xnex8jyZ/wGHKIveR3Tw2WZqbdfe85Mjt +7AK2IqfzLPHIknhttu7FKOyAIE+5awjnL6eGHn2xCJ9UuQA3PKDYGsiWHPQyFJw5 +lbfu8ENJwl7oy3lvU7/7SYos2EvZVfIScA== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 4 (0x4) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 3 CA/Email=certificate@trustcenter.de + Validity + Not Before: Mar 9 13:58:49 1998 GMT + Not After : Dec 31 13:58:49 2005 GMT + Subject: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 3 CA/Email=certificate@trustcenter.de + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b6:b4:c1:35:05:2e:0d:8d:ec:a0:40:6a:1c:0e: + 27:a6:50:92:6b:50:1b:07:de:2e:e7:76:cc:e0:da: + fc:84:a8:5e:8c:63:6a:2b:4d:d9:4e:02:76:11:c1: + 0b:f2:8d:79:ca:00:b6:f1:b0:0e:d7:fb:a4:17:3d: + af:ab:69:7a:96:27:bf:af:33:a1:9a:2a:59:aa:c4: + b5:37:08:f2:12:a5:31:b6:43:f5:32:96:71:28:28: + ab:8d:28:86:df:bb:ee:e3:0c:7d:30:d6:c3:52:ab: + 8f:5d:27:9c:6b:c0:a3:e7:05:6b:57:49:44:b3:6e: + ea:64:cf:d2:8e:7a:50:77:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape CA Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape Renewal Url: + https://www.trustcenter.de/cgi-bin/Renew.cgi? + Netscape CA Policy Url: + http://www.trustcenter.de/guidelines/index.html + Netscape Comment: + TC TrustCenter Class 3 CA + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Signature Algorithm: md5WithRSAEncryption + 84:86:50:62:79:a0:27:e1:25:ba:09:b1:34:0f:13:09:ed:2d: + ca:a3:e6:95:f9:30:ac:cd:17:a5:ce:3d:97:9d:ec:7c:8f:26: + 7f:c0:61:ca:22:f7:91:dd:3c:36:59:9a:9b:75:f7:bc:e4:c8: + ed:ec:02:b6:22:a7:f3:2c:f1:c8:92:78:6d:b6:ee:c5:28:ec: + 80:20:4f:b9:6b:08:e7:2f:a7:86:1e:7d:b1:08:9f:54:b9:00: + 37:3c:a0:d8:1a:c8:96:1c:f4:32:14:9c:39:95:b7:ee:f0:43: + 49:c2:5e:e8:cb:79:6f:53:bf:fb:49:8a:2c:d8:4b:d9:55:f2: + 12:70 + +TC TrustCenter, Germany, Class 4 CA +=================================== +MD5 Fingerprint: BF:AF:EC:C4:DA:F9:30:F9:CA:35:CA:25:E4:3F:8D:89 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIENTCCA56gAwIBAgIBBTANBgkqhkiG9w0BAQQFADCBvDELMAkGA1UEBhMCREUx +EDAOBgNVBAgTB0hhbWJ1cmcxEDAOBgNVBAcTB0hhbWJ1cmcxOjA4BgNVBAoTMVRD +IFRydXN0Q2VudGVyIGZvciBTZWN1cml0eSBpbiBEYXRhIE5ldHdvcmtzIEdtYkgx +IjAgBgNVBAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExKTAnBgkqhkiG9w0B +CQEWGmNlcnRpZmljYXRlQHRydXN0Y2VudGVyLmRlMB4XDTk4MDMwOTE0MDAyMFoX +DTA1MTIzMTE0MDAyMFowgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQIEwdIYW1idXJn +MRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3Ig +U2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVz +dENlbnRlciBDbGFzcyA0IENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0 +cnVzdGNlbnRlci5kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvy9j1jZ7 +sg3TVfVkbOYlXca0yBS6JTiD61ZipVWpZaP0I5nCS7nQzVRnpqOgo6kzK3bkva13 +su1cEnTDxbYPUppyk0OQYmYVD0Wl3eDduG9AblfBeXKjYKq6dh0SiVNa/AK+4QkT +xUov3D2LGa3XiyRF+0z0zVw1HSlMUfPybFUCAwEAAaOCAUMwggE/MEAGCWCGSAGG ++EIBAwQzFjFodHRwczovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL2NoZWNr +LXJldi5jZ2k/MEAGCWCGSAGG+EIBBAQzFjFodHRwczovL3d3dy50cnVzdGNlbnRl +ci5kZS9jZ2ktYmluL2NoZWNrLXJldi5jZ2k/MDwGCWCGSAGG+EIBBwQvFi1odHRw +czovL3d3dy50cnVzdGNlbnRlci5kZS9jZ2ktYmluL1JlbmV3LmNnaT8wPgYJYIZI +AYb4QgEIBDEWL2h0dHA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvZ3VpZGVsaW5lcy9p +bmRleC5odG1sMCgGCWCGSAGG+EIBDQQbFhlUQyBUcnVzdENlbnRlciBDbGFzcyA0 +IENBMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQQFAAOBgQCUaBQbJZ4p +mbGyI9JEs5Wf0Z5VBN3jL4IzVZZ3GZ0rnmUc+orjx48l/LEeVUYPj/9PNy+kdlmm +ZOvVFnC93ZUzDKQNJOtkULRDEfJDvg1xmCLsAa/s98dcccN1kVgZ6N2g9LTxvBBK +85O0Bkm7H2bSvXRH4Zr569erbR+64R0s2g== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 4 CA/Email=certificate@trustcenter.de + Validity + Not Before: Mar 9 14:00:20 1998 GMT + Not After : Dec 31 14:00:20 2005 GMT + Subject: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 4 CA/Email=certificate@trustcenter.de + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:bf:2f:63:d6:36:7b:b2:0d:d3:55:f5:64:6c:e6: + 25:5d:c6:b4:c8:14:ba:25:38:83:eb:56:62:a5:55: + a9:65:a3:f4:23:99:c2:4b:b9:d0:cd:54:67:a6:a3: + a0:a3:a9:33:2b:76:e4:bd:ad:77:b2:ed:5c:12:74: + c3:c5:b6:0f:52:9a:72:93:43:90:62:66:15:0f:45: + a5:dd:e0:dd:b8:6f:40:6e:57:c1:79:72:a3:60:aa: + ba:76:1d:12:89:53:5a:fc:02:be:e1:09:13:c5:4a: + 2f:dc:3d:8b:19:ad:d7:8b:24:45:fb:4c:f4:cd:5c: + 35:1d:29:4c:51:f3:f2:6c:55 + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape CA Revocation Url: + https://www.trustcenter.de/cgi-bin/check-rev.cgi? + Netscape Renewal Url: + https://www.trustcenter.de/cgi-bin/Renew.cgi? + Netscape CA Policy Url: + http://www.trustcenter.de/guidelines/index.html + Netscape Comment: + TC TrustCenter Class 4 CA + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Signature Algorithm: md5WithRSAEncryption + 94:68:14:1b:25:9e:29:99:b1:b2:23:d2:44:b3:95:9f:d1:9e: + 55:04:dd:e3:2f:82:33:55:96:77:19:9d:2b:9e:65:1c:fa:8a: + e3:c7:8f:25:fc:b1:1e:55:46:0f:8f:ff:4f:37:2f:a4:76:59: + a6:64:eb:d5:16:70:bd:dd:95:33:0c:a4:0d:24:eb:64:50:b4: + 43:11:f2:43:be:0d:71:98:22:ec:01:af:ec:f7:c7:5c:71:c3: + 75:91:58:19:e8:dd:a0:f4:b4:f1:bc:10:4a:f3:93:b4:06:49: + bb:1f:66:d2:bd:74:47:e1:9a:f9:eb:d7:ab:6d:1f:ba:e1:1d: + 2c:da + +Thawte Personal Basic CA +======================== +MD5 Fingerprint: E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD +VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT +ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj +IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X +DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw +EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE +ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy +dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD +QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53 +dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK +wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7 +G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF +AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 +c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P +9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Basic CA/Email=personal-basic@thawte.com + Validity + Not Before: Jan 1 00:00:00 1996 GMT + Not After : Dec 31 23:59:59 2020 GMT + Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Basic CA/Email=personal-basic@thawte.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:bc:bc:93:53:6d:c0:50:4f:82:15:e6:48:94:35: + a6:5a:be:6f:42:fa:0f:47:ee:77:75:72:dd:8d:49: + 9b:96:57:a0:78:d4:ca:3f:51:b3:69:0b:91:76:17: + 22:07:97:6a:c4:51:93:4b:e0:8d:ef:37:95:a1:0c: + 4d:da:34:90:1d:17:89:97:e0:35:38:57:4a:c0:f4: + 08:70:e9:3c:44:7b:50:7e:61:9a:90:e3:23:d3:88: + 11:46:27:f5:0b:07:0e:bb:dd:d1:7f:20:0a:88:b9: + 56:0b:2e:1c:80:da:f1:e3:9e:29:ef:14:bd:0a:44: + fb:1b:5b:18:d1:bf:23:93:21 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 2d:e2:99:6b:b0:3d:7a:89:d7:59:a2:94:01:1f:2b:dd:12:4b: + 53:c2:ad:7f:aa:a7:00:5c:91:40:57:25:4a:38:aa:84:70:b9: + d9:80:0f:a5:7b:5c:fb:73:c6:bd:d7:8a:61:5c:03:e3:2d:27: + a8:17:e0:84:85:42:dc:5e:9b:c6:b7:b2:6d:bb:74:af:e4:3f: + cb:a7:b7:b0:e0:5d:be:78:83:25:94:d2:db:81:0f:79:07:6d: + 4f:f4:39:15:5a:52:01:7b:de:32:d6:4d:38:f6:12:5c:06:50: + df:05:5b:bd:14:4b:a1:df:29:ba:3b:41:8d:f7:63:56:a1:df: + 22:b1 + +Thawte Personal Freemail CA +=========================== +MD5 Fingerprint: 1E:74:C3:86:3C:0C:35:C5:3E:C2:7F:EF:3C:AA:3C:D9 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD +VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT +ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt +YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu +Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa +MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp +b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG +cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh +d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY +DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E +rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq +uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN +BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP +MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa +/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei +gQ== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Freemail CA/Email=personal-freemail@thawte.com + Validity + Not Before: Jan 1 00:00:00 1996 GMT + Not After : Dec 31 23:59:59 2020 GMT + Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Freemail CA/Email=personal-freemail@thawte.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d4:69:d7:d4:b0:94:64:5b:71:e9:47:d8:0c:51: + b6:ea:72:91:b0:84:5e:7d:2d:0d:8f:7b:12:df:85: + 25:75:28:74:3a:42:2c:63:27:9f:95:7b:4b:ef:7e: + 19:87:1d:86:ea:a3:dd:b9:ce:96:64:1a:c2:14:6e: + 44:ac:7c:e6:8f:e8:4d:0f:71:1f:40:38:a6:00:a3: + 87:78:f6:f9:94:86:5e:ad:ea:c0:5e:76:eb:d9:14: + a3:5d:6e:7a:7c:0c:a5:4b:55:7f:06:19:29:7f:9e: + 9a:26:d5:6a:bb:38:24:08:6a:98:c7:b1:da:a3:98: + 91:fd:79:db:e5:5a:c4:1c:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + c7:ec:92:7e:4e:f8:f5:96:a5:67:62:2a:a4:f0:4d:11:60:d0: + 6f:8d:60:58:61:ac:26:bb:52:35:5c:08:cf:30:fb:a8:4a:96: + 8a:1f:62:42:23:8c:17:0f:f4:ba:64:9c:17:ac:47:29:df:9d: + 98:5e:d2:6c:60:71:5c:a2:ac:dc:79:e3:e7:6e:00:47:1f:b5: + 0d:28:e8:02:9d:e4:9a:fd:13:f4:a6:d9:7c:b1:f8:dc:5f:23: + 26:09:91:80:73:d0:14:1b:de:43:a9:83:25:f2:e6:9c:2f:15: + ca:fe:a6:ab:8a:07:75:8b:0c:dd:51:84:6b:e4:f8:d1:ce:77: + a2:81 + +Thawte Personal Premium CA +========================== +MD5 Fingerprint: 3A:B2:DE:22:9A:20:93:49:F9:ED:C8:D2:8A:E7:68:0D +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD +VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT +ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p +dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv +bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa +QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY +BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u +IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl +bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu +Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs +Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI +Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD +ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH +b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh +KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Premium CA/Email=personal-premium@thawte.com + Validity + Not Before: Jan 1 00:00:00 1996 GMT + Not After : Dec 31 23:59:59 2020 GMT + Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Premium CA/Email=personal-premium@thawte.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c9:66:d9:f8:07:44:cf:b9:8c:2e:f0:a1:ef:13: + 45:6c:05:df:de:27:16:51:36:41:11:6c:6c:3b:ed: + fe:10:7d:12:9e:e5:9b:42:9a:fe:60:31:c3:66:b7: + 73:3a:48:ae:4e:d0:32:37:94:88:b5:0d:b6:d9:f3: + f2:44:d9:d5:88:12:dd:76:4d:f2:1a:fc:6f:23:1e: + 7a:f1:d8:98:45:4e:07:10:ef:16:42:d0:43:75:6d: + 4a:de:e2:aa:c9:31:ff:1f:00:70:7c:66:cf:10:25: + 08:ba:fa:ee:00:e9:46:03:66:27:11:15:3b:aa:5b: + f2:98:dd:36:42:b2:da:88:75 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 69:36:89:f7:34:2a:33:72:2f:6d:3b:d4:22:b2:b8:6f:9a:c5: + 36:66:0e:1b:3c:a1:b1:75:5a:e6:fd:35:d3:f8:a8:f2:07:6f: + 85:67:8e:de:2b:b9:e2:17:b0:3a:a0:f0:0e:a2:00:9a:df:f3: + 14:15:6e:bb:c8:85:5a:98:80:f9:ff:be:74:1d:3d:f3:fe:30: + 25:d1:37:34:67:fa:a5:71:79:30:61:29:72:c0:e0:2c:4c:fb: + 56:e4:3a:a8:6f:e5:32:59:52:db:75:28:50:59:0c:f8:0b:19: + e4:ac:d9:af:96:8d:2f:50:db:07:c3:ea:1f:ab:33:e0:f5:2b: + 31:89 + +Thawte Premium Server CA +======================== +MD5 Fingerprint: 06:9F:69:79:16:66:90:02:1B:8C:8C:A2:C3:07:6F:3A +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD +VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy +dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t +MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB +MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG +A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp +b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl +cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv +bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE +VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ +ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR +uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI +hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM +pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/Email=premium-server@thawte.com + Validity + Not Before: Aug 1 00:00:00 1996 GMT + Not After : Dec 31 23:59:59 2020 GMT + Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/Email=premium-server@thawte.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d2:36:36:6a:8b:d7:c2:5b:9e:da:81:41:62:8f: + 38:ee:49:04:55:d6:d0:ef:1c:1b:95:16:47:ef:18: + 48:35:3a:52:f4:2b:6a:06:8f:3b:2f:ea:56:e3:af: + 86:8d:9e:17:f7:9e:b4:65:75:02:4d:ef:cb:09:a2: + 21:51:d8:9b:d0:67:d0:ba:0d:92:06:14:73:d4:93: + cb:97:2a:00:9c:5c:4e:0c:bc:fa:15:52:fc:f2:44: + 6e:da:11:4a:6e:08:9f:2f:2d:e3:f9:aa:3a:86:73: + b6:46:53:58:c8:89:05:bd:83:11:b8:73:3f:aa:07: + 8d:f4:42:4d:e7:40:9d:1c:37 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 26:48:2c:16:c2:58:fa:e8:16:74:0c:aa:aa:5f:54:3f:f2:d7: + c9:78:60:5e:5e:6e:37:63:22:77:36:7e:b2:17:c4:34:b9:f5: + 08:85:fc:c9:01:38:ff:4d:be:f2:16:42:43:e7:bb:5a:46:fb: + c1:c6:11:1f:f1:4a:b0:28:46:c9:c3:c4:42:7d:bc:fa:ab:59: + 6e:d5:b7:51:88:11:e3:a4:85:19:6b:82:4c:a4:0c:12:ad:e9: + a4:ae:3f:f1:c3:49:65:9a:8c:c5:c8:3e:25:b7:94:99:bb:92: + 32:71:07:f0:86:5e:ed:50:27:a6:0d:a6:23:f9:bb:cb:a6:07: + 14:42 + +Thawte Server CA +================ +MD5 Fingerprint: C5:70:C4:A2:ED:53:78:0C:C8:10:53:81:64:CB:D0:1D +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD +VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm +MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx +MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 +dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl +cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 +DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 +yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX +L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj +EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG +7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e +QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ +qdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/Email=server-certs@thawte.com + Validity + Not Before: Aug 1 00:00:00 1996 GMT + Not After : Dec 31 23:59:59 2020 GMT + Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/Email=server-certs@thawte.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d3:a4:50:6e:c8:ff:56:6b:e6:cf:5d:b6:ea:0c: + 68:75:47:a2:aa:c2:da:84:25:fc:a8:f4:47:51:da: + 85:b5:20:74:94:86:1e:0f:75:c9:e9:08:61:f5:06: + 6d:30:6e:15:19:02:e9:52:c0:62:db:4d:99:9e:e2: + 6a:0c:44:38:cd:fe:be:e3:64:09:70:c5:fe:b1:6b: + 29:b6:2f:49:c8:3b:d4:27:04:25:10:97:2f:e7:90: + 6d:c0:28:42:99:d7:4c:43:de:c3:f5:21:6d:54:9f: + 5d:c3:58:e1:c0:e4:d9:5b:b0:b8:dc:b4:7b:df:36: + 3a:c2:b5:66:22:12:d6:87:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 07:fa:4c:69:5c:fb:95:cc:46:ee:85:83:4d:21:30:8e:ca:d9: + a8:6f:49:1a:e6:da:51:e3:60:70:6c:84:61:11:a1:1a:c8:48: + 3e:59:43:7d:4f:95:3d:a1:8b:b7:0b:62:98:7a:75:8a:dd:88: + 4e:4e:9e:40:db:a8:cc:32:74:b9:6f:0d:c6:e3:b3:44:0b:d9: + 8a:6f:9a:29:9b:99:18:28:3b:d1:e3:40:28:9a:5a:3c:d5:b5: + e7:20:1b:8b:ca:a4:ab:8d:e9:51:d9:e2:4c:2c:59:a9:da:b9: + b2:75:1b:f6:42:f2:ef:c7:f2:18:f9:89:bc:a3:ff:8a:23:2e: + 70:47 + +Thawte Universal CA Root +======================== +MD5 Fingerprint: 17:AF:71:16:52:7B:73:65:22:05:29:28:84:71:9D:13 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIRIjCCCQoCAQAwDQYJKoZIhvcNAQEFBQAwVzEPMA0GA1UEChMGVGhhd3RlMSEw +HwYDVQQLExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3QxITAfBgNVBAMTGFRoYXd0 +ZSBVbml2ZXJzYWwgQ0EgUm9vdDAeFw05OTEyMDUxMzU2MDVaFw0zNzA0MDMxMzU2 +MDVaMFcxDzANBgNVBAoTBlRoYXd0ZTEhMB8GA1UECxMYVGhhd3RlIFVuaXZlcnNh +bCBDQSBSb290MSEwHwYDVQQDExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3Qwgggi +MA0GCSqGSIb3DQEBAQUAA4IIDwAwgggKAoIIAQDiiQVtw3+tpok6/7vHzZ03seHS +IR6bYSoV53tXT1U80Lv52T0+przstK1TmhYC6wty/Yryj0QFxevT5b22RDnm+0e/ +ap4KlRjiaOLWltYhrYj99Rf109pCpZDtKZWWdTrah6HU9dOH3gVipuNmdJLPpby7 +32j/cXVWQVk16zNaZlHy0qMKwYzOc1wRby2MlYyRsf3P5a1WlcyFkoOQVUHJwnft ++aN0QgpoCPPQ0WX9Zyw0/yR/53nIBzslV92kDJg9vuDMGWXb8lSir0LUneKuhCMl +CTMStWoedsSL2UkAbF66H/Ib2mfKJ6qjRCMbg4LO8qsz7VSk3MmrWWXROA7BPhtn +j9Z1AeBVIt12d+yO3fTPeSJtuVcD9ZkIpzw+NPvEF64jWM0k8yPKagIolAGBNLRs +a66LGsOj0gk8FlT1Nl8k459KoeJkxhbDpoF6JDZHjsFeDvv5FXgE1g5Z2Z1YZmLS +lCkyMsh4uWb2tVbhbMYUS5ZSWZECJGpVR9c/tiMaYHeXLuJAr54EV56tEcXJQ3Dv +SLRerBxpLi6C1VuLvoK+GRRe5w0ix1Eb/x6b8TCPcTEGszQnj196ZoJPii0Tq0LP +IVael45mNg+Wm+Ur9AKpKmqMLMTDuHAsLSkeP1B3Hm0qVORVCpE4ocW1ZqJ2Wu4P +v7Rn4ShuD+E2oYLRv9R34cRnMpN4yOdUU/4jeeZozCaQ9hBjXSpvkS2kczJRIfK7 +Fd+qJAhIBt6hnia/uoO/fKTIoIy90v+8hGknEyQYxEUYIyZeGBTKLoiHYqNT5iG3 +uIV7moW7FSZy+Ln3anQPST+SvqkFt5knv78JF0uZTK0REHzfdDH2jyZfqoiuOFfI +VS3T+9gbUZm+JRs6usB9G+3O0km5z/PFfYmQgdhpSCAQo/jvklEYMosRGMA/G4VW +zlfJ8oJkxt8CCS5KES+xJ203UvDwFmHxZ43fh3Kvh9rP+1CUbtSUheuKLOoh9ZZK +RNXgzmp0RE3QBdOHFe020KSLZlVwk+5HBsF+LqUYeWfzKIXxcPcOg6R+VJ5adjLL +ZRu4zfvIKAPSVJHRp8WFQwgXdqXmL2cI2KGigi0M+MGvY9RQd21rRkpBhdWQX3kt +xOzXEYdAiuFo4mT4VTL7b5Ms2nfZIcEX5TYsTn6Qf6yUKzJnvjhQdriuQbnXIcUJ +TGDIo1HENJtXN9/LyTNXi+v7dp8ZTcVqHypFrivtL42npQDLBPolYi50SBvKKoy6 +27Z+9rsCfKnD21h4ob/w/hoQVRHO6GlOlmXGFwPWB2iMVIKuHCJVP/H0CZcowEb3 +TgslHfcH1wkdOhhXODvoMwbnj3hGHlv1BrbsuKYN8boTS9YYIN1pM0ozFa64yJiK +JyyTvC377jO/ZuZNurabBlVgl0u8RM1+9KHYqi/AAighFmJ42whU8vz0NOPGjxxD +V86QGkvcLjsokYk/eto1HY4s7kns9DOtyVOojJ8EUz4kHFLJEvliV6O87izrQHwg +I3ArlflzF4rRwRxpprc4mmf3cB16WgxAz2IPhTzCAk5+tfbFKimEsx83KuGqckLE +7Wsaj5IcXb7R8lvyq6qp0vW4pEErK5FuEkjKmNg3jcjtADC1tgROfpzahOzA+nvl +HYikU0awlORcG6ElLA9IUneXCWzsWxgzgwLlgn7NhSEwEf0nT8/kHuw/pVds6Sow +GSqI5cNpOKtvOXF/hOFBw+HMKokgUi6DD2w5P0stFqwt8CSsAHP0m7MGPwW4FIUf +q55cPJ5inQ5tO4AJ/ALqopd0ysf541bhw8qlpprAkOAkElPSwovavu0CQ15n4YmY +ee7LqsrDG9znpUalfGsWh7ZaKNfbJzxepb22Ud0fQ887Jsg6jSVhwUn0PBvJROqv +HMIrlAEqDjDRW4srR+XD0QQDmw45LNYn1OZwWtl1zyrYyQAF5BOI7MM5+4dhMDZD +A8ienKIGwi/F/PCAY7FUBKBMqS7G9XZ62NDk1JQR5RW1eAbcuICPmakgMz0QhUxl +Cco+WF5gk5qqYl3AUQYcXWCgDZxLQ/anFiGkh6rywS7ukjC4nt/fEAGLhglw2Gyo +t1AeFpa092f9NTohkCoyxwB7TQcQCbkvc9gYfmeZBE8G/FDHhZudQJ2zljf6pdyy +ck7vTgks/ZH9Tfe7pqE+q3uiA0CmqVUn4vr5Gc6HdarxdTbz87iR+JHDi3UTjkxl +mhY5auU06HqWWX81sAD9W2n8Qyb69Shu/ofZfiT7tKCCblSi/66/YrT0cgHCy5hH +mOFMtReAgM6PpijuHkVq+9/xHfxaO9bq9GwdYklXO4qPhurwUwTOnBZo/7q5/IgP +R/cCRHJAuMo7LVOd3DxWjFl7aBosjXG7bADHGs5vQJKxoy8P2UTyo3Aunu4OrjLQ +Oz6LB+rmebNcKeJ9a6he+Vox6AiWoowDmEbxuH2QVCbtdmL+numabl7JScdcNFMp +VNns5EbhgDt12d/7edWH8bqe6xnOTFJz5luHriVPOXnMxrj5EHvs8JtxpAWg0ynT +Tn8f9C0oeMxVlXsekS/MVhhzi7LbvGkH5tDYT+2i/1iFo23gSlO3Z32NDFxbe3co +AjVEegTTKEPIazAXXTK4KTW6dto7FEp2GFik+JI8nk0zb0ZrCNkxSGjd9PskVjSy +z2lmvkjSimYizfJpzcJTE0UpQSLWXZgftqSyo8LuAi9RG9yDpOxwJajUCGEyb+Sh +gS58Y3L6KWW8cETPXQIDAQABMA0GCSqGSIb3DQEBBQUAA4IIAQBVmjRqIgZpCUUz +x66pXMcJTpuGvEGQ1JRS9s0jKZRLIs3ovf6dzVLyve2rh8mrq0YEtL2iPyIwR1DA +S4x2DwP1ktKxLcR6NZzJc4frpp/eD3ON03+Z2LqPb8Tzvhqui6KUNpDi5euNBfT8 +Zd+V8cSUTRdW1588j1A853e/lYYmZPtq/8ba6YyuQrtp5TPG2OkNxlUhScEMtKP5 +m0tc3oNPQQPOKnloOH3wVEkg9bYQ/wjcM2aWm/8G3gCe185WQ5pR/HDN9vBRo7fN +tFyFYs1xt8YrIyvdw25AQvo3/zcc9npXlIeFI9fUycdfwU0vyQ3XXOycJe6eMIKR +lnK4dR34CWhXl7ItS+4l7HokKe5y1JwT26vcAwrYShTJCFdEXaG1U4A08hSXz1Le +og6KEOkU79BgvmGh8SVd1RhzP5MQypbus0DS26NVz1dapQ5PdUff6veQmm31cC4d +FBw3ZARZULDccoZvnDc9XSivc1Xv0u4kdHQT79zbMUn7P2P10wg+M6XnnQreUyxR +jmfbm0FlQVC91KSWbIe8EuCUx9PA5MtzWACD4awnhdadU51cvQo+A0OcDJH1bXv4 +QHJ1qxF2kSvhxqofcGl2cBUJ/pPQ1i23FWqbZ1y0aZ8lpn2K+30iqXHyzk6MuCEt +3v5BcQ3/nexzprsHT4gOWEcufqnCx3jdunqeTuAwTmNvhdQgQen6/kNF5/uverLO +pAUdIppYht/kzkyp/tgWpW/72M5We/XWIO/kR81jJP+5vvFIo8EBcua9wK3tJg3K +NJ/8Ai0gTwUgriE9DMIgPD/wBITcz4n9uSWRjtBD5rMgq1wt1UCeoEvY9LLMffFY +Co6H7YisNpbkVqARivKa0LNXozS7Gas44XRrIsQxzgHVGzbjHjhMM5PfQONZV06s +bnseWj3FHVusyBCCNQIisvx16BCRjcR9eJNHnhydrGtiAliM1hwj1q94woCcpKok +VBS1FJjG+CsaJMtxMgrimw5pa91+jGTRLmPvDn+xPohMnVXlyW4XBLdB/72KQcsl +MW9Edz9HsfyBiAeOBUkgtxHZaQMqA525M4Sa399640Zzo9iijFMZiFVMdLj2RIQr +0RQtTjkukmj/afyFYhvrVU/vJYRiRZnW2E5vP1MIfR0GlYGAf09OdDaYteKHcJjc +1/XcUhXmxtZ5ljl/j5XPq4BTrRsLRUAO1Bi9LN6Kd3b98kRHxiHQ5HTw2BgFyHww +csff8bv8AjCp9EImWQ2TBYKhc+005ThdzVCQ/pT8E7y9/KiiiKdzxLKo0V2IxAKi +evEEyf6MdMnvHWRBn6welmdkrKsoQced98CYG24HwmR9WoNmVig2nOf7HHcOKKDE +92t5OQQghMdXk7wboOq860LlqBH+/KxlzP34KIj0pZrlc1HgqJsNA3dO5eCYs4ja +febGnnwUZsEuU0qSBzegfuk9CeQVfM/9uEGl755mncReBx2H+EGt6ucv0kFjGDf5 +FONN0OX3Q/0V4/k2cwYm3wFPqcNO3iBGd5i0eiQrO3UrTliNm12kxxagvDKIP6GD +8wDI+NhY6WNdTCu18HJB2Kt3N9ZydK62NpzIpoNJS+DJVgspvgAwy93WyEKKANns +FdE0cfJbZIf2J9K364awkL8p2yGeNozjIC+VI1FsG8Kk1ebYAkNnoP6bUANEf7vk +ctXR5NqPkhRk+10UEBJKlQbJZQgpyiGjJjgRySffcGcE/cpIMn9jskV0MVBPh9kg +cNIhcLHWEJ0zXXiDkW1Vguza5GJjx4FG1xllcipDGZC41yNNTBzgRKlmZ6zucXkn +Jnhtcg71XUsjtXx8ZekXxjoLDd1eHlHDhrjsf8cnSqVG6GotGcGHo8uZk4dkolUU +TLdDpZPX59JOeUDKZZlGPT96gHqIaswe5WszRvRQwNUfCbjNii6hJ+tdc6foawrl +V4IqsPziVFJW8KupEsYjlgcknOC8RqW0IATaCZNj5dQuwn7FMe21FXSGF7mz8yaK +HQJq2ho/6LrxBG2UUVTiWrRZgx1g0C1zzAe1Joz518aIke+Az10PoWDLRdRCItGx +cB390LcwkDrGSG1n5TLaj9vjqOMdICWiHOFMuaT2xj9cWA27xrJ3ARaRnxcGDbdA +PsyPjpxL4J1+mx4Fq4gi+tMoG1cUZEo+JCw4TSFpAHMu0FUtdPIV6JRDPkAqxsa5 +alveoswYUFRdTiqFbPaSiykZfufqSuAiKyW892bPd5pBdPI8FA10afVQg83NLyHb +IkaK0PdRGpVX8gWLGhntO0XoNsJufvtXIgAfBlOprpPGj3EqMUWS545t5pkiwIP8 +79xXZndPojYx+6ETjeXKo5V9AQxkcDtTQmiAx7udqAA1aZgMqGfYQ+Wqz5XgUZWk +Fz9CnbgEztN5ecjTihYykuDXou7XN0wvrLh7vkX28RgznHs3piTZvECrAOnDN4ur +2LbzXoFOsBRrBz4f7ML2RCKVu7Pmb9b5cGW6CoNlqg4TL4MTI1OLQBb6zi/8TQT4 +69isxTbCFVdIOOxVs7Qeuq3SQgYXDXPIV6a+lk2p8sD7eiEc9clwqYKQtfEM1HkQ +voGm6VxhnHd5mqTDNyZXN8lSLPoI/9BfxmHA9Ha+/N5Oz6tRmXHH33701s8GVhkT +UwttdFlIGZtTBS2dMlTT5SxTi2Q+1GR744AJFMz+FkZja3Fp+PnLJ/aIVLxFs84C +yJTuQFv5QgLC/7DYLOsof17JJgGZpw== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Thawte, OU=Thawte Universal CA Root, CN=Thawte Universal CA Root + Validity + Not Before: Dec 5 13:56:05 1999 GMT + Not After : Apr 3 13:56:05 2037 GMT + Subject: O=Thawte, OU=Thawte Universal CA Root, CN=Thawte Universal CA Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (16384 bit) + Modulus (16384 bit): + 00:e2:89:05:6d:c3:7f:ad:a6:89:3a:ff:bb:c7:cd: + 9d:37:b1:e1:d2:21:1e:9b:61:2a:15:e7:7b:57:4f: + 55:3c:d0:bb:f9:d9:3d:3e:a6:bc:ec:b4:ad:53:9a: + 16:02:eb:0b:72:fd:8a:f2:8f:44:05:c5:eb:d3:e5: + bd:b6:44:39:e6:fb:47:bf:6a:9e:0a:95:18:e2:68: + e2:d6:96:d6:21:ad:88:fd:f5:17:f5:d3:da:42:a5: + 90:ed:29:95:96:75:3a:da:87:a1:d4:f5:d3:87:de: + 05:62:a6:e3:66:74:92:cf:a5:bc:bb:df:68:ff:71: + 75:56:41:59:35:eb:33:5a:66:51:f2:d2:a3:0a:c1: + 8c:ce:73:5c:11:6f:2d:8c:95:8c:91:b1:fd:cf:e5: + ad:56:95:cc:85:92:83:90:55:41:c9:c2:77:ed:f9: + a3:74:42:0a:68:08:f3:d0:d1:65:fd:67:2c:34:ff: + 24:7f:e7:79:c8:07:3b:25:57:dd:a4:0c:98:3d:be: + e0:cc:19:65:db:f2:54:a2:af:42:d4:9d:e2:ae:84: + 23:25:09:33:12:b5:6a:1e:76:c4:8b:d9:49:00:6c: + 5e:ba:1f:f2:1b:da:67:ca:27:aa:a3:44:23:1b:83: + 82:ce:f2:ab:33:ed:54:a4:dc:c9:ab:59:65:d1:38: + 0e:c1:3e:1b:67:8f:d6:75:01:e0:55:22:dd:76:77: + ec:8e:dd:f4:cf:79:22:6d:b9:57:03:f5:99:08:a7: + 3c:3e:34:fb:c4:17:ae:23:58:cd:24:f3:23:ca:6a: + 02:28:94:01:81:34:b4:6c:6b:ae:8b:1a:c3:a3:d2: + 09:3c:16:54:f5:36:5f:24:e3:9f:4a:a1:e2:64:c6: + 16:c3:a6:81:7a:24:36:47:8e:c1:5e:0e:fb:f9:15: + 78:04:d6:0e:59:d9:9d:58:66:62:d2:94:29:32:32: + c8:78:b9:66:f6:b5:56:e1:6c:c6:14:4b:96:52:59: + 91:02:24:6a:55:47:d7:3f:b6:23:1a:60:77:97:2e: + e2:40:af:9e:04:57:9e:ad:11:c5:c9:43:70:ef:48: + b4:5e:ac:1c:69:2e:2e:82:d5:5b:8b:be:82:be:19: + 14:5e:e7:0d:22:c7:51:1b:ff:1e:9b:f1:30:8f:71: + 31:06:b3:34:27:8f:5f:7a:66:82:4f:8a:2d:13:ab: + 42:cf:21:56:9e:97:8e:66:36:0f:96:9b:e5:2b:f4: + 02:a9:2a:6a:8c:2c:c4:c3:b8:70:2c:2d:29:1e:3f: + 50:77:1e:6d:2a:54:e4:55:0a:91:38:a1:c5:b5:66: + a2:76:5a:ee:0f:bf:b4:67:e1:28:6e:0f:e1:36:a1: + 82:d1:bf:d4:77:e1:c4:67:32:93:78:c8:e7:54:53: + fe:23:79:e6:68:cc:26:90:f6:10:63:5d:2a:6f:91: + 2d:a4:73:32:51:21:f2:bb:15:df:aa:24:08:48:06: + de:a1:9e:26:bf:ba:83:bf:7c:a4:c8:a0:8c:bd:d2: + ff:bc:84:69:27:13:24:18:c4:45:18:23:26:5e:18: + 14:ca:2e:88:87:62:a3:53:e6:21:b7:b8:85:7b:9a: + 85:bb:15:26:72:f8:b9:f7:6a:74:0f:49:3f:92:be: + a9:05:b7:99:27:bf:bf:09:17:4b:99:4c:ad:11:10: + 7c:df:74:31:f6:8f:26:5f:aa:88:ae:38:57:c8:55: + 2d:d3:fb:d8:1b:51:99:be:25:1b:3a:ba:c0:7d:1b: + ed:ce:d2:49:b9:cf:f3:c5:7d:89:90:81:d8:69:48: + 20:10:a3:f8:ef:92:51:18:32:8b:11:18:c0:3f:1b: + 85:56:ce:57:c9:f2:82:64:c6:df:02:09:2e:4a:11: + 2f:b1:27:6d:37:52:f0:f0:16:61:f1:67:8d:df:87: + 72:af:87:da:cf:fb:50:94:6e:d4:94:85:eb:8a:2c: + ea:21:f5:96:4a:44:d5:e0:ce:6a:74:44:4d:d0:05: + d3:87:15:ed:36:d0:a4:8b:66:55:70:93:ee:47:06: + c1:7e:2e:a5:18:79:67:f3:28:85:f1:70:f7:0e:83: + a4:7e:54:9e:5a:76:32:cb:65:1b:b8:cd:fb:c8:28: + 03:d2:54:91:d1:a7:c5:85:43:08:17:76:a5:e6:2f: + 67:08:d8:a1:a2:82:2d:0c:f8:c1:af:63:d4:50:77: + 6d:6b:46:4a:41:85:d5:90:5f:79:2d:c4:ec:d7:11: + 87:40:8a:e1:68:e2:64:f8:55:32:fb:6f:93:2c:da: + 77:d9:21:c1:17:e5:36:2c:4e:7e:90:7f:ac:94:2b: + 32:67:be:38:50:76:b8:ae:41:b9:d7:21:c5:09:4c: + 60:c8:a3:51:c4:34:9b:57:37:df:cb:c9:33:57:8b: + eb:fb:76:9f:19:4d:c5:6a:1f:2a:45:ae:2b:ed:2f: + 8d:a7:a5:00:cb:04:fa:25:62:2e:74:48:1b:ca:2a: + 8c:ba:db:b6:7e:f6:bb:02:7c:a9:c3:db:58:78:a1: + bf:f0:fe:1a:10:55:11:ce:e8:69:4e:96:65:c6:17: + 03:d6:07:68:8c:54:82:ae:1c:22:55:3f:f1:f4:09: + 97:28:c0:46:f7:4e:0b:25:1d:f7:07:d7:09:1d:3a: + 18:57:38:3b:e8:33:06:e7:8f:78:46:1e:5b:f5:06: + b6:ec:b8:a6:0d:f1:ba:13:4b:d6:18:20:dd:69:33: + 4a:33:15:ae:b8:c8:98:8a:27:2c:93:bc:2d:fb:ee: + 33:bf:66:e6:4d:ba:b6:9b:06:55:60:97:4b:bc:44: + cd:7e:f4:a1:d8:aa:2f:c0:02:28:21:16:62:78:db: + 08:54:f2:fc:f4:34:e3:c6:8f:1c:43:57:ce:90:1a: + 4b:dc:2e:3b:28:91:89:3f:7a:da:35:1d:8e:2c:ee: + 49:ec:f4:33:ad:c9:53:a8:8c:9f:04:53:3e:24:1c: + 52:c9:12:f9:62:57:a3:bc:ee:2c:eb:40:7c:20:23: + 70:2b:95:f9:73:17:8a:d1:c1:1c:69:a6:b7:38:9a: + 67:f7:70:1d:7a:5a:0c:40:cf:62:0f:85:3c:c2:02: + 4e:7e:b5:f6:c5:2a:29:84:b3:1f:37:2a:e1:aa:72: + 42:c4:ed:6b:1a:8f:92:1c:5d:be:d1:f2:5b:f2:ab: + aa:a9:d2:f5:b8:a4:41:2b:2b:91:6e:12:48:ca:98: + d8:37:8d:c8:ed:00:30:b5:b6:04:4e:7e:9c:da:84: + ec:c0:fa:7b:e5:1d:88:a4:53:46:b0:94:e4:5c:1b: + a1:25:2c:0f:48:52:77:97:09:6c:ec:5b:18:33:83: + 02:e5:82:7e:cd:85:21:30:11:fd:27:4f:cf:e4:1e: + ec:3f:a5:57:6c:e9:2a:30:19:2a:88:e5:c3:69:38: + ab:6f:39:71:7f:84:e1:41:c3:e1:cc:2a:89:20:52: + 2e:83:0f:6c:39:3f:4b:2d:16:ac:2d:f0:24:ac:00: + 73:f4:9b:b3:06:3f:05:b8:14:85:1f:ab:9e:5c:3c: + 9e:62:9d:0e:6d:3b:80:09:fc:02:ea:a2:97:74:ca: + c7:f9:e3:56:e1:c3:ca:a5:a6:9a:c0:90:e0:24:12: + 53:d2:c2:8b:da:be:ed:02:43:5e:67:e1:89:98:79: + ee:cb:aa:ca:c3:1b:dc:e7:a5:46:a5:7c:6b:16:87: + b6:5a:28:d7:db:27:3c:5e:a5:bd:b6:51:dd:1f:43: + cf:3b:26:c8:3a:8d:25:61:c1:49:f4:3c:1b:c9:44: + ea:af:1c:c2:2b:94:01:2a:0e:30:d1:5b:8b:2b:47: + e5:c3:d1:04:03:9b:0e:39:2c:d6:27:d4:e6:70:5a: + d9:75:cf:2a:d8:c9:00:05:e4:13:88:ec:c3:39:fb: + 87:61:30:36:43:03:c8:9e:9c:a2:06:c2:2f:c5:fc: + f0:80:63:b1:54:04:a0:4c:a9:2e:c6:f5:76:7a:d8: + d0:e4:d4:94:11:e5:15:b5:78:06:dc:b8:80:8f:99: + a9:20:33:3d:10:85:4c:65:09:ca:3e:58:5e:60:93: + 9a:aa:62:5d:c0:51:06:1c:5d:60:a0:0d:9c:4b:43: + f6:a7:16:21:a4:87:aa:f2:c1:2e:ee:92:30:b8:9e: + df:df:10:01:8b:86:09:70:d8:6c:a8:b7:50:1e:16: + 96:b4:f7:67:fd:35:3a:21:90:2a:32:c7:00:7b:4d: + 07:10:09:b9:2f:73:d8:18:7e:67:99:04:4f:06:fc: + 50:c7:85:9b:9d:40:9d:b3:96:37:fa:a5:dc:b2:72: + 4e:ef:4e:09:2c:fd:91:fd:4d:f7:bb:a6:a1:3e:ab: + 7b:a2:03:40:a6:a9:55:27:e2:fa:f9:19:ce:87:75: + aa:f1:75:36:f3:f3:b8:91:f8:91:c3:8b:75:13:8e: + 4c:65:9a:16:39:6a:e5:34:e8:7a:96:59:7f:35:b0: + 00:fd:5b:69:fc:43:26:fa:f5:28:6e:fe:87:d9:7e: + 24:fb:b4:a0:82:6e:54:a2:ff:ae:bf:62:b4:f4:72: + 01:c2:cb:98:47:98:e1:4c:b5:17:80:80:ce:8f:a6: + 28:ee:1e:45:6a:fb:df:f1:1d:fc:5a:3b:d6:ea:f4: + 6c:1d:62:49:57:3b:8a:8f:86:ea:f0:53:04:ce:9c: + 16:68:ff:ba:b9:fc:88:0f:47:f7:02:44:72:40:b8: + ca:3b:2d:53:9d:dc:3c:56:8c:59:7b:68:1a:2c:8d: + 71:bb:6c:00:c7:1a:ce:6f:40:92:b1:a3:2f:0f:d9: + 44:f2:a3:70:2e:9e:ee:0e:ae:32:d0:3b:3e:8b:07: + ea:e6:79:b3:5c:29:e2:7d:6b:a8:5e:f9:5a:31:e8: + 08:96:a2:8c:03:98:46:f1:b8:7d:90:54:26:ed:76: + 62:fe:9e:e9:9a:6e:5e:c9:49:c7:5c:34:53:29:54: + d9:ec:e4:46:e1:80:3b:75:d9:df:fb:79:d5:87:f1: + ba:9e:eb:19:ce:4c:52:73:e6:5b:87:ae:25:4f:39: + 79:cc:c6:b8:f9:10:7b:ec:f0:9b:71:a4:05:a0:d3: + 29:d3:4e:7f:1f:f4:2d:28:78:cc:55:95:7b:1e:91: + 2f:cc:56:18:73:8b:b2:db:bc:69:07:e6:d0:d8:4f: + ed:a2:ff:58:85:a3:6d:e0:4a:53:b7:67:7d:8d:0c: + 5c:5b:7b:77:28:02:35:44:7a:04:d3:28:43:c8:6b: + 30:17:5d:32:b8:29:35:ba:76:da:3b:14:4a:76:18: + 58:a4:f8:92:3c:9e:4d:33:6f:46:6b:08:d9:31:48: + 68:dd:f4:fb:24:56:34:b2:cf:69:66:be:48:d2:8a: + 66:22:cd:f2:69:cd:c2:53:13:45:29:41:22:d6:5d: + 98:1f:b6:a4:b2:a3:c2:ee:02:2f:51:1b:dc:83:a4: + ec:70:25:a8:d4:08:61:32:6f:e4:a1:81:2e:7c:63: + 72:fa:29:65:bc:70:44:cf:5d + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 55:9a:34:6a:22:06:69:09:45:33:c7:ae:a9:5c:c7:09:4e:9b: + 86:bc:41:90:d4:94:52:f6:cd:23:29:94:4b:22:cd:e8:bd:fe: + 9d:cd:52:f2:bd:ed:ab:87:c9:ab:ab:46:04:b4:bd:a2:3f:22: + 30:47:50:c0:4b:8c:76:0f:03:f5:92:d2:b1:2d:c4:7a:35:9c: + c9:73:87:eb:a6:9f:de:0f:73:8d:d3:7f:99:d8:ba:8f:6f:c4: + f3:be:1a:ae:8b:a2:94:36:90:e2:e5:eb:8d:05:f4:fc:65:df: + 95:f1:c4:94:4d:17:56:d7:9f:3c:8f:50:3c:e7:77:bf:95:86: + 26:64:fb:6a:ff:c6:da:e9:8c:ae:42:bb:69:e5:33:c6:d8:e9: + 0d:c6:55:21:49:c1:0c:b4:a3:f9:9b:4b:5c:de:83:4f:41:03: + ce:2a:79:68:38:7d:f0:54:49:20:f5:b6:10:ff:08:dc:33:66: + 96:9b:ff:06:de:00:9e:d7:ce:56:43:9a:51:fc:70:cd:f6:f0: + 51:a3:b7:cd:b4:5c:85:62:cd:71:b7:c6:2b:23:2b:dd:c3:6e: + 40:42:fa:37:ff:37:1c:f6:7a:57:94:87:85:23:d7:d4:c9:c7: + 5f:c1:4d:2f:c9:0d:d7:5c:ec:9c:25:ee:9e:30:82:91:96:72: + b8:75:1d:f8:09:68:57:97:b2:2d:4b:ee:25:ec:7a:24:29:ee: + 72:d4:9c:13:db:ab:dc:03:0a:d8:4a:14:c9:08:57:44:5d:a1: + b5:53:80:34:f2:14:97:cf:52:de:a2:0e:8a:10:e9:14:ef:d0: + 60:be:61:a1:f1:25:5d:d5:18:73:3f:93:10:ca:96:ee:b3:40: + d2:db:a3:55:cf:57:5a:a5:0e:4f:75:47:df:ea:f7:90:9a:6d: + f5:70:2e:1d:14:1c:37:64:04:59:50:b0:dc:72:86:6f:9c:37: + 3d:5d:28:af:73:55:ef:d2:ee:24:74:74:13:ef:dc:db:31:49: + fb:3f:63:f5:d3:08:3e:33:a5:e7:9d:0a:de:53:2c:51:8e:67: + db:9b:41:65:41:50:bd:d4:a4:96:6c:87:bc:12:e0:94:c7:d3: + c0:e4:cb:73:58:00:83:e1:ac:27:85:d6:9d:53:9d:5c:bd:0a: + 3e:03:43:9c:0c:91:f5:6d:7b:f8:40:72:75:ab:11:76:91:2b: + e1:c6:aa:1f:70:69:76:70:15:09:fe:93:d0:d6:2d:b7:15:6a: + 9b:67:5c:b4:69:9f:25:a6:7d:8a:fb:7d:22:a9:71:f2:ce:4e: + 8c:b8:21:2d:de:fe:41:71:0d:ff:9d:ec:73:a6:bb:07:4f:88: + 0e:58:47:2e:7e:a9:c2:c7:78:dd:ba:7a:9e:4e:e0:30:4e:63: + 6f:85:d4:20:41:e9:fa:fe:43:45:e7:fb:af:7a:b2:ce:a4:05: + 1d:22:9a:58:86:df:e4:ce:4c:a9:fe:d8:16:a5:6f:fb:d8:ce: + 56:7b:f5:d6:20:ef:e4:47:cd:63:24:ff:b9:be:f1:48:a3:c1: + 01:72:e6:bd:c0:ad:ed:26:0d:ca:34:9f:fc:02:2d:20:4f:05: + 20:ae:21:3d:0c:c2:20:3c:3f:f0:04:84:dc:cf:89:fd:b9:25: + 91:8e:d0:43:e6:b3:20:ab:5c:2d:d5:40:9e:a0:4b:d8:f4:b2: + cc:7d:f1:58:0a:8e:87:ed:88:ac:36:96:e4:56:a0:11:8a:f2: + 9a:d0:b3:57:a3:34:bb:19:ab:38:e1:74:6b:22:c4:31:ce:01: + d5:1b:36:e3:1e:38:4c:33:93:df:40:e3:59:57:4e:ac:6e:7b: + 1e:5a:3d:c5:1d:5b:ac:c8:10:82:35:02:22:b2:fc:75:e8:10: + 91:8d:c4:7d:78:93:47:9e:1c:9d:ac:6b:62:02:58:8c:d6:1c: + 23:d6:af:78:c2:80:9c:a4:aa:24:54:14:b5:14:98:c6:f8:2b: + 1a:24:cb:71:32:0a:e2:9b:0e:69:6b:dd:7e:8c:64:d1:2e:63: + ef:0e:7f:b1:3e:88:4c:9d:55:e5:c9:6e:17:04:b7:41:ff:bd: + 8a:41:cb:25:31:6f:44:77:3f:47:b1:fc:81:88:07:8e:05:49: + 20:b7:11:d9:69:03:2a:03:9d:b9:33:84:9a:df:df:7a:e3:46: + 73:a3:d8:a2:8c:53:19:88:55:4c:74:b8:f6:44:84:2b:d1:14: + 2d:4e:39:2e:92:68:ff:69:fc:85:62:1b:eb:55:4f:ef:25:84: + 62:45:99:d6:d8:4e:6f:3f:53:08:7d:1d:06:95:81:80:7f:4f: + 4e:74:36:98:b5:e2:87:70:98:dc:d7:f5:dc:52:15:e6:c6:d6: + 79:96:39:7f:8f:95:cf:ab:80:53:ad:1b:0b:45:40:0e:d4:18: + bd:2c:de:8a:77:76:fd:f2:44:47:c6:21:d0:e4:74:f0:d8:18: + 05:c8:7c:30:72:c7:df:f1:bb:fc:02:30:a9:f4:42:26:59:0d: + 93:05:82:a1:73:ed:34:e5:38:5d:cd:50:90:fe:94:fc:13:bc: + bd:fc:a8:a2:88:a7:73:c4:b2:a8:d1:5d:88:c4:02:a2:7a:f1: + 04:c9:fe:8c:74:c9:ef:1d:64:41:9f:ac:1e:96:67:64:ac:ab: + 28:41:c7:9d:f7:c0:98:1b:6e:07:c2:64:7d:5a:83:66:56:28: + 36:9c:e7:fb:1c:77:0e:28:a0:c4:f7:6b:79:39:04:20:84:c7: + 57:93:bc:1b:a0:ea:bc:eb:42:e5:a8:11:fe:fc:ac:65:cc:fd: + f8:28:88:f4:a5:9a:e5:73:51:e0:a8:9b:0d:03:77:4e:e5:e0: + 98:b3:88:da:7d:e6:c6:9e:7c:14:66:c1:2e:53:4a:92:07:37: + a0:7e:e9:3d:09:e4:15:7c:cf:fd:b8:41:a5:ef:9e:66:9d:c4: + 5e:07:1d:87:f8:41:ad:ea:e7:2f:d2:41:63:18:37:f9:14:e3: + 4d:d0:e5:f7:43:fd:15:e3:f9:36:73:06:26:df:01:4f:a9:c3: + 4e:de:20:46:77:98:b4:7a:24:2b:3b:75:2b:4e:58:8d:9b:5d: + a4:c7:16:a0:bc:32:88:3f:a1:83:f3:00:c8:f8:d8:58:e9:63: + 5d:4c:2b:b5:f0:72:41:d8:ab:77:37:d6:72:74:ae:b6:36:9c: + c8:a6:83:49:4b:e0:c9:56:0b:29:be:00:30:cb:dd:d6:c8:42: + 8a:00:d9:ec:15:d1:34:71:f2:5b:64:87:f6:27:d2:b7:eb:86: + b0:90:bf:29:db:21:9e:36:8c:e3:20:2f:95:23:51:6c:1b:c2: + a4:d5:e6:d8:02:43:67:a0:fe:9b:50:03:44:7f:bb:e4:72:d5: + d1:e4:da:8f:92:14:64:fb:5d:14:10:12:4a:95:06:c9:65:08: + 29:ca:21:a3:26:38:11:c9:27:df:70:67:04:fd:ca:48:32:7f: + 63:b2:45:74:31:50:4f:87:d9:20:70:d2:21:70:b1:d6:10:9d: + 33:5d:78:83:91:6d:55:82:ec:da:e4:62:63:c7:81:46:d7:19: + 65:72:2a:43:19:90:b8:d7:23:4d:4c:1c:e0:44:a9:66:67:ac: + ee:71:79:27:26:78:6d:72:0e:f5:5d:4b:23:b5:7c:7c:65:e9: + 17:c6:3a:0b:0d:dd:5e:1e:51:c3:86:b8:ec:7f:c7:27:4a:a5: + 46:e8:6a:2d:19:c1:87:a3:cb:99:93:87:64:a2:55:14:4c:b7: + 43:a5:93:d7:e7:d2:4e:79:40:ca:65:99:46:3d:3f:7a:80:7a: + 88:6a:cc:1e:e5:6b:33:46:f4:50:c0:d5:1f:09:b8:cd:8a:2e: + a1:27:eb:5d:73:a7:e8:6b:0a:e5:57:82:2a:b0:fc:e2:54:52: + 56:f0:ab:a9:12:c6:23:96:07:24:9c:e0:bc:46:a5:b4:20:04: + da:09:93:63:e5:d4:2e:c2:7e:c5:31:ed:b5:15:74:86:17:b9: + b3:f3:26:8a:1d:02:6a:da:1a:3f:e8:ba:f1:04:6d:94:51:54: + e2:5a:b4:59:83:1d:60:d0:2d:73:cc:07:b5:26:8c:f9:d7:c6: + 88:91:ef:80:cf:5d:0f:a1:60:cb:45:d4:42:22:d1:b1:70:1d: + fd:d0:b7:30:90:3a:c6:48:6d:67:e5:32:da:8f:db:e3:a8:e3: + 1d:20:25:a2:1c:e1:4c:b9:a4:f6:c6:3f:5c:58:0d:bb:c6:b2: + 77:01:16:91:9f:17:06:0d:b7:40:3e:cc:8f:8e:9c:4b:e0:9d: + 7e:9b:1e:05:ab:88:22:fa:d3:28:1b:57:14:64:4a:3e:24:2c: + 38:4d:21:69:00:73:2e:d0:55:2d:74:f2:15:e8:94:43:3e:40: + 2a:c6:c6:b9:6a:5b:de:a2:cc:18:50:54:5d:4e:2a:85:6c:f6: + 92:8b:29:19:7e:e7:ea:4a:e0:22:2b:25:bc:f7:66:cf:77:9a: + 41:74:f2:3c:14:0d:74:69:f5:50:83:cd:cd:2f:21:db:22:46: + 8a:d0:f7:51:1a:95:57:f2:05:8b:1a:19:ed:3b:45:e8:36:c2: + 6e:7e:fb:57:22:00:1f:06:53:a9:ae:93:c6:8f:71:2a:31:45: + 92:e7:8e:6d:e6:99:22:c0:83:fc:ef:dc:57:66:77:4f:a2:36: + 31:fb:a1:13:8d:e5:ca:a3:95:7d:01:0c:64:70:3b:53:42:68: + 80:c7:bb:9d:a8:00:35:69:98:0c:a8:67:d8:43:e5:aa:cf:95: + e0:51:95:a4:17:3f:42:9d:b8:04:ce:d3:79:79:c8:d3:8a:16: + 32:92:e0:d7:a2:ee:d7:37:4c:2f:ac:b8:7b:be:45:f6:f1:18: + 33:9c:7b:37:a6:24:d9:bc:40:ab:00:e9:c3:37:8b:ab:d8:b6: + f3:5e:81:4e:b0:14:6b:07:3e:1f:ec:c2:f6:44:22:95:bb:b3: + e6:6f:d6:f9:70:65:ba:0a:83:65:aa:0e:13:2f:83:13:23:53: + 8b:40:16:fa:ce:2f:fc:4d:04:f8:eb:d8:ac:c5:36:c2:15:57: + 48:38:ec:55:b3:b4:1e:ba:ad:d2:42:06:17:0d:73:c8:57:a6: + be:96:4d:a9:f2:c0:fb:7a:21:1c:f5:c9:70:a9:82:90:b5:f1: + 0c:d4:79:10:be:81:a6:e9:5c:61:9c:77:79:9a:a4:c3:37:26: + 57:37:c9:52:2c:fa:08:ff:d0:5f:c6:61:c0:f4:76:be:fc:de: + 4e:cf:ab:51:99:71:c7:df:7e:f4:d6:cf:06:56:19:13:53:0b: + 6d:74:59:48:19:9b:53:05:2d:9d:32:54:d3:e5:2c:53:8b:64: + 3e:d4:64:7b:e3:80:09:14:cc:fe:16:46:63:6b:71:69:f8:f9: + cb:27:f6:88:54:bc:45:b3:ce:02:c8:94:ee:40:5b:f9:42:02: + c2:ff:b0:d8:2c:eb:28:7f:5e:c9:26:01:99:a7 + +UPS Document Exchange by DST +============================ +MD5 Fingerprint: 78:A5:FB:10:4B:E4:63:2E:D2:6B:FB:F2:B6:C2:4B:8E +PEM Data: +-----BEGIN CERTIFICATE----- +MIID+DCCAuACEQDQHkCLAAACfAAAAAcAAAABMA0GCSqGSIb3DQEBBQUAMIG5MQsw +CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp +dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEeMBwGA1UE +CxMVVW5pdGVkIFBhcmNlbCBTZXJ2aWNlMRkwFwYDVQQDExBEU1QgKFVQUykgUm9v +dENBMSEwHwYJKoZIhvcNAQkBFhJjYUBkaWdzaWd0cnVzdC5jb20wHhcNOTgxMjEw +MDAyNTQ2WhcNMDgxMjA3MDAyNTQ2WjCBuTELMAkGA1UEBhMCdXMxDTALBgNVBAgT +BFV0YWgxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xHjAcBgNVBAsTFVVuaXRlZCBQYXJjZWwgU2Vy +dmljZTEZMBcGA1UEAxMQRFNUIChVUFMpIFJvb3RDQTEhMB8GCSqGSIb3DQEJARYS +Y2FAZGlnc2lndHJ1c3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA7xfsrynm2SsnwNt7JJ9m9ASjwq0KyrDNhCuqN/OAoWDvQo/lXXdfV0JU3Svb +YbJxXpN7b1/rJCvnpPLr8XOzC431Wdcy36yQjk4xuiVNtgym8eWvDOHlb1IDFcHf +vn5KpqYYRnA/76dNqNz1dNlhekA8oZQo6sKUiMs3FQUZPJViuhwt+yiM0ciekjxb +EVQ7eNlHO5stSuY+e2vf9PYFzyj2upg2AJ48N4UKnN63pIXFY/23YhRtFx7MioCF +QjIRsCHinXfJgBZBnuvlFIl/t8O8T8Gfh5uW7GP2+ZBWDpWjIwqMZNqbuxx3sExd +5sjo9X15LVckP8zjPSyYzxKfFwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQC7OI4E +IiZYDiFEVsy9WXwpaMtcD8iGVD+BeKetj8xG9xxUuHktW3IFaugh0OwdHf6kNFG+ +7u3OzJwWaOJddXMIQzGRahArEMJLafjJrZio/bjv9qvwXyHvy4VrCe0vSGa1YHLA +6KDHmNsO9xtzjTQICnvFd2KqMCObsB6LgJhU3AWHs6liWfyLtxWarETszzUa9w8u +XZJLAch77qA37eQdgg2ZQUMXrdTVyuP5fReiAdAwD0C53LkEgmmDtvkP+gaS96j0 +1hcc8F5/xCnI5uHi/zZoIVGu/6m6hJKtinsz2JDSwXltMzM5dKwbOHGfLAeQ6h3g +04lfy+8UjSdUpb1G +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + d0:1e:40:8b:00:00:02:7c:00:00:00:07:00:00:00:01 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=United Parcel Service, CN=DST (UPS) RootCA/Email=ca@digsigtrust.com + Validity + Not Before: Dec 10 00:25:46 1998 GMT + Not After : Dec 7 00:25:46 2008 GMT + Subject: C=us, ST=Utah, L=Salt Lake City, O=Digital Signature Trust Co., OU=United Parcel Service, CN=DST (UPS) RootCA/Email=ca@digsigtrust.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ef:17:ec:af:29:e6:d9:2b:27:c0:db:7b:24:9f: + 66:f4:04:a3:c2:ad:0a:ca:b0:cd:84:2b:aa:37:f3: + 80:a1:60:ef:42:8f:e5:5d:77:5f:57:42:54:dd:2b: + db:61:b2:71:5e:93:7b:6f:5f:eb:24:2b:e7:a4:f2: + eb:f1:73:b3:0b:8d:f5:59:d7:32:df:ac:90:8e:4e: + 31:ba:25:4d:b6:0c:a6:f1:e5:af:0c:e1:e5:6f:52: + 03:15:c1:df:be:7e:4a:a6:a6:18:46:70:3f:ef:a7: + 4d:a8:dc:f5:74:d9:61:7a:40:3c:a1:94:28:ea:c2: + 94:88:cb:37:15:05:19:3c:95:62:ba:1c:2d:fb:28: + 8c:d1:c8:9e:92:3c:5b:11:54:3b:78:d9:47:3b:9b: + 2d:4a:e6:3e:7b:6b:df:f4:f6:05:cf:28:f6:ba:98: + 36:00:9e:3c:37:85:0a:9c:de:b7:a4:85:c5:63:fd: + b7:62:14:6d:17:1e:cc:8a:80:85:42:32:11:b0:21: + e2:9d:77:c9:80:16:41:9e:eb:e5:14:89:7f:b7:c3: + bc:4f:c1:9f:87:9b:96:ec:63:f6:f9:90:56:0e:95: + a3:23:0a:8c:64:da:9b:bb:1c:77:b0:4c:5d:e6:c8: + e8:f5:7d:79:2d:57:24:3f:cc:e3:3d:2c:98:cf:12: + 9f:17 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + bb:38:8e:04:22:26:58:0e:21:44:56:cc:bd:59:7c:29:68:cb: + 5c:0f:c8:86:54:3f:81:78:a7:ad:8f:cc:46:f7:1c:54:b8:79: + 2d:5b:72:05:6a:e8:21:d0:ec:1d:1d:fe:a4:34:51:be:ee:ed: + ce:cc:9c:16:68:e2:5d:75:73:08:43:31:91:6a:10:2b:10:c2: + 4b:69:f8:c9:ad:98:a8:fd:b8:ef:f6:ab:f0:5f:21:ef:cb:85: + 6b:09:ed:2f:48:66:b5:60:72:c0:e8:a0:c7:98:db:0e:f7:1b: + 73:8d:34:08:0a:7b:c5:77:62:aa:30:23:9b:b0:1e:8b:80:98: + 54:dc:05:87:b3:a9:62:59:fc:8b:b7:15:9a:ac:44:ec:cf:35: + 1a:f7:0f:2e:5d:92:4b:01:c8:7b:ee:a0:37:ed:e4:1d:82:0d: + 99:41:43:17:ad:d4:d5:ca:e3:f9:7d:17:a2:01:d0:30:0f:40: + b9:dc:b9:04:82:69:83:b6:f9:0f:fa:06:92:f7:a8:f4:d6:17: + 1c:f0:5e:7f:c4:29:c8:e6:e1:e2:ff:36:68:21:51:ae:ff:a9: + ba:84:92:ad:8a:7b:33:d8:90:d2:c1:79:6d:33:33:39:74:ac: + 1b:38:71:9f:2c:07:90:ea:1d:e0:d3:89:5f:cb:ef:14:8d:27: + 54:a5:bd:46 + +ValiCert Class 1 VA +=================== +MD5 Fingerprint: 65:58:AB:15:AD:57:6C:1E:A8:A7:B5:69:AC:BF:FF:EB +PEM Data: +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy +NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y +LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ +TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y +TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 +LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW +I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw +nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 1 Policy Validation Authority, CN=http://www.valicert.com//Email=info@valicert.com + Validity + Not Before: Jun 25 22:23:48 1999 GMT + Not After : Jun 25 22:23:48 2019 GMT + Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 1 Policy Validation Authority, CN=http://www.valicert.com//Email=info@valicert.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d8:59:82:7a:89:b8:96:ba:a6:2f:68:6f:58:2e: + a7:54:1c:06:6e:f4:ea:8d:48:bc:31:94:17:f0:f3: + 4e:bc:b2:b8:35:92:76:b0:d0:a5:a5:01:d7:00:03: + 12:22:19:08:f8:ff:11:23:9b:ce:07:f5:bf:69:1a: + 26:fe:4e:e9:d1:7f:9d:2c:40:1d:59:68:6e:a6:f8: + 58:b0:9d:1a:8f:d3:3f:f1:dc:19:06:81:a8:0e:e0: + 3a:dd:c8:53:45:09:06:e6:0f:70:c3:fa:40:a6:0e: + e2:56:05:0f:18:4d:fc:20:82:d1:73:55:74:8d:76: + 72:a0:1d:9d:1d:c0:dd:3f:71 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 50:68:3d:49:f4:2c:1c:06:94:df:95:60:7f:96:7b:17:fe:4f: + 71:ad:64:c8:dd:77:d2:ef:59:55:e8:3f:e8:8e:05:2a:21:f2: + 07:d2:b5:a7:52:fe:9c:b1:b6:e2:5b:77:17:40:ea:72:d6:23: + cb:28:81:32:c3:00:79:18:ec:59:17:89:c9:c6:6a:1e:71:c9: + fd:b7:74:a5:25:45:69:c5:48:ab:19:e1:45:8a:25:6b:19:ee: + e5:bb:12:f5:7f:f7:a6:8d:51:c3:f0:9d:74:b7:a9:3e:a0:a5: + ff:b6:49:03:13:da:22:cc:ed:71:82:2b:99:cf:3a:b7:f5:2d: + 72:c8 + +ValiCert Class 2 VA +=================== +MD5 Fingerprint: A9:23:75:9B:BA:49:36:6E:31:C2:DB:F2:E7:66:BA:87 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy +NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY +dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 +WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS +v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v +UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu +IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC +W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//Email=info@valicert.com + Validity + Not Before: Jun 26 00:19:54 1999 GMT + Not After : Jun 26 00:19:54 2019 GMT + Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//Email=info@valicert.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ce:3a:71:ca:e5:ab:c8:59:92:55:d7:ab:d8:74: + 0e:f9:ee:d9:f6:55:47:59:65:47:0e:05:55:dc:eb: + 98:36:3c:5c:53:5d:d3:30:cf:38:ec:bd:41:89:ed: + 25:42:09:24:6b:0a:5e:b3:7c:dd:52:2d:4c:e6:d4: + d6:7d:5a:59:a9:65:d4:49:13:2d:24:4d:1c:50:6f: + b5:c1:85:54:3b:fe:71:e4:d3:5c:42:f9:80:e0:91: + 1a:0a:5b:39:36:67:f3:3f:55:7c:1b:3f:b4:5f:64: + 73:34:e3:b4:12:bf:87:64:f8:da:12:ff:37:27:c1: + b3:43:bb:ef:7b:6e:2e:69:f7 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 3b:7f:50:6f:6f:50:94:99:49:62:38:38:1f:4b:f8:a5:c8:3e: + a7:82:81:f6:2b:c7:e8:c5:ce:e8:3a:10:82:cb:18:00:8e:4d: + bd:a8:58:7f:a1:79:00:b5:bb:e9:8d:af:41:d9:0f:34:ee:21: + 81:19:a0:32:49:28:f4:c4:8e:56:d5:52:33:fd:50:d5:7e:99: + 6c:03:e4:c9:4c:fc:cb:6c:ab:66:b3:4a:21:8c:e5:b5:0c:32: + 3e:10:b2:cc:6c:a1:dc:9a:98:4c:02:5b:f3:ce:b9:9e:a5:72: + 0e:4a:b7:3f:3c:e6:16:68:f8:be:ed:74:4c:bc:5b:d5:62:1f: + 43:dd + +ValiCert Class 3 VA +=================== +MD5 Fingerprint: A2:6F:53:B7:EE:40:DB:4A:68:E7:FA:18:D9:10:4B:72 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy +NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD +cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs +2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY +JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE +Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ +n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A +PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com//Email=info@valicert.com + Validity + Not Before: Jun 26 00:22:33 1999 GMT + Not After : Jun 26 00:22:33 2019 GMT + Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com//Email=info@valicert.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:e3:98:51:96:1c:e8:d5:b1:06:81:6a:57:c3:72: + 75:93:ab:cf:9e:a6:fc:f3:16:52:d6:2d:4d:9f:35: + 44:a8:2e:04:4d:07:49:8a:38:29:f5:77:37:e7:b7: + ab:5d:df:36:71:14:99:8f:dc:c2:92:f1:e7:60:92: + 97:ec:d8:48:dc:bf:c1:02:20:c6:24:a4:28:4c:30: + 5a:76:6d:b1:5c:f3:dd:de:9e:10:71:a1:88:c7:5b: + 9b:41:6d:ca:b0:b8:8e:15:ee:ad:33:2b:cf:47:04: + 5c:75:71:0a:98:24:98:29:a7:49:59:a5:dd:f8:b7: + 43:62:61:f3:d3:e2:d0:55:3f + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 56:bb:02:58:84:67:08:2c:df:1f:db:7b:49:33:f5:d3:67:9d: + f4:b4:0a:10:b3:c9:c5:2c:e2:92:6a:71:78:27:f2:70:83:42: + d3:3e:cf:a9:54:f4:f1:d8:92:16:8c:d1:04:cb:4b:ab:c9:9f: + 45:ae:3c:8a:a9:b0:71:33:5d:c8:c5:57:df:af:a8:35:b3:7f: + 89:87:e9:e8:25:92:b8:7f:85:7a:ae:d6:bc:1e:37:58:2a:67: + c9:91:cf:2a:81:3e:ed:c6:39:df:c0:3e:19:9c:19:cc:13:4d: + 82:41:b5:8c:de:e0:3d:60:08:20:0f:45:7e:6b:a2:7f:a3:8c: + 15:ee + +VeriSign Class 4 Primary CA +=========================== +MD5 Fingerprint: 1B:D1:AD:17:8B:7F:22:13:24:F5:26:E2:5D:4E:B9:10 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICMTCCAZoCBQKmAAABMA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NjAxMjkwMDAwMDBa +Fw05OTEyMzEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2ln +biwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LJ1 +9njQrlpQ9OlQqZ+M1++RlHDo0iSQdomF1t+s5gEXMoDwnZNHvJplnR+Xrr/phnVj +IIm9gFidBAydqMEk6QvlMXi9/C0MN2qeeIDpRnX57aP7E3vIwUzSo+/1PLBij0pd +O92VZ48TucE81qcmm+zDO3rZTbxtm+gVAePwR6kCAwEAATANBgkqhkiG9w0BAQIF +AAOBgQBT3dPwnCR+QKri/AAa19oM/DJhuBUNlvP6Vxt/M3yv6ZiaYch6s7f/sdyZ +g9ysEvxwyR84Qu1E9oAuW2szaayc01znX1oYx7EteQSWQZGZQbE8DbqEOcY7l/Am +yY7uvcxClf8exwI/VAx49byqYHwCaejcrOICdmHEPgPq0ook0Q== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 02:a6:00:00:01 + Signature Algorithm: md2WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 4 Public Primary Certification Authority + Validity + Not Before: Jan 29 00:00:00 1996 GMT + Not After : Dec 31 23:59:59 1999 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 4 Public Primary Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d0:b2:75:f6:78:d0:ae:5a:50:f4:e9:50:a9:9f: + 8c:d7:ef:91:94:70:e8:d2:24:90:76:89:85:d6:df: + ac:e6:01:17:32:80:f0:9d:93:47:bc:9a:65:9d:1f: + 97:ae:bf:e9:86:75:63:20:89:bd:80:58:9d:04:0c: + 9d:a8:c1:24:e9:0b:e5:31:78:bd:fc:2d:0c:37:6a: + 9e:78:80:e9:46:75:f9:ed:a3:fb:13:7b:c8:c1:4c: + d2:a3:ef:f5:3c:b0:62:8f:4a:5d:3b:dd:95:67:8f: + 13:b9:c1:3c:d6:a7:26:9b:ec:c3:3b:7a:d9:4d:bc: + 6d:9b:e8:15:01:e3:f0:47:a9 + Exponent: 65537 (0x10001) + Signature Algorithm: md2WithRSAEncryption + 53:dd:d3:f0:9c:24:7e:40:aa:e2:fc:00:1a:d7:da:0c:fc:32: + 61:b8:15:0d:96:f3:fa:57:1b:7f:33:7c:af:e9:98:9a:61:c8: + 7a:b3:b7:ff:b1:dc:99:83:dc:ac:12:fc:70:c9:1f:38:42:ed: + 44:f6:80:2e:5b:6b:33:69:ac:9c:d3:5c:e7:5f:5a:18:c7:b1: + 2d:79:04:96:41:91:99:41:b1:3c:0d:ba:84:39:c6:3b:97:f0: + 26:c9:8e:ee:bd:cc:42:95:ff:1e:c7:02:3f:54:0c:78:f5:bc: + aa:60:7c:02:69:e8:dc:ac:e2:02:76:61:c4:3e:03:ea:d2:8a: + 24:d1 + +Verisign Class 1 Public Primary Certification Authority +======================================================= +MD5 Fingerprint: 97:60:E8:57:5F:D3:50:47:E5:43:0C:94:36:8A:B0:62 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh +c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 +NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD +VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp +bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N +H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR +4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN +BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo +EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 +FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx +lA== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + cd:ba:7f:56:f0:df:e4:bc:54:fe:22:ac:b3:72:aa:55 + Signature Algorithm: md2WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 1 Public Primary Certification Authority + Validity + Not Before: Jan 29 00:00:00 1996 GMT + Not After : Aug 1 23:59:59 2028 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 1 Public Primary Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:e5:19:bf:6d:a3:56:61:2d:99:48:71:f6:67:de: + b9:8d:eb:b7:9e:86:80:0a:91:0e:fa:38:25:af:46: + 88:82:e5:73:a8:a0:9b:24:5d:0d:1f:cc:65:6e:0c: + b0:d0:56:84:18:87:9a:06:9b:10:a1:73:df:b4:58: + 39:6b:6e:c1:f6:15:d5:a8:a8:3f:aa:12:06:8d:31: + ac:7f:b0:34:d7:8f:34:67:88:09:cd:14:11:e2:4e: + 45:56:69:1f:78:02:80:da:dc:47:91:29:bb:36:c9: + 63:5c:c5:e0:d7:2d:87:7b:a1:b7:32:b0:7b:30:ba: + 2a:2f:31:aa:ee:a3:67:da:db + Exponent: 65537 (0x10001) + Signature Algorithm: md2WithRSAEncryption + 4c:3f:b8:8b:c6:68:df:ee:43:33:0e:5d:e9:a6:cb:07:84:4d: + 7a:33:ff:92:1b:f4:36:ad:d8:95:22:36:68:11:6c:7c:42:cc: + f3:9c:2e:c4:07:3f:14:b0:0f:4f:ff:90:92:76:f9:e2:bc:4a: + e9:8f:cd:a0:80:0a:f7:c5:29:f1:82:22:5d:b8:b1:dd:81:23: + a3:7b:25:15:46:30:79:16:f8:ea:05:4b:94:7f:1d:c2:1c:c8: + e3:b7:f4:10:40:3c:13:c3:5f:1f:53:e8:48:e4:86:b4:7b:a1: + 35:b0:7b:25:ba:b8:d3:8e:ab:3f:38:9d:00:34:00:98:f3:d1: + 71:94 + +Verisign Class 1 Public Primary Certification Authority - G2 +============================================================ +MD5 Fingerprint: F2:7D:E9:54:E4:A3:22:0D:76:9F:E7:0B:BB:B3:24:2B +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEDnKVIn+UCIy/jLZ2/sbhBkwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTE4MDUxODIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK +VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm +Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAIv3GhDOdlwHq4OZ3BeAbzQ5XZg+a3Is4cei +e0ApuXiIukzFo2penm574/ICQQxmvq37rqIUzpLzojSLtLK2JPLl1eDI5WJthHvL +vrsDi3xXyvA3qZCviu4Dvh0onNkmdqDNxJ1O8K4HFtW+r1cIatCgQkJCHvQgzKV4 +gpUmOIpH +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 39:ca:54:89:fe:50:22:32:fe:32:d9:db:fb:1b:84:19 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 1 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Validity + Not Before: May 18 00:00:00 1998 GMT + Not After : May 18 23:59:59 2018 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 1 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:aa:d0:ba:be:16:2d:b8:83:d4:ca:d2:0f:bc:76: + 31:ca:94:d8:1d:93:8c:56:02:bc:d9:6f:1a:6f:52: + 36:6e:75:56:0a:55:d3:df:43:87:21:11:65:8a:7e: + 8f:bd:21:de:6b:32:3f:1b:84:34:95:05:9d:41:35: + eb:92:eb:96:dd:aa:59:3f:01:53:6d:99:4f:ed:e5: + e2:2a:5a:90:c1:b9:c4:a6:15:cf:c8:45:eb:a6:5d: + 8e:9c:3e:f0:64:24:76:a5:cd:ab:1a:6f:b6:d8:7b: + 51:61:6e:a6:7f:87:c8:e2:b7:e5:34:dc:41:88:ea: + 09:40:be:73:92:3d:6b:e7:75 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 8b:f7:1a:10:ce:76:5c:07:ab:83:99:dc:17:80:6f:34:39:5d: + 98:3e:6b:72:2c:e1:c7:a2:7b:40:29:b9:78:88:ba:4c:c5:a3: + 6a:5e:9e:6e:7b:e3:f2:02:41:0c:66:be:ad:fb:ae:a2:14:ce: + 92:f3:a2:34:8b:b4:b2:b6:24:f2:e5:d5:e0:c8:e5:62:6d:84: + 7b:cb:be:bb:03:8b:7c:57:ca:f0:37:a9:90:af:8a:ee:03:be: + 1d:28:9c:d9:26:76:a0:cd:c4:9d:4e:f0:ae:07:16:d5:be:af: + 57:08:6a:d0:a0:42:42:42:1e:f4:20:cc:a5:78:82:95:26:38: + 8a:47 + +Verisign Class 1 Public Primary Certification Authority - G3 +============================================================ +MD5 Fingerprint: B1:47:BC:18:57:D1:18:A0:78:2D:EC:71:E8:2A:95:73 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 +nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO +8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV +ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb +PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 +6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr +n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a +qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 +wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 +ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs +pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 +E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 8b:5b:75:56:84:54:85:0b:00:cf:af:38:48:ce:b1:a4 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 1 Public Primary Certification Authority - G3 + Validity + Not Before: Oct 1 00:00:00 1999 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 1 Public Primary Certification Authority - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:dd:84:d4:b9:b4:f9:a7:d8:f3:04:78:9c:de:3d: + dc:6c:13:16:d9:7a:dd:24:51:66:c0:c7:26:59:0d: + ac:06:08:c2:94:d1:33:1f:f0:83:35:1f:6e:1b:c8: + de:aa:6e:15:4e:54:27:ef:c4:6d:1a:ec:0b:e3:0e: + f0:44:a5:57:c7:40:58:1e:a3:47:1f:71:ec:60:f6: + 6d:94:c8:18:39:ed:fe:42:18:56:df:e4:4c:49:10: + 78:4e:01:76:35:63:12:36:dd:66:bc:01:04:36:a3: + 55:68:d5:a2:36:09:ac:ab:21:26:54:06:ad:3f:ca: + 14:e0:ac:ca:ad:06:1d:95:e2:f8:9d:f1:e0:60:ff: + c2:7f:75:2b:4c:cc:da:fe:87:99:21:ea:ba:fe:3e: + 54:d7:d2:59:78:db:3c:6e:cf:a0:13:00:1a:b8:27: + a1:e4:be:67:96:ca:a0:c5:b3:9c:dd:c9:75:9e:eb: + 30:9a:5f:a3:cd:d9:ae:78:19:3f:23:e9:5c:db:29: + bd:ad:55:c8:1b:54:8c:63:f6:e8:a6:ea:c7:37:12: + 5c:a3:29:1e:02:d9:db:1f:3b:b4:d7:0f:56:47:81: + 15:04:4a:af:83:27:d1:c5:58:88:c1:dd:f6:aa:a7: + a3:18:da:68:aa:6d:11:51:e1:bf:65:6b:9f:96:76: + d1:3d + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + ab:66:8d:d7:b3:ba:c7:9a:b6:e6:55:d0:05:f1:9f:31:8d:5a: + aa:d9:aa:46:26:0f:71:ed:a5:ad:53:56:62:01:47:2a:44:e9: + fe:3f:74:0b:13:9b:b9:f4:4d:1b:b2:d1:5f:b2:b6:d2:88:5c: + b3:9f:cd:cb:d4:a7:d9:60:95:84:3a:f8:c1:37:1d:61:ca:e7: + b0:c5:e5:91:da:54:a6:ac:31:81:ae:97:de:cd:08:ac:b8:c0: + 97:80:7f:6e:72:a4:e7:69:13:95:65:1f:c4:93:3c:fd:79:8f: + 04:d4:3e:4f:ea:f7:9e:ce:cd:67:7c:4f:65:02:ff:91:85:54: + 73:c7:ff:36:f7:86:2d:ec:d0:5e:4f:ff:11:9f:72:06:d6:b8: + 1a:f1:4c:0d:26:65:e2:44:80:1e:c7:9f:e3:dd:e8:0a:da:ec: + a5:20:80:69:68:a1:4f:7e:e1:6b:cf:07:41:fa:83:8e:bc:38: + dd:b0:2e:11:b1:6b:b2:42:cc:9a:bc:f9:48:22:79:4a:19:0f: + b2:1c:3e:20:74:d9:6a:c3:be:f2:28:78:13:56:79:4f:6d:50: + ea:1b:b0:b5:57:b1:37:66:58:23:f3:dc:0f:df:0a:87:c4:ef: + 86:05:d5:38:14:60:99:a3:4b:de:06:96:71:2c:f2:db:b6:1f: + a4:ef:3f:ee + +Verisign Class 2 Public Primary Certification Authority +======================================================= +MD5 Fingerprint: B3:9C:25:B1:C3:2E:32:53:80:15:30:9D:4D:02:77:3E +PEM Data: +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh +YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 +FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G +CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg +J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc +r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 2d:1b:fc:4a:17:8d:a3:91:eb:e7:ff:f5:8b:45:be:0b + Signature Algorithm: md2WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 2 Public Primary Certification Authority + Validity + Not Before: Jan 29 00:00:00 1996 GMT + Not After : Aug 1 23:59:59 2028 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 2 Public Primary Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b6:5a:8b:a3:0d:6a:23:83:80:6b:cf:39:87:f4: + 21:13:33:06:4c:25:a2:ed:55:12:97:c5:a7:80:b9: + fa:83:c1:20:a0:fa:2f:15:0d:7c:a1:60:6b:7e:79: + 2c:fa:06:0f:3a:ae:f6:1b:6f:b1:d2:ff:2f:28:52: + 5f:83:7d:4b:c4:7a:b7:f8:66:1f:80:54:fc:b7:c2: + 8e:59:4a:14:57:46:d1:9a:93:be:41:91:03:bb:15: + 80:93:5c:eb:e7:cc:08:6c:3f:3e:b3:4a:fc:ff:4b: + 6c:23:d5:50:82:26:44:19:8e:23:c3:71:ea:19:24: + 47:04:9e:75:bf:c8:a6:00:1f + Exponent: 65537 (0x10001) + Signature Algorithm: md2WithRSAEncryption + 8a:1b:2b:fa:39:c1:74:d7:5e:d8:19:64:a2:58:4a:2d:37:e0: + 33:47:0f:ac:ed:f7:aa:db:1e:e4:8b:06:5c:60:27:ca:45:52: + ce:16:ef:3f:06:64:e7:94:68:7c:60:33:15:11:69:af:9d:62: + 8d:a3:03:54:6b:a6:be:e5:ee:05:18:60:04:bf:42:80:fd:d0: + a8:a8:1e:01:3b:f7:a3:5c:af:a3:dc:e6:26:80:23:3c:b8:44: + 74:f7:0a:ae:49:8b:61:78:cc:24:bf:88:8a:a7:0e:ea:73:19: + 41:fd:4d:03:f0:88:d1:e5:78:8d:a5:2a:4f:f6:97:0d:17:77: + ca:d8 + +Verisign Class 2 Public Primary Certification Authority - G2 +============================================================ +MD5 Fingerprint: 2D:BB:E5:25:D3:D1:65:82:3A:B7:0E:FA:E6:EB:E2:E1 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns +YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y +aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe +Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj +IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx +KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM +HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw +DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC +AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji +nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX +rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn +jBJ7xUS0rg== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + b9:2f:60:cc:88:9f:a1:7a:46:09:b8:5b:70:6c:8a:af + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 2 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Validity + Not Before: May 18 00:00:00 1998 GMT + Not After : Aug 1 23:59:59 2028 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 2 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a7:88:01:21:74:2c:e7:1a:03:f0:98:e1:97:3c: + 0f:21:08:f1:9c:db:97:e9:9a:fc:c2:04:06:13:be: + 5f:52:c8:cc:1e:2c:12:56:2c:b8:01:69:2c:cc:99: + 1f:ad:b0:96:ae:79:04:f2:13:39:c1:7b:98:ba:08: + 2c:e8:c2:84:13:2c:aa:69:e9:09:f4:c7:a9:02:a4: + 42:c2:23:4f:4a:d8:f0:0e:a2:fb:31:6c:c9:e6:6f: + 99:27:07:f5:e6:f4:4c:78:9e:6d:eb:46:86:fa:b9: + 86:c9:54:f2:b2:c4:af:d4:46:1c:5a:c9:15:30:ff: + 0d:6c:f5:2d:0e:6d:ce:7f:77 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 72:2e:f9:7f:d1:f1:71:fb:c4:9e:f6:c5:5e:51:8a:40:98:b8: + 68:f8:9b:1c:83:d8:e2:9d:bd:ff:ed:a1:e6:66:ea:2f:09:f4: + ca:d7:ea:a5:2b:95:f6:24:60:86:4d:44:2e:83:a5:c4:2d:a0: + d3:ae:78:69:6f:72:da:6c:ae:08:f0:63:92:37:e6:bb:c4:30: + 17:ad:77:cc:49:35:aa:cf:d8:8f:d1:be:b7:18:96:47:73:6a: + 54:22:34:64:2d:b6:16:9b:59:5b:b4:51:59:3a:b3:0b:14:f4: + 12:df:67:a0:f4:ad:32:64:5e:b1:46:72:27:8c:12:7b:c5:44: + b4:ae + +Verisign Class 2 Public Primary Certification Authority - G3 +============================================================ +MD5 Fingerprint: F8:BE:C4:63:22:C9:A8:46:74:8B:B8:1D:1E:4A:2B:F6 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy +aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp +Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV +BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp +Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g +Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU +J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO +JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY +wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o +koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN +qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E +Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe +xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u +7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU +sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI +sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP +cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 61:70:cb:49:8c:5f:98:45:29:e7:b0:a6:d9:50:5b:7a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 2 Public Primary Certification Authority - G3 + Validity + Not Before: Oct 1 00:00:00 1999 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 2 Public Primary Certification Authority - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:af:0a:0d:c2:d5:2c:db:67:b9:2d:e5:94:27:dd: + a5:be:e0:b0:4d:8f:b3:61:56:3c:d6:7c:c3:f4:cd: + 3e:86:cb:a2:88:e2:e1:d8:a4:69:c5:b5:e2:bf:c1: + a6:47:50:5e:46:39:8b:d5:96:ba:b5:6f:14:bf:10: + ce:27:13:9e:05:47:9b:31:7a:13:d8:1f:d9:d3:02: + 37:8b:ad:2c:47:f0:8e:81:06:a7:0d:30:0c:eb:f7: + 3c:0f:20:1d:dc:72:46:ee:a5:02:c8:5b:c3:c9:56: + 69:4c:c5:18:c1:91:7b:0b:d5:13:00:9b:bc:ef:c3: + 48:3e:46:60:20:85:2a:d5:90:b6:cd:8b:a0:cc:32: + dd:b7:fd:40:55:b2:50:1c:56:ae:cc:8d:77:4d:c7: + 20:4d:a7:31:76:ef:68:92:8a:90:1e:08:81:56:b2: + ad:69:a3:52:d0:cb:1c:c4:23:3d:1f:99:fe:4c:e8: + 16:63:8e:c6:08:8e:f6:31:f6:d2:fa:e5:76:dd:b5: + 1c:92:a3:49:cd:cd:01:cd:68:cd:a9:69:ba:a3:eb: + 1d:0d:9c:a4:20:a6:c1:a0:c5:d1:46:4c:17:6d:d2: + ac:66:3f:96:8c:e0:84:d4:36:ff:22:59:c5:f9:11: + 60:a8:5f:04:7d:f2:1a:f6:25:42:61:0f:c4:4a:b8: + 3e:89 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 34:26:15:3c:c0:8d:4d:43:49:1d:bd:e9:21:92:d7:66:9c:b7: + de:c5:b8:d0:e4:5d:5f:76:22:c0:26:f9:84:3a:3a:f9:8c:b5: + fb:ec:60:f1:e8:ce:04:b0:c8:dd:a7:03:8f:30:f3:98:df:a4: + e6:a4:31:df:d3:1c:0b:46:dc:72:20:3f:ae:ee:05:3c:a4:33: + 3f:0b:39:ac:70:78:73:4b:99:2b:df:30:c2:54:b0:a8:3b:55: + a1:fe:16:28:cd:42:bd:74:6e:80:db:27:44:a7:ce:44:5d:d4: + 1b:90:98:0d:1e:42:94:b1:00:2c:04:d0:74:a3:02:05:22:63: + 63:cd:83:b5:fb:c1:6d:62:6b:69:75:fd:5d:70:41:b9:f5:bf: + 7c:df:be:c1:32:73:22:21:8b:58:81:7b:15:91:7a:ba:e3:64: + 48:b0:7f:fb:36:25:da:95:d0:f1:24:14:17:dd:18:80:6b:46: + 23:39:54:f5:8e:62:09:04:1d:94:90:a6:9b:e6:25:e2:42:45: + aa:b8:90:ad:be:08:8f:a9:0b:42:18:94:cf:72:39:e1:b1:43: + e0:28:cf:b7:e7:5a:6c:13:6b:49:b3:ff:e3:18:7c:89:8b:33: + 5d:ac:33:d7:a7:f9:da:3a:55:c9:58:10:f9:aa:ef:5a:b6:cf: + 4b:4b:df:2a + +Verisign Class 3 Public Primary Certification Authority +======================================================= +MD5 Fingerprint: 10:FC:63:5D:F6:26:3E:0D:F3:25:BE:5F:79:CD:67:67 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do +lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc +AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 70:ba:e4:1d:10:d9:29:34:b6:38:ca:7b:03:cc:ba:bf + Signature Algorithm: md2WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority + Validity + Not Before: Jan 29 00:00:00 1996 GMT + Not After : Aug 1 23:59:59 2028 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c9:5c:59:9e:f2:1b:8a:01:14:b4:10:df:04:40: + db:e3:57:af:6a:45:40:8f:84:0c:0b:d1:33:d9:d9: + 11:cf:ee:02:58:1f:25:f7:2a:a8:44:05:aa:ec:03: + 1f:78:7f:9e:93:b9:9a:00:aa:23:7d:d6:ac:85:a2: + 63:45:c7:72:27:cc:f4:4c:c6:75:71:d2:39:ef:4f: + 42:f0:75:df:0a:90:c6:8e:20:6f:98:0f:f8:ac:23: + 5f:70:29:36:a4:c9:86:e7:b1:9a:20:cb:53:a5:85: + e7:3d:be:7d:9a:fe:24:45:33:dc:76:15:ed:0f:a2: + 71:64:4c:65:2e:81:68:45:a7 + Exponent: 65537 (0x10001) + Signature Algorithm: md2WithRSAEncryption + bb:4c:12:2b:cf:2c:26:00:4f:14:13:dd:a6:fb:fc:0a:11:84: + 8c:f3:28:1c:67:92:2f:7c:b6:c5:fa:df:f0:e8:95:bc:1d:8f: + 6c:2c:a8:51:cc:73:d8:a4:c0:53:f0:4e:d6:26:c0:76:01:57: + 81:92:5e:21:f1:d1:b1:ff:e7:d0:21:58:cd:69:17:e3:44:1c: + 9c:19:44:39:89:5c:dc:9c:00:0f:56:8d:02:99:ed:a2:90:45: + 4c:e4:bb:10:a4:3d:f0:32:03:0e:f1:ce:f8:e8:c9:51:8c:e6: + 62:9f:e6:9f:c0:7d:b7:72:9c:c9:36:3a:6b:9f:4e:a8:ff:64: + 0d:64 + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +MD5 Fingerprint: A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 +pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 +13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk +U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i +F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY +oJ2daZH9 +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 7d:d9:fe:07:cf:a8:1e:b7:10:79:67:fb:a7:89:34:c6 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Validity + Not Before: May 18 00:00:00 1998 GMT + Not After : Aug 1 23:59:59 2028 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:cc:5e:d1:11:5d:5c:69:d0:ab:d3:b9:6a:4c:99: + 1f:59:98:30:8e:16:85:20:46:6d:47:3f:d4:85:20: + 84:e1:6d:b3:f8:a4:ed:0c:f1:17:0f:3b:f9:a7:f9: + 25:d7:c1:cf:84:63:f2:7c:63:cf:a2:47:f2:c6:5b: + 33:8e:64:40:04:68:c1:80:b9:64:1c:45:77:c7:d8: + 6e:f5:95:29:3c:50:e8:34:d7:78:1f:a8:ba:6d:43: + 91:95:8f:45:57:5e:7e:c5:fb:ca:a4:04:eb:ea:97: + 37:54:30:6f:bb:01:47:32:33:cd:dc:57:9b:64:69: + 61:f8:9b:1d:1c:89:4f:5c:67 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 51:4d:cd:be:5c:cb:98:19:9c:15:b2:01:39:78:2e:4d:0f:67: + 70:70:99:c6:10:5a:94:a4:53:4d:54:6d:2b:af:0d:5d:40:8b: + 64:d3:d7:ee:de:56:61:92:5f:a6:c4:1d:10:61:36:d3:2c:27: + 3c:e8:29:09:b9:11:64:74:cc:b5:73:9f:1c:48:a9:bc:61:01: + ee:e2:17:a6:0c:e3:40:08:3b:0e:e7:eb:44:73:2a:9a:f1:69: + 92:ef:71:14:c3:39:ac:71:a7:91:09:6f:e4:71:06:b3:ba:59: + 57:26:79:00:f6:f8:0d:a2:33:30:28:d4:aa:58:a0:9d:9d:69: + 91:fd + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +MD5 Fingerprint: CD:68:B6:A7:C7:C4:CE:75:E0:1D:4F:57:44:61:92:09 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 9b:7e:06:49:a3:3e:62:b9:d5:ee:90:48:71:29:ef:57 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G3 + Validity + Not Before: Oct 1 00:00:00 1999 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:cb:ba:9c:52:fc:78:1f:1a:1e:6f:1b:37:73:bd: + f8:c9:6b:94:12:30:4f:f0:36:47:f5:d0:91:0a:f5: + 17:c8:a5:61:c1:16:40:4d:fb:8a:61:90:e5:76:20: + c1:11:06:7d:ab:2c:6e:a6:f5:11:41:8e:fa:2d:ad: + 2a:61:59:a4:67:26:4c:d0:e8:bc:52:5b:70:20:04: + 58:d1:7a:c9:a4:69:bc:83:17:64:ad:05:8b:bc:d0: + 58:ce:8d:8c:f5:eb:f0:42:49:0b:9d:97:27:67:32: + 6e:e1:ae:93:15:1c:70:bc:20:4d:2f:18:de:92:88: + e8:6c:85:57:11:1a:e9:7e:e3:26:11:54:a2:45:96: + 55:83:ca:30:89:e8:dc:d8:a3:ed:2a:80:3f:7f:79: + 65:57:3e:15:20:66:08:2f:95:93:bf:aa:47:2f:a8: + 46:97:f0:12:e2:fe:c2:0a:2b:51:e6:76:e6:b7:46: + b7:e2:0d:a6:cc:a8:c3:4c:59:55:89:e6:e8:53:5c: + 1c:ea:9d:f0:62:16:0b:a7:c9:5f:0c:f0:de:c2:76: + ce:af:f7:6a:f2:fa:41:a6:a2:33:14:c9:e5:7a:63: + d3:9e:62:37:d5:85:65:9e:0e:e6:53:24:74:1b:5e: + 1d:12:53:5b:c7:2c:e7:83:49:3b:15:ae:8a:68:b9: + 57:97 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 11:14:96:c1:ab:92:08:f7:3f:2f:c9:b2:fe:e4:5a:9f:64:de: + db:21:4f:86:99:34:76:36:57:dd:d0:15:2f:c5:ad:7f:15:1f: + 37:62:73:3e:d4:e7:5f:ce:17:03:db:35:fa:2b:db:ae:60:09: + 5f:1e:5f:8f:6e:bb:0b:3d:ea:5a:13:1e:0c:60:6f:b5:c0:b5: + 23:22:2e:07:0b:cb:a9:74:cb:47:bb:1d:c1:d7:a5:6b:cc:2f: + d2:42:fd:49:dd:a7:89:cf:53:ba:da:00:5a:28:bf:82:df:f8: + ba:13:1d:50:86:82:fd:8e:30:8f:29:46:b0:1e:3d:35:da:38: + 62:16:18:4a:ad:e6:b6:51:6c:de:af:62:eb:01:d0:1e:24:fe: + 7a:8f:12:1a:12:68:b8:fb:66:99:14:14:45:5c:ae:e7:ae:69: + 17:81:2b:5a:37:c9:5e:2a:f4:c6:e2:a1:5c:54:9b:a6:54:00: + cf:f0:f1:c1:c7:98:30:1a:3b:36:16:db:a3:6e:ea:fd:ad:b2: + c2:da:ef:02:47:13:8a:c0:f1:b3:31:ad:4f:1c:e1:4f:9c:af: + 0f:0c:9d:f7:78:0d:d8:f4:35:56:80:da:b7:6d:17:8f:9d:1e: + 81:64:e1:fe:c5:45:ba:ad:6b:b9:0a:7a:4e:4f:4b:84:ee:4b: + f1:7d:dd:11 + +Verisign Class 4 Public Primary Certification Authority - G2 +============================================================ +MD5 Fingerprint: 26:6D:2C:19:98:B6:70:68:38:50:54:19:EC:90:34:60 +PEM Data: +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM +HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK +qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj +cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y +cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP +T8qAkbYp +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 32:88:8e:9a:d2:f5:eb:13:47:f8:7f:c4:20:37:25:f8 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 4 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Validity + Not Before: May 18 00:00:00 1998 GMT + Not After : Aug 1 23:59:59 2028 GMT + Subject: C=US, O=VeriSign, Inc., OU=Class 4 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ba:f0:e4:cf:f9:c4:ae:85:54:b9:07:57:f9:8f: + c5:7f:68:11:f8:c4:17:b0:44:dc:e3:30:73:d5:2a: + 62:2a:b8:d0:cc:1c:ed:28:5b:7e:bd:6a:dc:b3:91: + 24:ca:41:62:3c:fc:02:01:bf:1c:16:31:94:05:97: + 76:6e:a2:ad:bd:61:17:6c:4e:30:86:f0:51:37:2a: + 50:c7:a8:62:81:dc:5b:4a:aa:c1:a0:b4:6e:eb:2f: + e5:57:c5:b1:2b:40:70:db:5a:4d:a1:8e:1f:bd:03: + 1f:d8:03:d4:8f:4c:99:71:bc:e2:82:cc:58:e8:98: + 3a:86:d3:86:38:f3:00:29:1f + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 85:8c:12:c1:a7:b9:50:15:7a:cb:3e:ac:b8:43:8a:dc:aa:dd: + 14:ba:89:81:7e:01:3c:23:71:21:88:2f:82:dc:63:fa:02:45: + ac:45:59:d7:2a:58:44:5b:b7:9f:81:3b:92:68:3d:e2:37:24: + f5:7b:6c:8f:76:35:96:09:a8:59:9d:b9:ce:23:ab:74:d6:83: + fd:32:73:27:d8:69:3e:43:74:f6:ae:c5:89:9a:e7:53:7c:e9: + 7b:f6:4b:f3:c1:65:83:de:8d:8a:9c:3c:88:8d:39:59:fc:aa: + 3f:22:8d:a1:c1:66:50:81:72:4c:ed:22:64:4f:4f:ca:80:91: + b6:29 + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +MD5 Fingerprint: DB:C8:F2:27:2E:B1:EA:6A:29:23:5D:FE:56:3E:33:DF +PEM Data: +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 +GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ ++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd +U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm +NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY +ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ +ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 +CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq +g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c +2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ +bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + ec:a0:a7:8b:6e:75:6a:01:cf:c4:7c:cc:2f:94:5e:d7 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 4 Public Primary Certification Authority - G3 + Validity + Not Before: Oct 1 00:00:00 1999 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 4 Public Primary Certification Authority - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ad:cb:a5:11:69:c6:59:ab:f1:8f:b5:19:0f:56: + ce:cc:b5:1f:20:e4:9e:26:25:4b:e0:73:65:89:59: + de:d0:83:e4:f5:0f:b5:bb:ad:f1:7c:e8:21:fc:e4: + e8:0c:ee:7c:45:22:19:76:92:b4:13:b7:20:5b:09: + fa:61:ae:a8:f2:a5:8d:85:c2:2a:d6:de:66:36:d2: + 9b:02:f4:a8:92:60:7c:9c:69:b4:8f:24:1e:d0:86: + 52:f6:32:9c:41:58:1e:22:bd:cd:45:62:95:08:6e: + d0:66:dd:53:a2:cc:f0:10:dc:54:73:8b:04:a1:46: + 33:33:5c:17:40:b9:9e:4d:d3:f3:be:55:83:e8:b1: + 89:8e:5a:7c:9a:96:22:90:3b:88:25:f2:d2:53:88: + 02:0c:0b:78:f2:e6:37:17:4b:30:46:07:e4:80:6d: + a6:d8:96:2e:e8:2c:f8:11:b3:38:0d:66:a6:9b:ea: + c9:23:5b:db:8e:e2:f3:13:8e:1a:59:2d:aa:02:f0: + ec:a4:87:66:dc:c1:3f:f5:d8:b9:f4:ec:82:c6:d2: + 3d:95:1d:e5:c0:4f:84:c9:d9:a3:44:28:06:6a:d7: + 45:ac:f0:6b:6a:ef:4e:5f:f8:11:82:1e:38:63:34: + 66:50:d4:3e:93:73:fa:30:c3:66:ad:ff:93:2d:97: + ef:03 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 8f:fa:25:6b:4f:5b:e4:a4:4e:27:55:ab:22:15:59:3c:ca:b5: + 0a:d4:4a:db:ab:dd:a1:5f:53:c5:a0:57:39:c2:ce:47:2b:be: + 3a:c8:56:bf:c2:d9:27:10:3a:b1:05:3c:c0:77:31:bb:3a:d3: + 05:7b:6d:9a:1c:30:8c:80:cb:93:93:2a:83:ab:05:51:82:02: + 00:11:67:6b:f3:88:61:47:5f:03:93:d5:5b:0d:e0:f1:d4:a1: + 32:35:85:b2:3a:db:b0:82:ab:d1:cb:0a:bc:4f:8c:5b:c5:4b: + 00:3b:1f:2a:82:a6:7e:36:85:dc:7e:3c:67:00:b5:e4:3b:52: + e0:a8:eb:5d:15:f9:c6:6d:f0:ad:1d:0e:85:b7:a9:9a:73:14: + 5a:5b:8f:41:28:c0:d5:e8:2d:4d:a4:5e:cd:aa:d9:ed:ce:dc: + d8:d5:3c:42:1d:17:c1:12:5d:45:38:c3:38:f3:fc:85:2e:83: + 46:48:b2:d7:20:5f:92:36:8f:e7:79:0f:98:5e:99:e8:f0:d0: + a4:bb:f5:53:bd:2a:ce:59:b0:af:6e:7f:6c:bb:d2:1e:00:b0: + 21:ed:f8:41:62:82:b9:d8:b2:c4:bb:46:50:f3:31:c5:8f:01: + a8:74:eb:f5:78:27:da:e7:f7:66:43:f3:9e:83:3e:20:aa:c3: + 35:60:91:ce + +Verisign/RSA Commercial CA +========================== +MD5 Fingerprint: 5A:0B:DD:42:9E:B2:B4:62:97:32:7F:7F:0A:AA:9A:39 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICIzCCAZACBQJBAAAWMA0GCSqGSIb3DQEBAgUAMFwxCzAJBgNVBAYTAlVTMSAw +HgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVy +Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NDExMDQxODU4MzRaFw05 +OTExMDMxODU4MzRaMFwxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdSU0EgRGF0YSBT +ZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVyY2lhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTCBmzANBgkqhkiG9w0BAQEFAAOBiQAwgYUCfgCk+4Fie84QJ93o +975sbsZwmdu41QUDaSiCnHJ/lj+O7Kwpkj+KFPhCdr69XQO5kNTQvAayUTNfxMK/ +touPmbZiImDd298ggrTKoi8tUO2UMt7gVY3UaOLgTNLNBRYulWZcYVI4HlGogqHE +7yXpCuaLK44xZtn42f29O2nZ6wIDAQABMA0GCSqGSIb3DQEBAgUAA34AdrW2EP4j +9/dZYkuwX5zBaLxJu7NJbyFHXSudVMQAKD+YufKKg5tgf+tQx6sFEC097TgCwaVI +0v5loMC86qYjFmZsGySp8+x5NRhPJsjjr1BKx6cxa9B8GJ1Qv6km+iYrRpwUqbtb +MJhCKLVLU7tDCZJAuqiqWqTGtotXTcU= +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 02:41:00:00:16 + Signature Algorithm: md2WithRSAEncryption + Issuer: C=US, O=RSA Data Security, Inc., OU=Commercial Certification Authority + Validity + Not Before: Nov 4 18:58:34 1994 GMT + Not After : Nov 3 18:58:34 1999 GMT + Subject: C=US, O=RSA Data Security, Inc., OU=Commercial Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1000 bit) + Modulus (1000 bit): + 00:a4:fb:81:62:7b:ce:10:27:dd:e8:f7:be:6c:6e: + c6:70:99:db:b8:d5:05:03:69:28:82:9c:72:7f:96: + 3f:8e:ec:ac:29:92:3f:8a:14:f8:42:76:be:bd:5d: + 03:b9:90:d4:d0:bc:06:b2:51:33:5f:c4:c2:bf:b6: + 8b:8f:99:b6:62:22:60:dd:db:df:20:82:b4:ca:a2: + 2f:2d:50:ed:94:32:de:e0:55:8d:d4:68:e2:e0:4c: + d2:cd:05:16:2e:95:66:5c:61:52:38:1e:51:a8:82: + a1:c4:ef:25:e9:0a:e6:8b:2b:8e:31:66:d9:f8:d9: + fd:bd:3b:69:d9:eb + Exponent: 65537 (0x10001) + Signature Algorithm: md2WithRSAEncryption + 76:b5:b6:10:fe:23:f7:f7:59:62:4b:b0:5f:9c:c1:68:bc:49: + bb:b3:49:6f:21:47:5d:2b:9d:54:c4:00:28:3f:98:b9:f2:8a: + 83:9b:60:7f:eb:50:c7:ab:05:10:2d:3d:ed:38:02:c1:a5:48: + d2:fe:65:a0:c0:bc:ea:a6:23:16:66:6c:1b:24:a9:f3:ec:79: + 35:18:4f:26:c8:e3:af:50:4a:c7:a7:31:6b:d0:7c:18:9d:50: + bf:a9:26:fa:26:2b:46:9c:14:a9:bb:5b:30:98:42:28:b5:4b: + 53:bb:43:09:92:40:ba:a8:aa:5a:a4:c6:b6:8b:57:4d:c5 + +Verisign/RSA Secure Server CA +============================= +MD5 Fingerprint: 74:7B:82:03:43:F0:00:9E:6B:B3:EC:47:BF:85:A5:93 +PEM Data: +-----BEGIN CERTIFICATE----- +MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD +VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0 +MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV +BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy +dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ +ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII +0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI +uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI +hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3 +YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc +1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA== +-----END CERTIFICATE----- +Certificate Ingredients: + Data: + Version: 1 (0x0) + Serial Number: + 02:ad:66:7e:4e:45:fe:5e:57:6f:3c:98:19:5e:dd:c0 + Signature Algorithm: md2WithRSAEncryption + Issuer: C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority + Validity + Not Before: Nov 9 00:00:00 1994 GMT + Not After : Jan 7 23:59:59 2010 GMT + Subject: C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1000 bit) + Modulus (1000 bit): + 00:92:ce:7a:c1:ae:83:3e:5a:aa:89:83:57:ac:25: + 01:76:0c:ad:ae:8e:2c:37:ce:eb:35:78:64:54:03: + e5:84:40:51:c9:bf:8f:08:e2:8a:82:08:d2:16:86: + 37:55:e9:b1:21:02:ad:76:68:81:9a:05:a2:4b:c9: + 4b:25:66:22:56:6c:88:07:8f:f7:81:59:6d:84:07: + 65:70:13:71:76:3e:9b:77:4c:e3:50:89:56:98:48: + b9:1d:a7:29:1a:13:2e:4a:11:59:9c:1e:15:d5:49: + 54:2c:73:3a:69:82:b1:97:39:9c:6d:70:67:48:e5: + dd:2d:d6:c8:1e:7b + Exponent: 65537 (0x10001) + Signature Algorithm: md2WithRSAEncryption + 65:dd:7e:e1:b2:ec:b0:e2:3a:e0:ec:71:46:9a:19:11:b8:d3: + c7:a0:b4:03:40:26:02:3e:09:9c:e1:12:b3:d1:5a:f6:37:a5: + b7:61:03:b6:5b:16:69:3b:c6:44:08:0c:88:53:0c:6b:97:49: + c7:3e:35:dc:6c:b9:bb:aa:df:5c:bb:3a:2f:93:60:b6:a9:4b: + 4d:f2:20:f7:cd:5f:7f:64:7b:8e:dc:00:5c:d7:fa:77:ca:39: + 16:59:6f:0e:ea:d3:b5:83:7f:4d:4d:42:56:76:b4:c9:5f:04: + f8:38:f8:eb:d2:5f:75:5f:cd:7b:fc:e5:8e:80:7c:fc:50 diff --git a/data/message_template.msg b/data/message_template.msg new file mode 100644 index 0000000..ce7e2a4 --- /dev/null +++ b/data/message_template.msg @@ -0,0 +1,9049 @@ +// Linden Lab development message templates + +version 2.0 + +// The Version 2.0 template requires preservation of message +// numbers. Each message must be numbered relative to the +// other messages of that type. The current highest number +// for each type is listed below: +// Low: 423 +// Medium: 18 +// High: 29 +// PLEASE UPDATE THIS WHEN YOU ADD A NEW MESSAGE! + + +// ************************************************************************* +// Test Message +// ************************************************************************* + +// Test Message + +{ + TestMessage Low 1 NotTrusted Zerocoded + { + TestBlock1 Single + { Test1 U32 } + } + { + NeighborBlock Multiple 4 + { Test0 U32 } + { Test1 U32 } + { Test2 U32 } + } +} + +// ************************************************************************* +// Messaging Internal Data Management Message +// ************************************************************************* + +// ************************* +// List fixed messages first +// ************************* + + +// Packet Ack - Ack a list of packets sent reliable +{ + PacketAck Fixed 0xFFFFFFFB NotTrusted Unencoded + { + Packets Variable + { ID U32 } + } +} + + +// OpenCircuit - Tells the recipient's messaging system to open the descibed circuit +{ + OpenCircuit Fixed 0xFFFFFFFC NotTrusted Unencoded UDPBlackListed + { + CircuitInfo Single + { IP IPADDR } + { Port IPPORT } + } +} + + +// CloseCircuit - Tells the recipient's messaging system to close the descibed circuit +{ + CloseCircuit Fixed 0xFFFFFFFD NotTrusted Unencoded +} + + +// ****************** +// End fixed messages +// ****************** + +// StartPingCheck - used to measure circuit ping times +// PingID is used to determine how backlogged the ping was that was +// returned (or how hosed the other side is) +{ + StartPingCheck High 1 NotTrusted Unencoded + { + PingID Single + { PingID U8 } + { OldestUnacked U32 } // Current oldest "unacked" packet on the sender side + } +} + +// CompletePingCheck - used to measure circuit ping times + +{ + CompletePingCheck High 2 NotTrusted Unencoded + { + PingID Single + { PingID U8 } + } +} + +// space->sim +// sim->sim +// AddCircuitCode - Tells the recipient's messaging system that this code +// is for a legal circuit +{ + AddCircuitCode Low 2 Trusted Unencoded + { + CircuitCode Single + { Code U32 } + { SessionID LLUUID } + { AgentID LLUUID } // WARNING - may be null in valid message + } +} + +// viewer->sim +// UseCircuitCode - Attempts to provide the recipient with IP and Port +// info. In the case of viewers, the id is the session id. For other +// machines it may be null. The session id will always be the session +// id of the process, which every server will generate on startup and +// the viewer will be handed after login. +{ + UseCircuitCode Low 3 NotTrusted Unencoded + { + CircuitCode Single + { Code U32 } + { SessionID LLUUID } + { ID LLUUID } // agent id + } +} + + +// ************************************************************************* +// SpaceServer to Simulator Messages +// ************************************************************************ + +// Neighbor List - Passed anytime neighbors change +{ + NeighborList High 3 Trusted Unencoded + { + NeighborBlock Multiple 4 + { IP IPADDR } + { Port IPPORT } + { PublicIP IPADDR } + { PublicPort IPPORT } + { RegionID LLUUID } + { Name Variable 1 } // string + { SimAccess U8 } + } +} + + +// AvatarTextureUpdate +// simulator -> dataserver +// reliable +{ + AvatarTextureUpdate Low 4 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { TexturesChanged BOOL } + } + { + WearableData Variable + { CacheID LLUUID } + { TextureIndex U8 } + { HostName Variable 1 } + } + { + TextureData Variable + { TextureID LLUUID } + } +} + + +// SimulatorMapUpdate +// simulator -> dataserver +// reliable +{ + SimulatorMapUpdate Low 5 Trusted Unencoded + { + MapData Single + { Flags U32 } + } +} + +// SimulatorSetMap +// simulator -> dataserver +// reliable +// Used to upload a map image into the database (currently used only for Land For Sale) +{ + SimulatorSetMap Low 6 Trusted Unencoded + { + MapData Single + { RegionHandle U64 } + { Type S32 } + { MapImage LLUUID } + } +} + +// SubscribeLoad +// spaceserver -> simulator +// reliable +{ + SubscribeLoad Low 7 Trusted Unencoded +} + +// UnsubscribeLoad +// spaceserver -> simulator +// reliable +{ + UnsubscribeLoad Low 8 Trusted Unencoded +} + + +// ************************************************************************ +// Simulator to SpaceServer Messages +// ************************************************************************ + +// SimulatorReady - indicates the sim has finished loading its state +// and is ready to receive updates from others +{ + SimulatorReady Low 9 Trusted Zerocoded + { + SimulatorBlock Single + { SimName Variable 1 } + { SimAccess U8 } + { RegionFlags U32 } + { RegionID LLUUID } + { EstateID U32 } + { ParentEstateID U32 } + } + { + TelehubBlock Single + { HasTelehub BOOL } + { TelehubPos LLVector3 } + } +} + +// TelehubInfo - fill in the UI for telehub creation floater. +// sim -> viewer +// reliable +{ + TelehubInfo Low 10 Trusted Unencoded + { + TelehubBlock Single + { ObjectID LLUUID } // null if no telehub + { ObjectName Variable 1 } // string + { TelehubPos LLVector3 } // fallback if viewer can't find object + { TelehubRot LLQuaternion } + } + { + SpawnPointBlock Variable + { SpawnPointPos LLVector3 } // relative to telehub position + } +} + +// SimulatorPresentAtLocation - indicates that the sim is present at a grid +// location and passes what it believes its neighbors are +{ + SimulatorPresentAtLocation Low 11 Trusted Unencoded + { + SimulatorPublicHostBlock Single + { Port IPPORT } + { SimulatorIP IPADDR } + { GridX U32 } + { GridY U32 } + } + { + NeighborBlock Multiple 4 + { IP IPADDR } + { Port IPPORT } + } + { + SimulatorBlock Single + { SimName Variable 1 } + { SimAccess U8 } + { RegionFlags U32 } + { RegionID LLUUID } + { EstateID U32 } + { ParentEstateID U32 } + } + { + TelehubBlock Variable + { HasTelehub BOOL } + { TelehubPos LLVector3 } + } +} + +// SimulatorLoad +// simulator -> spaceserver +// reliable +{ + SimulatorLoad Low 12 Trusted Unencoded + { + SimulatorLoad Single + { TimeDilation F32 } + { AgentCount S32 } + { CanAcceptAgents BOOL } + } + { + AgentList Variable + { CircuitCode U32 } + { X U8 } + { Y U8 } + } +} + +// Simulator Shutdown Request - Tells spaceserver that a simulator is trying to shutdown +{ + SimulatorShutdownRequest Low 13 Trusted Unencoded +} + +// **************************************************************************** +// Presense messages +// **************************************************************************** + +// sim -> dataserver +{ + RegionPresenceRequestByRegionID Low 14 Trusted Unencoded + { + RegionData Variable + { RegionID LLUUID } + } +} + +// sim -> dataserver +{ + RegionPresenceRequestByHandle Low 15 Trusted Unencoded + { + RegionData Variable + { RegionHandle U64 } + } +} + +// dataserver -> sim +{ + RegionPresenceResponse Low 16 Trusted Zerocoded + { + RegionData Variable + { RegionID LLUUID } + { RegionHandle U64 } + { InternalRegionIP IPADDR } + { ExternalRegionIP IPADDR } + { RegionPort IPPORT } + { ValidUntil F64 } + { Message Variable 1 } + } +} + + +// **************************************************************************** +// Simulator to dataserver messages +// **************************************************************************** + +// Updates SimName, EstateID and SimAccess using RegionID as a key +{ + UpdateSimulator Low 17 Trusted Unencoded + { + SimulatorInfo Single + { RegionID LLUUID } + { SimName Variable 1 } + { EstateID U32 } + { SimAccess U8 } + } +} + + +// record dwell time. +{ + LogDwellTime Low 18 Trusted Unencoded + { + DwellInfo Single + { AgentID LLUUID } + { SessionID LLUUID } + { Duration F32 } + { SimName Variable 1 } + { RegionX U32 } + { RegionY U32 } + { AvgAgentsInView U8 } + { AvgViewerFPS U8 } + } +} + +// Disabled feature response message +{ + FeatureDisabled Low 19 Trusted Unencoded + { + FailureInfo Single + { ErrorMessage Variable 1 } + { AgentID LLUUID } + { TransactionID LLUUID } + } +} + + +// record lost money transactions. This message could be generated +// from either the simulator or the dataserver, depending on how +// the transaction failed. +{ + LogFailedMoneyTransaction Low 20 Trusted Unencoded + { + TransactionData Single + { TransactionID LLUUID } + { TransactionTime U32 } // utc seconds since epoch + { TransactionType S32 } // see lltransactiontypes.h + { SourceID LLUUID } + { DestID LLUUID } // destination of the transfer + { Flags U8 } + { Amount S32 } + { SimulatorIP IPADDR } // U32 encoded IP + { GridX U32 } + { GridY U32 } + { FailureType U8 } + } +} + +// complaint/bug-report - sim -> dataserver. see UserReport for details. +// reliable +{ + UserReportInternal Low 21 Trusted Zerocoded + { + ReportData Single + { ReportType U8 } + { Category U8 } + { ReporterID LLUUID } + { ViewerPosition LLVector3 } + { AgentPosition LLVector3 } + { ScreenshotID LLUUID } + { ObjectID LLUUID } + { OwnerID LLUUID } + { LastOwnerID LLUUID } + { CreatorID LLUUID } + { RegionID LLUUID } + { AbuserID LLUUID } + { AbuseRegionName Variable 1 } + { AbuseRegionID LLUUID } + { Summary Variable 1 } + { Details Variable 2 } + { VersionString Variable 1 } + } +} + +// SetSimStatusInDatabase +// alters the "simulator" table in the database +// sim -> dataserver +// reliable +{ + SetSimStatusInDatabase Low 22 Trusted Unencoded + { + Data Single + { RegionID LLUUID } + { HostName Variable 1 } + { X S32 } + { Y S32 } + { PID S32 } + { AgentCount S32 } + { TimeToLive S32 } // in seconds + { Status Variable 1 } + } +} + +// SetSimPresenceInDatabase +// updates the "presence" table in the database to ensure +// that a given simulator is present and valid for a set amount of +// time +{ + SetSimPresenceInDatabase Low 23 Trusted Unencoded + { + SimData Single + { RegionID LLUUID } + { HostName Variable 1 } + { GridX U32 } + { GridY U32 } + { PID S32 } + { AgentCount S32 } + { TimeToLive S32 } // in seconds + { Status Variable 1 } + } +} + +// *************************************************************************** +// Economy messages +// *************************************************************************** + +// once we use local stats, this will include a region handle +{ + EconomyDataRequest Low 24 NotTrusted Unencoded +} + +// dataserver to sim, response w/ econ data +{ + EconomyData Low 25 Trusted Zerocoded + { + Info Single + { ObjectCapacity S32 } + { ObjectCount S32 } + { PriceEnergyUnit S32 } + { PriceObjectClaim S32 } + { PricePublicObjectDecay S32 } + { PricePublicObjectDelete S32 } + { PriceParcelClaim S32 } + { PriceParcelClaimFactor F32 } + { PriceUpload S32 } + { PriceRentLight S32 } + { TeleportMinPrice S32 } + { TeleportPriceExponent F32 } + { EnergyEfficiency F32 } + { PriceObjectRent F32 } + { PriceObjectScaleFactor F32 } + { PriceParcelRent S32 } + { PriceGroupCreate S32 } + } +} + +// *************************************************************************** +// Search messages +// *************************************************************************** + +// AvatarPickerRequest +// Get a list of names to select a person +// viewer -> sim -> data +// reliable +{ + AvatarPickerRequest Low 26 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { QueryID LLUUID } + } + { + Data Single + { Name Variable 1 } + } +} + +// backend implementation which tracks if the user is a god. +{ + AvatarPickerRequestBackend Low 27 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { QueryID LLUUID } + { GodLevel U8 } + } + { + Data Single + { Name Variable 1 } + } +} + +// AvatarPickerReply +// List of names to select a person +// reliable +{ + AvatarPickerReply Low 28 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { QueryID LLUUID } + } + { + Data Variable + { AvatarID LLUUID } + { FirstName Variable 1 } + { LastName Variable 1 } + } +} + +// PlacesQuery +// Used for getting a list of places for the group land panel +// and the user land holdings panel. NOT for the directory. +{ + PlacesQuery Low 29 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { QueryID LLUUID } + } + { + TransactionData Single + { TransactionID LLUUID } + } + { + QueryData Single + { QueryText Variable 1 } + { QueryFlags U32 } + { Category S8 } + { SimName Variable 1 } + } +} + +// PlacesReply +// dataserver -> simulator -> viewer +// If the user has specified a location, use that to compute +// global x,y,z. Otherwise, use center of the AABB. +// reliable +{ + PlacesReply Low 30 Trusted Zerocoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { QueryID LLUUID } + } + { + TransactionData Single + { TransactionID LLUUID } + } + { + QueryData Variable + { OwnerID LLUUID } + { Name Variable 1 } + { Desc Variable 1 } + { ActualArea S32 } + { BillableArea S32 } + { Flags U8 } + { GlobalX F32 } // meters + { GlobalY F32 } // meters + { GlobalZ F32 } // meters + { SimName Variable 1 } + { SnapshotID LLUUID } + { Dwell F32 } + { Price S32 } + //{ ProductSKU Variable 1 } + } +} + +// DirFindQuery viewer->sim +// Message to start asking questions for the directory +{ + DirFindQuery Low 31 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryText Variable 1 } + { QueryFlags U32 } + { QueryStart S32 } // prev/next page support + } +} + +// DirFindQueryBackend sim->data +// Trusted message generated by receipt of DirFindQuery to sim. +{ + DirFindQueryBackend Low 32 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryText Variable 1 } + { QueryFlags U32 } + { QueryStart S32 } // prev/next page support + { EstateID U32 } + { Godlike BOOL } + } +} + + +// DirPlacesQuery viewer->sim +// Used for the Find directory of places +{ + DirPlacesQuery Low 33 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryText Variable 1 } + { QueryFlags U32 } + { Category S8 } + { SimName Variable 1 } + { QueryStart S32 } + } +} + +// DirPlacesQueryBackend sim->dataserver +// Used for the Find directory of places. +{ + DirPlacesQueryBackend Low 34 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryText Variable 1 } + { QueryFlags U32 } + { Category S8 } + { SimName Variable 1 } + { EstateID U32 } + { Godlike BOOL } + { QueryStart S32 } + } +} + +// DirPlacesReply dataserver->sim->viewer +// If the user has specified a location, use that to compute +// global x,y,z. Otherwise, use center of the AABB. +// reliable +{ + DirPlacesReply Low 35 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Variable + { QueryID LLUUID } + } + { + QueryReplies Variable + { ParcelID LLUUID } + { Name Variable 1 } + { ForSale BOOL } + { Auction BOOL } + { Dwell F32 } + } + { + StatusData Variable + { Status U32 } + } +} + +// DirPeopleReply +{ + DirPeopleReply Low 36 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + } + { + QueryReplies Variable + { AgentID LLUUID } + { FirstName Variable 1 } + { LastName Variable 1 } + { Group Variable 1 } + { Online BOOL } + { Reputation S32 } + } +} + +// DirEventsReply +{ + DirEventsReply Low 37 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + } + { + QueryReplies Variable + { OwnerID LLUUID } + { Name Variable 1 } + { EventID U32 } + { Date Variable 1 } + { UnixTime U32 } + { EventFlags U32 } + } + { + StatusData Variable + { Status U32 } + } +} + +// DirGroupsReply +// dataserver -> userserver -> viewer +// reliable +{ + DirGroupsReply Low 38 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + } + { + QueryReplies Variable + { GroupID LLUUID } + { GroupName Variable 1 } // string + { Members S32 } + { SearchOrder F32 } + } +} + + +// DirClassifiedQuery viewer->sim +// reliable +{ + DirClassifiedQuery Low 39 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryText Variable 1 } + { QueryFlags U32 } + { Category U32 } + { QueryStart S32 } + } +} + +// DirClassifiedQueryBackend sim->dataserver +// reliable +{ + DirClassifiedQueryBackend Low 40 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryText Variable 1 } + { QueryFlags U32 } + { Category U32 } + { EstateID U32 } + { Godlike BOOL } + { QueryStart S32 } + } +} + +// DirClassifiedReply dataserver->sim->viewer +// reliable +{ + DirClassifiedReply Low 41 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + } + { + QueryReplies Variable + { ClassifiedID LLUUID } + { Name Variable 1 } + { ClassifiedFlags U8 } + { CreationDate U32 } + { ExpirationDate U32 } + { PriceForListing S32 } + } + { + StatusData Variable + { Status U32 } + } +} + + +// AvatarClassifiedReply +// dataserver -> simulator -> viewer +// Send the header information for this avatar's classifieds +// This fills in the tabs of the Classifieds panel. +// reliable +{ + AvatarClassifiedReply Low 42 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { TargetID LLUUID } + } + { + Data Variable + { ClassifiedID LLUUID } + { Name Variable 1 } + } +} + + +// ClassifiedInfoRequest +// viewer -> simulator +// simulator -> dataserver +// reliable +{ + ClassifiedInfoRequest Low 43 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ClassifiedID LLUUID } + } +} + + +// ClassifiedInfoReply +// dataserver -> simulator +// simulator -> viewer +// reliable +{ + ClassifiedInfoReply Low 44 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + Data Single + { ClassifiedID LLUUID } + { CreatorID LLUUID } + { CreationDate U32 } + { ExpirationDate U32 } + { Category U32 } + { Name Variable 1 } + { Desc Variable 2 } + { ParcelID LLUUID } + { ParentEstate U32 } + { SnapshotID LLUUID } + { SimName Variable 1 } + { PosGlobal LLVector3d } + { ParcelName Variable 1 } + { ClassifiedFlags U8 } + { PriceForListing S32 } + } +} + + +// ClassifiedInfoUpdate +// Update a classified. ParcelID and EstateID are set +// on the simulator as the message passes through. +// viewer -> simulator -> dataserver +// reliable +{ + ClassifiedInfoUpdate Low 45 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ClassifiedID LLUUID } + { Category U32 } + { Name Variable 1 } + { Desc Variable 2 } + { ParcelID LLUUID } + { ParentEstate U32 } + { SnapshotID LLUUID } + { PosGlobal LLVector3d } + { ClassifiedFlags U8 } + { PriceForListing S32 } + } +} + + +// ClassifiedDelete +// Delete a classified from the database. +// viewer -> simulator -> dataserver +// reliable +{ + ClassifiedDelete Low 46 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ClassifiedID LLUUID } + } +} + +// ClassifiedGodDelete +// Delete a classified from the database. +// QueryID is needed so database can send a repeat list of +// classified. +// viewer -> simulator -> dataserver +// reliable +{ + ClassifiedGodDelete Low 47 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ClassifiedID LLUUID } + { QueryID LLUUID } + } +} + + +// DirLandQuery viewer->sim +// Special query for the land for sale/auction panel. +// reliable +{ + DirLandQuery Low 48 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryFlags U32 } + { SearchType U32 } + { Price S32 } + { Area S32 } + { QueryStart S32 } + } +} + +// DirLandQueryBackend sim->dataserver +// Special query for the land for sale/auction panel. +{ + DirLandQueryBackend Low 49 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryFlags U32 } + { SearchType U32 } + { Price S32 } + { Area S32 } + { QueryStart S32 } + { EstateID U32 } + { Godlike BOOL } + } +} + +// DirLandReply +// dataserver -> simulator -> viewer +// reliable +{ + DirLandReply Low 50 Trusted Zerocoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + } + { + QueryReplies Variable + { ParcelID LLUUID } + { Name Variable 1 } + { Auction BOOL } + { ForSale BOOL } + { SalePrice S32 } + { ActualArea S32 } + //{ ProductSKU Variable 1 } + } +} + +// DEPRECATED: DirPopularQuery viewer->sim +// Special query for the land for sale/auction panel. +// reliable +{ + DirPopularQuery Low 51 NotTrusted Zerocoded Deprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryFlags U32 } + } +} + +// DEPRECATED: DirPopularQueryBackend sim->dataserver +// Special query for the land for sale/auction panel. +// reliable +{ + DirPopularQueryBackend Low 52 Trusted Zerocoded Deprecated + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + { QueryFlags U32 } + { EstateID U32 } + { Godlike BOOL } + } +} + +// DEPRECATED: DirPopularReply +// dataserver -> simulator -> viewer +// reliable +{ + DirPopularReply Low 53 Trusted Zerocoded Deprecated + { + AgentData Single + { AgentID LLUUID } + } + { + QueryData Single + { QueryID LLUUID } + } + { + QueryReplies Variable + { ParcelID LLUUID } + { Name Variable 1 } + { Dwell F32 } + } +} + +// ParcelInfoRequest +// viewer -> simulator -> dataserver +// reliable +{ + ParcelInfoRequest Low 54 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ParcelID LLUUID } + } +} + +// ParcelInfoReply +// dataserver -> simulator -> viewer +// reliable +{ + ParcelInfoReply Low 55 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + Data Single + { ParcelID LLUUID } + { OwnerID LLUUID } + { Name Variable 1 } + { Desc Variable 1 } + { ActualArea S32 } + { BillableArea S32 } + { Flags U8 } + { GlobalX F32 } // meters + { GlobalY F32 } // meters + { GlobalZ F32 } // meters + { SimName Variable 1 } + { SnapshotID LLUUID } + { Dwell F32 } + { SalePrice S32 } + { AuctionID S32 } + } +} + + +// ParcelObjectOwnersRequest +// viewer -> simulator +// reliable +{ + ParcelObjectOwnersRequest Low 56 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + } +} + + +// ParcelObjectOwnersReply +// simulator -> viewer +// reliable +{ + ParcelObjectOwnersReply Low 57 Trusted Zerocoded UDPDeprecated + { + Data Variable + { OwnerID LLUUID } + { IsGroupOwned BOOL } + { Count S32 } + { OnlineStatus BOOL } + } +} + +// GroupNoticeListRequest +// viewer -> simulator -> dataserver +// reliable +{ + GroupNoticesListRequest Low 58 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { GroupID LLUUID } + } +} + +// GroupNoticesListReply +// dataserver -> simulator -> viewer +// reliable +{ + GroupNoticesListReply Low 59 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + } + { + Data Variable + { NoticeID LLUUID } + { Timestamp U32 } + { FromName Variable 2 } + { Subject Variable 2 } + { HasAttachment BOOL } + { AssetType U8 } + } +} + +// GroupNoticeRequest +// viewer -> simulator +// simulator -> dataserver +// reliable +{ + GroupNoticeRequest Low 60 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { GroupNoticeID LLUUID } + } +} + +// GroupNoticeAdd +// Add a group notice. +// simulator -> dataserver +// reliable +{ + GroupNoticeAdd Low 61 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + MessageBlock Single + { ToGroupID LLUUID } + { ID LLUUID } + { Dialog U8 } + { FromAgentName Variable 1 } + { Message Variable 2 } + { BinaryBucket Variable 2 } + } +} + + +// **************************************************************************** +// Teleport messages +// +// The teleport messages are numerous, so I have attempted to give them a +// consistent naming convention. Since there is a bit of glob pattern +// aliasing, the rules are applied in order. +// +// Teleport* - viewer->sim or sim->viewer message which announces a +// teleportation request, progrees, start, or end. +// Data* - sim->data or data->sim trusted message. +// Space* - sim->space or space->sim trusted messaging +// *Lure - A lure message to pass around information. +// +// All actual viewer teleports will begin with a Teleport* message and +// end in a TeleportStart, TeleportLocal or TeleportFailed message. The TeleportFailed +// message may be returned by any process and must be routed through the +// teleporting agent's simulator and back to the viewer. +// **************************************************************************** + +// TeleportRequest +// viewer -> sim specifying exact teleport destination +{ + TeleportRequest Low 62 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Info Single + { RegionID LLUUID } + { Position LLVector3 } + { LookAt LLVector3 } + } +} + +// TeleportLocationRequest +// viewer -> sim specifying exact teleport destination +{ + TeleportLocationRequest Low 63 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Info Single + { RegionHandle U64 } + { Position LLVector3 } + { LookAt LLVector3 } + } +} + +// TeleportLocal +// sim -> viewer reply telling the viewer that we've successfully TP'd +// to somewhere else within the sim +{ + TeleportLocal Low 64 Trusted Unencoded + { + Info Single + { AgentID LLUUID } + { LocationID U32 } + { Position LLVector3 } // region + { LookAt LLVector3 } + { TeleportFlags U32 } + } +} + +// TeleportLandmarkRequest viewer->sim +// teleport to landmark asset ID destination. use LLUUD::null for home. +{ + TeleportLandmarkRequest Low 65 NotTrusted Zerocoded + { + Info Single + { AgentID LLUUID } + { SessionID LLUUID } + { LandmarkID LLUUID } + } +} + +// TeleportProgress sim->viewer +// Tell the agent how the teleport is going. +{ + TeleportProgress Low 66 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + Info Single + { TeleportFlags U32 } + { Message Variable 1 } // string + } +} + +// DataHomeLocationRequest sim->data +// Request +{ + DataHomeLocationRequest Low 67 Trusted Zerocoded + { + Info Single + { AgentID LLUUID } + { KickedFromEstateID U32 } + } + { + AgentInfo Single + { AgentEffectiveMaturity U32 } + } +} + +// DataHomeLocationReply data->sim +// response is the location of agent home. +{ + DataHomeLocationReply Low 68 Trusted Unencoded + { + Info Single + { AgentID LLUUID } + { RegionHandle U64 } + { Position LLVector3 } // region coords + { LookAt LLVector3 } + } +} + + +// TeleportFinish sim->viewer +// called when all of the information has been collected and readied for +// the agent. +{ + TeleportFinish Low 69 Trusted Unencoded UDPBlackListed + { + Info Single + { AgentID LLUUID } + { LocationID U32 } + { SimIP IPADDR } + { SimPort IPPORT } + { RegionHandle U64 } + { SeedCapability Variable 2 } // URL + { SimAccess U8 } + { TeleportFlags U32 } + } +} + +// StartLure viewer->sim +// Sent from viewer to the local simulator to lure target id to near +// agent id. This will generate an instant message that will be routed +// through the space server and out to the userserver. When that IM +// goes through the userserver and the TargetID is online, the +// userserver will send an InitializeLure to the spaceserver. When that +// packet is acked, the original instant message is finally forwarded to +// TargetID. +{ + StartLure Low 70 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Info Single + { LureType U8 } + { Message Variable 1 } + } + { + TargetData Variable + { TargetID LLUUID } + } +} + +// TeleportLureRequest viewer->sim +// Message from target of lure to begin the teleport process on the +// local simulator. +{ + TeleportLureRequest Low 71 NotTrusted Unencoded + { + Info Single + { AgentID LLUUID } + { SessionID LLUUID } + { LureID LLUUID } + { TeleportFlags U32 } + } +} + +// TeleportCancel viewer->sim +// reliable +{ + TeleportCancel Low 72 NotTrusted Unencoded + { + Info Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + + +// TeleportStart sim->viewer +// announce a successful teleport request to the viewer. +{ + TeleportStart Low 73 Trusted Unencoded + { + Info Single + { TeleportFlags U32 } + } +} + +// TeleportFailed somewhere->sim->viewer +// announce failure of teleport request +{ + TeleportFailed Low 74 Trusted Unencoded + { + Info Single + { AgentID LLUUID } + { Reason Variable 1 } // string + } + { + AlertInfo Variable + { Message Variable 1 } // string id + { ExtraParams Variable 1 } // llsd extra parameters + } +} + + +// *************************************************************************** +// Viewer to Simulator Messages +// *************************************************************************** + +// Undo +{ + Undo Low 75 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + ObjectData Variable + { ObjectID LLUUID } + } +} + + +// Redo +{ + Redo Low 76 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + ObjectData Variable + { ObjectID LLUUID } + } +} + +// UndoLand +{ + UndoLand Low 77 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + + +// AgentPause - viewer occasionally will block, inform simulator of this fact +{ + AgentPause Low 78 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { SerialNum U32 } // U32, used by both pause and resume. Non-increasing numbers are ignored. + } +} + +// AgentResume - unblock the agent +{ + AgentResume Low 79 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { SerialNum U32 } // U32, used by both pause and resume. Non-increasing numbers are ignored. + } +} + + +// AgentUpdate - Camera info sent from viewer to simulator +// or, more simply, two axes and compute cross product +// State data is temporary, indicates current behavior state: +// 0 = walking +// 1 = mouselook +// 2 = typing +// +// Center is region local (JNC 8.16.2001) +// Camera center is region local (JNC 8.29.2001) +{ + AgentUpdate High 4 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { BodyRotation LLQuaternion } + { HeadRotation LLQuaternion } + { State U8 } + { CameraCenter LLVector3 } + { CameraAtAxis LLVector3 } + { CameraLeftAxis LLVector3 } + { CameraUpAxis LLVector3 } + { Far F32 } + { ControlFlags U32 } + { Flags U8 } + } +} + +// ChatFromViewer +// Specifies the text to be said and the "type", +// normal speech, shout, whisper. +// with the specified radius +{ + ChatFromViewer Low 80 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ChatData Single + { Message Variable 2 } + { Type U8 } + { Channel S32 } + } +} + + +// AgentThrottle +{ + AgentThrottle Low 81 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { CircuitCode U32 } + } + { + Throttle Single + { GenCounter U32 } + { Throttles Variable 1 } + } +} + + +// AgentFOV - Update to agent's field of view, angle is vertical, single F32 float in radians +{ + AgentFOV Low 82 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { CircuitCode U32 } + } + { + FOVBlock Single + { GenCounter U32 } + { VerticalAngle F32 } + } +} + + +// AgentHeightWidth - Update to height and aspect, sent as height/width to save space +// Usually sent when window resized or created +{ + AgentHeightWidth Low 83 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { CircuitCode U32 } + } + { + HeightWidthBlock Single + { GenCounter U32 } + { Height U16 } + { Width U16 } + } +} + + +// AgentSetAppearance - Update to agent appearance +{ + AgentSetAppearance Low 84 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { SerialNum U32 } // U32, Increases every time the appearance changes. A value of 0 resets. + { Size LLVector3 } + } + { + WearableData Variable + { CacheID LLUUID } + { TextureIndex U8 } + } + { + ObjectData Single + { TextureEntry Variable 2 } + } + { + VisualParam Variable + { ParamValue U8 } + } +} + +// AgentAnimation - Update animation state +// viewer --> simulator +{ + AgentAnimation High 5 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + AnimationList Variable + { AnimID LLUUID } + { StartAnim BOOL } + } + { + PhysicalAvatarEventList Variable + { TypeData Variable 1 } + } +} + +// AgentRequestSit - Try to sit on an object +{ + AgentRequestSit High 6 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + TargetObject Single + { TargetID LLUUID } + { Offset LLVector3 } + } +} + +// AgentSit - Actually sit on object +{ + AgentSit High 7 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + + +// quit message sent between simulators +{ + AgentQuitCopy Low 85 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + FuseBlock Single + { ViewerCircuitCode U32 } + } +} + + +// Request Image - Sent by the viewer to request a specified image at a specified resolution + +{ + RequestImage High 8 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + RequestImage Variable + { Image LLUUID } + { DiscardLevel S8 } + { DownloadPriority F32 } + { Packet U32 } + { Type U8 } + } +} + +// ImageNotInDatabase +// Simulator informs viewer that a requsted image definitely does not exist in the asset database +{ + ImageNotInDatabase Low 86 Trusted Unencoded + { + ImageID Single + { ID LLUUID } + } +} + +// RebakeAvatarTextures +// simulator -> viewer request when a temporary baked avatar texture is not found +{ + RebakeAvatarTextures Low 87 Trusted Unencoded + { + TextureData Single + { TextureID LLUUID } + } +} + + +// SetAlwaysRun +// Lets the viewer choose between running and walking +{ + SetAlwaysRun Low 88 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { AlwaysRun BOOL } + } +} + +// ObjectAdd - create new object in the world +// Simulator will assign ID and send message back to signal +// object actually created. +// +// AddFlags (see also ObjectUpdate) +// 0x01 - use physics +// 0x02 - create selected +// +// If only one ImageID is sent for an object type that has more than +// one face, the same image is repeated on each subsequent face. +// +// Data field is opaque type-specific data for this object +{ + ObjectAdd Medium 1 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + ObjectData Single + { PCode U8 } + { Material U8 } + { AddFlags U32 } // see object_flags.h + + { PathCurve U8 } + { ProfileCurve U8 } + { PathBegin U16 } // 0 to 1, quanta = 0.01 + { PathEnd U16 } // 0 to 1, quanta = 0.01 + { PathScaleX U8 } // 0 to 1, quanta = 0.01 + { PathScaleY U8 } // 0 to 1, quanta = 0.01 + { PathShearX U8 } // -.5 to .5, quanta = 0.01 + { PathShearY U8 } // -.5 to .5, quanta = 0.01 + { PathTwist S8 } // -1 to 1, quanta = 0.01 + { PathTwistBegin S8 } // -1 to 1, quanta = 0.01 + { PathRadiusOffset S8 } // -1 to 1, quanta = 0.01 + { PathTaperX S8 } // -1 to 1, quanta = 0.01 + { PathTaperY S8 } // -1 to 1, quanta = 0.01 + { PathRevolutions U8 } // 0 to 3, quanta = 0.015 + { PathSkew S8 } // -1 to 1, quanta = 0.01 + { ProfileBegin U16 } // 0 to 1, quanta = 0.01 + { ProfileEnd U16 } // 0 to 1, quanta = 0.01 + { ProfileHollow U16 } // 0 to 1, quanta = 0.01 + + { BypassRaycast U8 } + { RayStart LLVector3 } + { RayEnd LLVector3 } + { RayTargetID LLUUID } + { RayEndIsIntersection U8 } + + { Scale LLVector3 } + { Rotation LLQuaternion } + + { State U8 } + } +} + + +// ObjectDelete +// viewer -> simulator +{ + ObjectDelete Low 89 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Force BOOL } // BOOL, god trying to force delete + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + + +// ObjectDuplicate +// viewer -> simulator +// Makes a copy of a set of objects, offset by a given amount +{ + ObjectDuplicate Low 90 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + SharedData Single + { Offset LLVector3 } + { DuplicateFlags U32 } // see object_flags.h + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + + +// ObjectDuplicateOnRay +// viewer -> simulator +// Makes a copy of an object, using the add object raycast +// code to abut it to other objects. +{ + ObjectDuplicateOnRay Low 91 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + { RayStart LLVector3 } // region local + { RayEnd LLVector3 } // region local + { BypassRaycast BOOL } + { RayEndIsIntersection BOOL } + { CopyCenters BOOL } + { CopyRotates BOOL } + { RayTargetID LLUUID } + { DuplicateFlags U32 } // see object_flags.h + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + + +// MultipleObjectUpdate +// viewer -> simulator +// updates position, rotation and scale in one message +// positions sent as region-local floats +{ + MultipleObjectUpdate Medium 2 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { Type U8 } + { Data Variable 1 } // custom type + } +} + +// RequestMultipleObjects +// viewer -> simulator +// reliable +// +// When the viewer gets a local_id/crc for an object that +// it either doesn't have, or doesn't have the current version +// of, it sends this upstream get get an update. +// +// CacheMissType 0 => full object (viewer doesn't have it) +// CacheMissType 1 => CRC mismatch only +{ + RequestMultipleObjects Medium 3 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { CacheMissType U8 } + { ID U32 } + } +} + + +// DEPRECATED: ObjectPosition +// == Old Behavior == +// Set the position on objects +// +// == Reason for deprecation == +// Unused code path was removed in the move to Havok4 +// Object position, scale and rotation messages were already unified +// to MultipleObjectUpdate and this message was unused cruft. +// +// == New Location == +// MultipleObjectUpdate can be used instead. +{ + ObjectPosition Medium 4 NotTrusted Zerocoded Deprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { Position LLVector3 } // region + } +} + + +// DEPRECATED: ObjectScale +// == Old Behavior == +// Set the scale on objects +// +// == Reason for deprecation == +// Unused code path was removed in the move to Havok4 +// Object position, scale and rotation messages were already unified +// to MultipleObjectUpdate and this message was unused cruft. +// +// == New Location == +// MultipleObjectUpdate can be used instead. +{ + ObjectScale Low 92 NotTrusted Zerocoded Deprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { Scale LLVector3 } + } +} + + +// ObjectRotation +// viewer -> simulator +{ + ObjectRotation Low 93 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { Rotation LLQuaternion } + } +} + + +// ObjectFlagUpdate +// viewer -> simulator +{ + ObjectFlagUpdate Low 94 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { ObjectLocalID U32 } + { UsePhysics BOOL } + { IsTemporary BOOL } + { IsPhantom BOOL } + { CastsShadows BOOL } + } + { + ExtraPhysics Variable + { PhysicsShapeType U8 } + { Density F32 } + { Friction F32 } + { Restitution F32 } + { GravityMultiplier F32 } + + } +} + + +// ObjectClickAction +// viewer -> simulator +{ + ObjectClickAction Low 95 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { ClickAction U8 } + } +} + + +// ObjectImage +// viewer -> simulator +{ + ObjectImage Low 96 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { MediaURL Variable 1 } + { TextureEntry Variable 2 } + } +} + + +{ + ObjectMaterial Low 97 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { Material U8 } + } +} + + +{ + ObjectShape Low 98 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { PathCurve U8 } + { ProfileCurve U8 } + { PathBegin U16 } // 0 to 1, quanta = 0.01 + { PathEnd U16 } // 0 to 1, quanta = 0.01 + { PathScaleX U8 } // 0 to 1, quanta = 0.01 + { PathScaleY U8 } // 0 to 1, quanta = 0.01 + { PathShearX U8 } // -.5 to .5, quanta = 0.01 + { PathShearY U8 } // -.5 to .5, quanta = 0.01 + { PathTwist S8 } // -1 to 1, quanta = 0.01 + { PathTwistBegin S8 } // -1 to 1, quanta = 0.01 + { PathRadiusOffset S8 } // -1 to 1, quanta = 0.01 + { PathTaperX S8 } // -1 to 1, quanta = 0.01 + { PathTaperY S8 } // -1 to 1, quanta = 0.01 + { PathRevolutions U8 } // 0 to 3, quanta = 0.015 + { PathSkew S8 } // -1 to 1, quanta = 0.01 + { ProfileBegin U16 } // 0 to 1, quanta = 0.01 + { ProfileEnd U16 } // 0 to 1, quanta = 0.01 + { ProfileHollow U16 } // 0 to 1, quanta = 0.01 + } +} + +{ + ObjectExtraParams Low 99 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { ParamType U16 } + { ParamInUse BOOL } + { ParamSize U32 } + { ParamData Variable 1 } + } +} + + +// ObjectOwner +// To make public, set OwnerID to LLUUID::null. +// TODO: Eliminate god-bit. Maybe not. God-bit is ok, because it's +// known on the server. +{ + ObjectOwner Low 100 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + HeaderData Single + { Override BOOL } // BOOL, God-bit. + { OwnerID LLUUID } + { GroupID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + +// ObjectGroup +// To make the object part of no group, set GroupID = LLUUID::null. +// This call only works if objectid.ownerid == agentid. +{ + ObjectGroup Low 101 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + +// Attempt to buy an object. This will only pack root objects. +{ + ObjectBuy Low 102 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + { CategoryID LLUUID } // folder where it goes (if derezed) + } + { + ObjectData Variable + { ObjectLocalID U32 } + { SaleType U8 } // U8 -> EForSale + { SalePrice S32 } + } +} + +// viewer -> simulator + +// buy object inventory. If the transaction succeeds, it will add +// inventory to the agent, and potentially remove the original. +{ + BuyObjectInventory Low 103 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ObjectID LLUUID } + { ItemID LLUUID } + { FolderID LLUUID } + } +} + +// sim -> viewer +// Used to propperly handle buying asset containers +{ + DerezContainer Low 104 Trusted Zerocoded + { + Data Single + { ObjectID LLUUID } + { Delete BOOL } // BOOL + } +} + +// ObjectPermissions +// Field - see llpermissionsflags.h +// If Set is true, tries to turn on bits in mask. +// If set is false, tries to turn off bits in mask. +// BUG: This just forces the permissions field. +{ + ObjectPermissions Low 105 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + HeaderData Single + { Override BOOL } // BOOL, God-bit. + } + { + ObjectData Variable + { ObjectLocalID U32 } + { Field U8 } + { Set U8 } + { Mask U32 } + } +} + +// set object sale information +{ + ObjectSaleInfo Low 106 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { LocalID U32 } + { SaleType U8 } // U8 -> EForSale + { SalePrice S32 } + } +} + + +// set object names +{ + ObjectName Low 107 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { LocalID U32 } + { Name Variable 1 } + } +} + +// set object descriptions +{ + ObjectDescription Low 108 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { LocalID U32 } + { Description Variable 1 } + } +} + +// set object category +{ + ObjectCategory Low 109 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { LocalID U32 } + { Category U32 } + } +} + +// ObjectSelect +// Variable object data because rectangular selection can +// generate a large list very quickly. +{ + ObjectSelect Low 110 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } + +} + + +// ObjectDeselect +{ + ObjectDeselect Low 111 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } + +} + +// ObjectAttach +{ + ObjectAttach Low 112 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { AttachmentPoint U8 } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { Rotation LLQuaternion } + } +} + +// ObjectDetach -- derezzes an attachment, marking its item in your inventory as not "(worn)" +{ + ObjectDetach Low 113 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + + +// ObjectDrop -- drops an attachment from your avatar onto the ground +{ + ObjectDrop Low 114 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + + +// ObjectLink +{ + ObjectLink Low 115 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + +// ObjectDelink +{ + ObjectDelink Low 116 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + } +} + + +// ObjectGrab +{ + ObjectGrab Low 117 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { LocalID U32 } + { GrabOffset LLVector3 } + } + { + SurfaceInfo Variable + { UVCoord LLVector3 } + { STCoord LLVector3 } + { FaceIndex S32 } + { Position LLVector3 } + { Normal LLVector3 } + { Binormal LLVector3 } + } +} + + +// ObjectGrabUpdate +// TODO: Quantize this data, reduce message size. +// TimeSinceLast could go to 1 byte, since capped +// at 100 on sim. +{ + ObjectGrabUpdate Low 118 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { ObjectID LLUUID } + { GrabOffsetInitial LLVector3 } // LLVector3 + { GrabPosition LLVector3 } // LLVector3, region local + { TimeSinceLast U32 } + } + { + SurfaceInfo Variable + { UVCoord LLVector3 } + { STCoord LLVector3 } + { FaceIndex S32 } + { Position LLVector3 } + { Normal LLVector3 } + { Binormal LLVector3 } + } + +} + + +// ObjectDeGrab +{ + ObjectDeGrab Low 119 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { LocalID U32 } + } + { + SurfaceInfo Variable + { UVCoord LLVector3 } + { STCoord LLVector3 } + { FaceIndex S32 } + { Position LLVector3 } + { Normal LLVector3 } + { Binormal LLVector3 } + } +} + + +// ObjectSpinStart +{ + ObjectSpinStart Low 120 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { ObjectID LLUUID } + } +} + + +// ObjectSpinUpdate +{ + ObjectSpinUpdate Low 121 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { ObjectID LLUUID } + { Rotation LLQuaternion } + } +} + + +// ObjectSpinStop +{ + ObjectSpinStop Low 122 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { ObjectID LLUUID } + } +} + +// Export selected objects +// viewer->sim +{ + ObjectExportSelected Low 123 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { RequestID LLUUID } + { VolumeDetail S16 } + } + { + ObjectData Variable + { ObjectID LLUUID } + } +} + + +// ModifyLand - sent to modify a piece of land on a simulator. +// viewer -> sim +{ + ModifyLand Low 124 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ModifyBlock Single + { Action U8 } + { BrushSize U8 } + { Seconds F32 } + { Height F32 } + } + { + ParcelData Variable + { LocalID S32 } + { West F32 } + { South F32 } + { East F32 } + { North F32 } + } + { + ModifyBlockExtended Variable + { BrushSize F32 } + } +} + + +// VelocityInterpolateOn +// viewer->sim +// requires administrative access +{ + VelocityInterpolateOn Low 125 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + + +// VelocityInterpolateOff +// viewer->sim +// requires administrative access +{ + VelocityInterpolateOff Low 126 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// Save State +// viewer->sim +// requires administrative access +{ + StateSave Low 127 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + DataBlock Single + { Filename Variable 1 } + } +} + +// ReportAutosaveCrash +// sim->launcher +{ + ReportAutosaveCrash Low 128 NotTrusted Unencoded + { + AutosaveData Single + { PID S32 } + { Status S32 } + } +} + +// SimWideDeletes +{ + SimWideDeletes Low 129 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + DataBlock Single + { TargetID LLUUID } + { Flags U32 } + } +} + +// RequestObjectPropertiesFamily +// Ask for extended information, such as creator, permissions, resources, etc. +// Medium frequency because it is driven by mouse hovering over objects, which +// occurs at high rates. +{ + RequestObjectPropertiesFamily Medium 5 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { RequestFlags U32 } + { ObjectID LLUUID } + } +} + + +// Track agent - this information is used when sending out the +// coarse location update so that we know who you are tracking. +// To stop tracking - send a null uuid as the prey. +{ + TrackAgent Low 130 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + TargetData Single + { PreyID LLUUID } + } +} + +// end viewer to simulator section + +{ + ViewerStats Low 131 NotTrusted Zerocoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { IP IPADDR } + { StartTime U32 } + { RunTime F32 } // F32 + { SimFPS F32 } // F32 + { FPS F32 } // F32 + { AgentsInView U8 } // + { Ping F32 } // F32 + { MetersTraveled F64 } + { RegionsVisited S32 } + { SysRAM U32 } + { SysOS Variable 1 } // String + { SysCPU Variable 1 } // String + { SysGPU Variable 1 } // String + } + + { + DownloadTotals Single + { World U32 } + { Objects U32 } + { Textures U32 } + } + + { + NetStats Multiple 2 + { Bytes U32 } + { Packets U32 } + { Compressed U32 } + { Savings U32 } + } + + { + FailStats Single + { SendPacket U32 } + { Dropped U32 } + { Resent U32 } + { FailedResends U32 } + { OffCircuit U32 } + { Invalid U32 } + } + + { + MiscStats Variable + { Type U32 } + { Value F64 } + } +} + +// ScriptAnswerYes +// reliable +{ + ScriptAnswerYes Low 132 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { TaskID LLUUID } + { ItemID LLUUID } + { Questions S32 } + } +} + + +// complaint/bug-report +// reliable +{ + UserReport Low 133 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ReportData Single + { ReportType U8 } // BUG=1, COMPLAINT=2 + { Category U8 } // see sequence.user_report_category + { Position LLVector3 } // screenshot position, region-local + { CheckFlags U8 } // checkboxflags + { ScreenshotID LLUUID } + { ObjectID LLUUID } + { AbuserID LLUUID } + { AbuseRegionName Variable 1 } + { AbuseRegionID LLUUID } + { Summary Variable 1 } + { Details Variable 2 } + { VersionString Variable 1 } + } +} + + +// *************************************************************************** +// Simulator to Viewer Messages +// *************************************************************************** + +// AlertMessage +// Specifies the text to be posted in an alert dialog +{ + AlertMessage Low 134 Trusted Unencoded + { + AlertData Single + { Message Variable 1 } + } + { + AlertInfo Variable + { Message Variable 1 } + { ExtraParams Variable 1 } + } +} + +// Send an AlertMessage to the named agent. +// usually dataserver->simulator +{ + AgentAlertMessage Low 135 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + AlertData Single + { Modal BOOL } + { Message Variable 1 } + } +} + + +// MeanCollisionAlert +// Specifies the text to be posted in an alert dialog +{ + MeanCollisionAlert Low 136 Trusted Zerocoded + { + MeanCollision Variable + { Victim LLUUID } + { Perp LLUUID } + { Time U32 } + { Mag F32 } + { Type U8 } + } +} + +// ViewerFrozenMessage +// Specifies the text to be posted in an alert dialog +{ + ViewerFrozenMessage Low 137 Trusted Unencoded + { + FrozenData Single + { Data BOOL } + } +} + +// Health Message +// Tells viewer what agent health is +{ + HealthMessage Low 138 Trusted Zerocoded + { + HealthData Single + { Health F32 } + } +} + +// ChatFromSimulator +// Chat text to appear on a user's screen +// Position is region local. +// Viewer can optionally use position to animate +// If audible is CHAT_NOT_AUDIBLE, message will not be valid +{ + ChatFromSimulator Low 139 Trusted Unencoded + { + ChatData Single + { FromName Variable 1 } + { SourceID LLUUID } // agent id or object id + { OwnerID LLUUID } // object's owner + { SourceType U8 } + { ChatType U8 } + { Audible U8 } + { Position LLVector3 } + { Message Variable 2 } // UTF-8 text + } +} + + +// Simulator statistics packet (goes out to viewer and dataserver/spaceserver) +{ + SimStats Low 140 Trusted Unencoded + { + Region Single + { RegionX U32 } + { RegionY U32 } + { RegionFlags U32 } + { ObjectCapacity U32 } + } + { + Stat Variable + { StatID U32 } + { StatValue F32 } + } + { + PidStat Single + { PID S32 } + } + { + RegionInfo Variable + { RegionFlagsExtended U64 } + } +} + +// viewer -> sim +// reliable +{ + RequestRegionInfo Low 141 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// RegionInfo +// Used to populate UI for both region/estate floater +// and god tools floater +// sim -> viewer +// reliable +{ + RegionInfo Low 142 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + RegionInfo Single + { SimName Variable 1 } // string + { EstateID U32 } + { ParentEstateID U32 } + { RegionFlags U32 } + { SimAccess U8 } + { MaxAgents U8 } + { BillableFactor F32 } + { ObjectBonusFactor F32 } + { WaterHeight F32 } + { TerrainRaiseLimit F32 } + { TerrainLowerLimit F32 } + { PricePerMeter S32 } + { RedirectGridX S32 } + { RedirectGridY S32 } + { UseEstateSun BOOL } + { SunHour F32 } // last value set by estate or region controls JC + } + { + RegionInfo2 Single + { ProductSKU Variable 1 } // string + { ProductName Variable 1 } // string + { MaxAgents32 U32 } // Identical to RegionInfo.MaxAgents but allows greater range + { HardMaxAgents U32 } + { HardMaxObjects U32 } + } + { + RegionInfo3 Variable + { RegionFlagsExtended U64 } + } +} + +// GodUpdateRegionInfo +// Sent from viewer to sim after a god has changed some +// of the parameters in the god tools floater +// viewer -> sim +// reliable +{ + GodUpdateRegionInfo Low 143 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + RegionInfo Single + { SimName Variable 1 } // string + { EstateID U32 } + { ParentEstateID U32 } + { RegionFlags U32 } + { BillableFactor F32 } + { PricePerMeter S32 } + { RedirectGridX S32 } + { RedirectGridY S32 } + } + { + RegionInfo2 Variable + { RegionFlagsExtended U64 } + } +} + +//NearestLandingRegionRequest +//sim->dataserver +//Sent from the region to the data server +//to request the most up to date region for the requesting +//region to redirect teleports to +{ + NearestLandingRegionRequest Low 144 Trusted Unencoded + { + RequestingRegionData Single + { RegionHandle U64 } + } +} + +//NearestLandingPointReply +//dataserver->sim +//Sent from the data server to a region in reply +//to the redirectregion request stating which region +//the requesting region should redirect teleports to if necessary +{ + NearestLandingRegionReply Low 145 Trusted Unencoded + { + LandingRegionData Single + { RegionHandle U64 } + } +} + +//NearestLandingPointUpdated +//sim->dataserver +//Sent from a region to the data server +//to have the dataserver note/clear in the db +//that the region has updated it's nearest landing point +{ + NearestLandingRegionUpdated Low 146 Trusted Unencoded + { + RegionData Single + { RegionHandle U64 } + } +} + + +//TeleportLandingStatusChanged +//sim->dataserver +//Sent from the region to the data server +//to note that the region's teleportation landing status has changed +{ + TeleportLandingStatusChanged Low 147 Trusted Unencoded + { + RegionData Single + { RegionHandle U64 } + } +} + +// RegionHandshake +// Sent by region to viewer after it has received UseCircuitCode +// from that viewer. +// sim -> viewer +// reliable +{ + RegionHandshake Low 148 Trusted Zerocoded + { + RegionInfo Single + { RegionFlags U32 } + { SimAccess U8 } + { SimName Variable 1 } // string + { SimOwner LLUUID } + { IsEstateManager BOOL } // this agent, for this sim + { WaterHeight F32 } + { BillableFactor F32 } + { CacheID LLUUID } + { TerrainBase0 LLUUID } + { TerrainBase1 LLUUID } + { TerrainBase2 LLUUID } + { TerrainBase3 LLUUID } + { TerrainDetail0 LLUUID } + { TerrainDetail1 LLUUID } + { TerrainDetail2 LLUUID } + { TerrainDetail3 LLUUID } + { TerrainStartHeight00 F32 } + { TerrainStartHeight01 F32 } + { TerrainStartHeight10 F32 } + { TerrainStartHeight11 F32 } + { TerrainHeightRange00 F32 } + { TerrainHeightRange01 F32 } + { TerrainHeightRange10 F32 } + { TerrainHeightRange11 F32 } + } + { + RegionInfo2 Single + { RegionID LLUUID } + } + { + RegionInfo3 Single + { CPUClassID S32 } + { CPURatio S32 } + { ColoName Variable 1 } // string + { ProductSKU Variable 1 } // string + { ProductName Variable 1 } // string + } + { + RegionInfo4 Variable + { RegionFlagsExtended U64 } + { RegionProtocols U64 } + } +} + +// RegionHandshakeReply +// viewer -> sim +// reliable +// Sent after viewer has initialized the (pre-existing) +// LLViewerRegion with the name, access level, etc. and +// has loaded the cache for the region. +// After the simulator receives this, it will start sending +// data about objects. +{ + RegionHandshakeReply Low 149 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + RegionInfo Single + { Flags U32 } + } +} + +// The CoarseLocationUpdate message is sent to notify the viewer of +// the location of mappable objects in the region. 1 meter resolution is +// sufficient for this. The index block is used to show where you are, +// and where someone you are tracking is located. They are -1 if not +// applicable. +{ + CoarseLocationUpdate Medium 6 Trusted Unencoded + { + Location Variable + { X U8 } + { Y U8 } + { Z U8 } // Z in meters / 4 + } + { + Index Single + { You S16 } + { Prey S16 } + } + { + AgentData Variable + { AgentID LLUUID } + } +} + +// ImageData - sent to viewer to transmit information about an image +{ + ImageData High 9 Trusted Unencoded + { + ImageID Single + { ID LLUUID } + { Codec U8 } + { Size U32 } + { Packets U16 } + } + { + ImageData Single + { Data Variable 2 } + } +} + +// ImagePacket - follow on image data for images having > 1 packet of data +{ + ImagePacket High 10 Trusted Unencoded + { + ImageID Single + { ID LLUUID } + { Packet U16 } + } + { + ImageData Single + { Data Variable 2 } + } +} + +// LayerData - Sent to viewer - encodes layer data + +{ + LayerData High 11 Trusted Unencoded + { + LayerID Single + { Type U8 } + + } + { + LayerData Single + { Data Variable 2 } + } +} + +// ObjectUpdate - Sent by objects from the simulator to the viewer +// +// If only one ImageID is sent for an object type that has more than +// one face, the same image is repeated on each subsequent face. +// +// NameValue is a list of name-value strings, separated by \n characters, +// terminated by \0 +// +// Data is type-specific opaque data for this object +{ + ObjectUpdate High 12 Trusted Zerocoded + { + RegionData Single + { RegionHandle U64 } + { TimeDilation U16 } + } + { + ObjectData Variable + { ID U32 } + { State U8 } + + { FullID LLUUID } + { CRC U32 } // TEMPORARY HACK FOR JAMES + { PCode U8 } + { Material U8 } + { ClickAction U8 } + { Scale LLVector3 } + { ObjectData Variable 1 } + + { ParentID U32 } + { UpdateFlags U32 } // U32, see object_flags.h + + { PathCurve U8 } + { ProfileCurve U8 } + { PathBegin U16 } // 0 to 1, quanta = 0.01 + { PathEnd U16 } // 0 to 1, quanta = 0.01 + { PathScaleX U8 } // 0 to 1, quanta = 0.01 + { PathScaleY U8 } // 0 to 1, quanta = 0.01 + { PathShearX U8 } // -.5 to .5, quanta = 0.01 + { PathShearY U8 } // -.5 to .5, quanta = 0.01 + { PathTwist S8 } // -1 to 1, quanta = 0.01 + { PathTwistBegin S8 } // -1 to 1, quanta = 0.01 + { PathRadiusOffset S8 } // -1 to 1, quanta = 0.01 + { PathTaperX S8 } // -1 to 1, quanta = 0.01 + { PathTaperY S8 } // -1 to 1, quanta = 0.01 + { PathRevolutions U8 } // 0 to 3, quanta = 0.015 + { PathSkew S8 } // -1 to 1, quanta = 0.01 + { ProfileBegin U16 } // 0 to 1, quanta = 0.01 + { ProfileEnd U16 } // 0 to 1, quanta = 0.01 + { ProfileHollow U16 } // 0 to 1, quanta = 0.01 + + { TextureEntry Variable 2 } + { TextureAnim Variable 1 } + + { NameValue Variable 2 } + { Data Variable 2 } + { Text Variable 1 } // llSetText() hovering text + { TextColor Fixed 4 } // actually, a LLColor4U + { MediaURL Variable 1 } // URL for web page, movie, etc. + + // Info for particle systems + { PSBlock Variable 1 } + + // Extra parameters + { ExtraParams Variable 1 } + + // info for looped attached sounds + // because these are almost always all zero + // the hit after zero-coding is only 2 bytes + // not the 42 you see here + { Sound LLUUID } + { OwnerID LLUUID } // HACK object's owner id, only set if non-null sound, for muting + { Gain F32 } + { Flags U8 } + { Radius F32 } // cutoff radius + + // joint info -- is sent in the update of each joint-child-root + { JointType U8 } + { JointPivot LLVector3 } + { JointAxisOrAnchor LLVector3 } + } +} + + +// ObjectUpdateCompressed +{ + ObjectUpdateCompressed High 13 Trusted Unencoded + { + RegionData Single + { RegionHandle U64 } + { TimeDilation U16 } + } + { + ObjectData Variable + { UpdateFlags U32 } + { Data Variable 2 } + } +} + +// ObjectUpdateCached +// reliable +{ + ObjectUpdateCached High 14 Trusted Unencoded + { + RegionData Single + { RegionHandle U64 } + { TimeDilation U16 } + } + { + ObjectData Variable + { ID U32 } + { CRC U32 } + { UpdateFlags U32 } + } +} + +// packed terse object update format +{ + ImprovedTerseObjectUpdate High 15 Trusted Unencoded + { + RegionData Single + { RegionHandle U64 } + { TimeDilation U16 } + } + { + ObjectData Variable + { Data Variable 1 } + { TextureEntry Variable 2 } + } +} + +// KillObject - Sent by objects to the viewer to tell them to kill themselves + +{ + KillObject High 16 Trusted Unencoded + { + ObjectData Variable + { ID U32 } + } +} + + +// CrossedRegion - new way to tell a viewer it has gone across a region +// boundary +{ + CrossedRegion Medium 7 Trusted Unencoded UDPBlackListed + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + RegionData Single + { SimIP IPADDR } + { SimPort IPPORT } + { RegionHandle U64 } + { SeedCapability Variable 2 } // URL + } + { + Info Single + { Position LLVector3 } + { LookAt LLVector3 } + } +} + +// SimulatorViewerTimeMessage - Allows viewer to resynch to world time + +{ + SimulatorViewerTimeMessage Low 150 Trusted Unencoded + { + TimeInfo Single + { UsecSinceStart U64 } + { SecPerDay U32 } + { SecPerYear U32 } + { SunDirection LLVector3 } + { SunPhase F32 } + { SunAngVelocity LLVector3 } + } +} + +// EnableSimulator - Preps a viewer to receive data from a simulator + +{ + EnableSimulator Low 151 Trusted Unencoded UDPBlackListed + { + SimulatorInfo Single + { Handle U64 } + { IP IPADDR } + { Port IPPORT } + } +} + +// DisableThisSimulator - Tells a viewer not to expect data from this simulator anymore + +{ + DisableSimulator Low 152 Trusted Unencoded +} + +// ConfirmEnableSimulator - A confirmation message sent from simulator to neighbors that the simulator +// has successfully been enabled by the viewer + +{ + ConfirmEnableSimulator Medium 8 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +//----------------------------------------------------------------------------- +// New Transfer system +//----------------------------------------------------------------------------- + +// Request a new transfer (target->source) +{ + TransferRequest Low 153 NotTrusted Zerocoded + { + TransferInfo Single + { TransferID LLUUID } + { ChannelType S32 } + { SourceType S32 } + { Priority F32 } + { Params Variable 2 } + } +} + +// Return info about a transfer/initiate transfer (source->target) +// Possibly should have a Params field like above +{ + TransferInfo Low 154 NotTrusted Zerocoded + { + TransferInfo Single + { TransferID LLUUID } + { ChannelType S32 } + { TargetType S32 } + { Status S32 } + { Size S32 } + { Params Variable 2 } + } +} + +{ + TransferPacket High 17 NotTrusted Unencoded + { + TransferData Single + { TransferID LLUUID } + { ChannelType S32 } + { Packet S32 } + { Status S32 } + { Data Variable 2 } + } +} + +// Abort a transfer in progress (either from target->source or source->target) +{ + TransferAbort Low 155 NotTrusted Zerocoded + { + TransferInfo Single + { TransferID LLUUID } + { ChannelType S32 } + } +} + + +//----------------------------------------------------------------------------- +// General file transfer +//----------------------------------------------------------------------------- + +// RequestXfer - request an arbitrary xfer +{ + RequestXfer Low 156 NotTrusted Zerocoded + { + XferID Single + { ID U64 } + { Filename Variable 1 } + { FilePath U8 } // ELLPath + { DeleteOnCompletion BOOL } // BOOL + { UseBigPackets BOOL } // BOOL + { VFileID LLUUID } + { VFileType S16 } + } +} + +// SendXferPacket - send an additional packet of an arbitrary xfer from sim -> viewer +{ + SendXferPacket High 18 NotTrusted Unencoded + { + XferID Single + { ID U64 } + { Packet U32 } + } + { + DataPacket Single + { Data Variable 2 } + } +} + +// ConfirmXferPacket +{ + ConfirmXferPacket High 19 NotTrusted Unencoded + { + XferID Single + { ID U64 } + { Packet U32 } + } +} + +// AbortXfer +{ + AbortXfer Low 157 NotTrusted Unencoded + { + XferID Single + { ID U64 } + { Result S32 } + } +} + +//----------------------------------------------------------------------------- +// Avatar information +//----------------------------------------------------------------------------- + + +// AvatarAnimation - Update animation state +// simulator --> viewer +{ + AvatarAnimation High 20 Trusted Unencoded + { + Sender Single + { ID LLUUID } + } + { + AnimationList Variable + { AnimID LLUUID } + { AnimSequenceID S32 } + } + { + AnimationSourceList Variable + { ObjectID LLUUID } + } + { + PhysicalAvatarEventList Variable + { TypeData Variable 1 } + } + +} + +// AvatarAppearance - Update visual params +{ + AvatarAppearance Low 158 Trusted Zerocoded + { + Sender Single + { ID LLUUID } + { IsTrial BOOL } + } + { + ObjectData Single + { TextureEntry Variable 2 } + } + { + VisualParam Variable + { ParamValue U8 } + } + { + AppearanceData Variable + { AppearanceVersion U8 } + { CofVersion S32 } + { Flags U32 } + } + { + AppearanceHover Variable + { HoverHeight LLVector3 } + } +} + +// AvatarSitResponse - response to a request to sit on an object +{ + AvatarSitResponse High 21 Trusted Zerocoded + { + SitObject Single + { ID LLUUID } + } + { + SitTransform Single + { AutoPilot BOOL } + { SitPosition LLVector3 } + { SitRotation LLQuaternion } + { CameraEyeOffset LLVector3 } + { CameraAtOffset LLVector3 } + { ForceMouselook BOOL } + } +} + +// SetFollowCamProperties +{ + SetFollowCamProperties Low 159 Trusted Unencoded + { + ObjectData Single + { ObjectID LLUUID } + } + { + CameraProperty Variable + { Type S32 } + { Value F32 } + } +} + +// ClearFollowCamProperties +{ + ClearFollowCamProperties Low 160 Trusted Unencoded + { + ObjectData Single + { ObjectID LLUUID } + } +} + +// CameraConstraint - new camera distance limit (based on collision with objects) +{ + CameraConstraint High 22 Trusted Zerocoded + { + CameraCollidePlane Single + { Plane LLVector4 } + } +} + +// ObjectProperties +// Extended information such as creator, permissions, etc. +// Medium because potentially driven by mouse hover events. +{ + ObjectProperties Medium 9 Trusted Zerocoded + { + ObjectData Variable + { ObjectID LLUUID } + { CreatorID LLUUID } + { OwnerID LLUUID } + { GroupID LLUUID } + { CreationDate U64 } + { BaseMask U32 } + { OwnerMask U32 } + { GroupMask U32 } + { EveryoneMask U32 } + { NextOwnerMask U32 } + { OwnershipCost S32 } +// { TaxRate F32 } // F32 + { SaleType U8 } // U8 -> EForSale + { SalePrice S32 } + { AggregatePerms U8 } + { AggregatePermTextures U8 } + { AggregatePermTexturesOwner U8 } + { Category U32 } // LLCategory + { InventorySerial S16 } // S16 + { ItemID LLUUID } + { FolderID LLUUID } + { FromTaskID LLUUID } + { LastOwnerID LLUUID } + { Name Variable 1 } + { Description Variable 1 } + { TouchName Variable 1 } + { SitName Variable 1 } + { TextureID Variable 1 } + } +} + +// ObjectPropertiesFamily +// Medium because potentially driven by mouse hover events. +{ + ObjectPropertiesFamily Medium 10 Trusted Zerocoded + { + ObjectData Single + { RequestFlags U32 } + { ObjectID LLUUID } + { OwnerID LLUUID } + { GroupID LLUUID } + { BaseMask U32 } + { OwnerMask U32 } + { GroupMask U32 } + { EveryoneMask U32 } + { NextOwnerMask U32 } + { OwnershipCost S32 } + { SaleType U8 } // U8 -> EForSale + { SalePrice S32 } + { Category U32 } // LLCategory + { LastOwnerID LLUUID } + { Name Variable 1 } + { Description Variable 1 } + } +} + +// RequestPayPrice +// viewer -> sim +{ + RequestPayPrice Low 161 NotTrusted Unencoded + { + ObjectData Single + { ObjectID LLUUID } + } +} + +// PayPriceReply +// sim -> viewer +{ + PayPriceReply Low 162 Trusted Unencoded + { + ObjectData Single + { ObjectID LLUUID } + { DefaultPayPrice S32 } + } + { + ButtonData Variable + + { PayButton S32 } + } +} + +// KickUser +// *FIXME* +// Kick off a logged-in user, such as when two people log in with the +// same account name. +// ROUTED dataserver -> userserver -> spaceserver -> simulator -> viewer +// reliable, but that may not matter if a system component is quitting +{ + KickUser Low 163 Trusted Unencoded + { + TargetBlock Single + { TargetIP IPADDR } // U32 encoded IP + { TargetPort IPPORT } + } + { + UserInfo Single + { AgentID LLUUID } + { SessionID LLUUID } + { Reason Variable 2 } // string + } +} + +// ack sent from the simulator up to the main database so that login +// can continue. +{ + KickUserAck Low 164 Trusted Unencoded + { + UserInfo Single + { SessionID LLUUID } + { Flags U32 } + } +} + +// GodKickUser +// When a god wants someone kicked +// viewer -> sim +// reliable +{ + GodKickUser Low 165 NotTrusted Unencoded + { + UserInfo Single + { GodID LLUUID } + { GodSessionID LLUUID } + { AgentID LLUUID } + { KickFlags U32 } + { Reason Variable 2 } // string + } +} + +// SystemKickUser +// user->space, reliable +{ + SystemKickUser Low 166 Trusted Unencoded + { + AgentInfo Variable + { AgentID LLUUID } + } +} + +// EjectUser +// viewer -> sim +// reliable +{ + EjectUser Low 167 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { TargetID LLUUID } + { Flags U32 } + } +} + +// FreezeUser +// Freeze someone who is on my land. +// viewer -> sim +// reliable +{ + FreezeUser Low 168 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { TargetID LLUUID } + { Flags U32 } + } +} + + +// AvatarPropertiesRequest +// viewer -> simulator +// reliable +{ + AvatarPropertiesRequest Low 169 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { AvatarID LLUUID } + } +} + +// AvatarPropertiesRequestBackend +// simulator -> dataserver +// reliable +{ + AvatarPropertiesRequestBackend Low 170 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { AvatarID LLUUID } + { GodLevel U8 } + { WebProfilesDisabled BOOL } + } +} +// AvatarPropertiesReply +// dataserver -> simulator +// simulator -> viewer +// reliable +{ + AvatarPropertiesReply Low 171 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } // your id + { AvatarID LLUUID } // avatar you're asking about + } + { + PropertiesData Single + { ImageID LLUUID } + { FLImageID LLUUID } + { PartnerID LLUUID } + { AboutText Variable 2 } // string, up to 512 + { FLAboutText Variable 1 } // string + { BornOn Variable 1 } // string + { ProfileURL Variable 1 } // string + { CharterMember Variable 1 } // special - usually U8 + { Flags U32 } + } +} + +{ + AvatarInterestsReply Low 172 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } // your id + { AvatarID LLUUID } // avatar you're asking about + } + { + PropertiesData Single + { WantToMask U32 } + { WantToText Variable 1 } // string + { SkillsMask U32 } + { SkillsText Variable 1 } // string + { LanguagesText Variable 1 } // string + } +} + +// AvatarGroupsReply +// dataserver -> simulator +// simulator -> viewer +// reliable +{ + AvatarGroupsReply Low 173 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } // your id + { AvatarID LLUUID } // avatar you're asking about + } + { + GroupData Variable + { GroupPowers U64 } + { AcceptNotices BOOL } + { GroupTitle Variable 1 } + { GroupID LLUUID } + { GroupName Variable 1 } + { GroupInsigniaID LLUUID } + } + { + NewGroupData Single + { ListInProfile BOOL } // whether group displays in profile + } +} + + +// AvatarPropertiesUpdate +// viewer -> simulator +// reliable +{ + AvatarPropertiesUpdate Low 174 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + PropertiesData Single + { ImageID LLUUID } + { FLImageID LLUUID } + { AboutText Variable 2 } // string, up to 512 + { FLAboutText Variable 1 } + { AllowPublish BOOL } // whether profile is externally visible or not + { MaturePublish BOOL } // profile is "mature" + { ProfileURL Variable 1 } // string + } +} + +// AvatarInterestsUpdate +// viewer -> simulator +// reliable +{ + AvatarInterestsUpdate Low 175 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + PropertiesData Single + { WantToMask U32 } + { WantToText Variable 1 } // string + { SkillsMask U32 } + { SkillsText Variable 1 } // string + { LanguagesText Variable 1 } // string + } +} + + + +// AvatarNotesReply +// dataserver -> simulator +// simulator -> viewer +// reliable +{ + AvatarNotesReply Low 176 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + Data Single + { TargetID LLUUID } + { Notes Variable 2 } // string + } +} + + +// AvatarNotesUpdate +// viewer -> simulator -> dataserver +// reliable +{ + AvatarNotesUpdate Low 177 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { TargetID LLUUID } + { Notes Variable 2 } // string + } +} + + +// AvatarPicksReply +// dataserver -> simulator -> viewer +// Send the header information for this avatar's picks +// This fills in the tabs of the Picks panel. +// reliable +{ + AvatarPicksReply Low 178 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { TargetID LLUUID } + } + { + Data Variable + { PickID LLUUID } + { PickName Variable 1 } // string + } +} + + +// EventInfoRequest +// viewer -> simulator +// simulator -> dataserver +// reliable +{ + EventInfoRequest Low 179 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + EventData Single + { EventID U32 } + } +} + + +// EventInfoReply +// dataserver -> simulator +// simulator -> viewer +// reliable +{ + EventInfoReply Low 180 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + EventData Single + { EventID U32 } + { Creator Variable 1 } + { Name Variable 1 } + { Category Variable 1 } + { Desc Variable 2 } + { Date Variable 1 } + { DateUTC U32 } + { Duration U32 } + { Cover U32 } + { Amount U32 } + { SimName Variable 1 } + { GlobalPos LLVector3d } + { EventFlags U32 } + } +} + + +// EventNotificationAddRequest +// viewer -> simulator +// simulator -> dataserver +// reliable +{ + EventNotificationAddRequest Low 181 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + EventData Single + { EventID U32 } + } +} + + +// EventNotificationRemoveRequest +// viewer -> simulator +// simulator -> dataserver +// reliable +{ + EventNotificationRemoveRequest Low 182 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + EventData Single + { EventID U32 } + } +} + +// EventGodDelete +// viewer -> simulator +// simulator -> dataserver +// QueryData is used to resend a search result after the deletion +// reliable +{ + EventGodDelete Low 183 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + EventData Single + { EventID U32 } + } + { + QueryData Single + { QueryID LLUUID } + { QueryText Variable 1 } + { QueryFlags U32 } + { QueryStart S32 } // prev/next page support + } +} + + +// PickInfoReply +// dataserver -> simulator +// simulator -> viewer +// reliable +{ + PickInfoReply Low 184 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + Data Single + { PickID LLUUID } + { CreatorID LLUUID } + { TopPick BOOL } + { ParcelID LLUUID } + { Name Variable 1 } + { Desc Variable 2 } + { SnapshotID LLUUID } + { User Variable 1 } + { OriginalName Variable 1 } + { SimName Variable 1 } + { PosGlobal LLVector3d } + { SortOrder S32 } + { Enabled BOOL } + } +} + + +// PickInfoUpdate +// Update a pick. ParcelID is set on the simulator as the message +// passes through. +// If TopPick is TRUE, the simulator will only pass on the message +// if the agent_id is a god. +// viewer -> simulator -> dataserver +// reliable +{ + PickInfoUpdate Low 185 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { PickID LLUUID } + { CreatorID LLUUID } + { TopPick BOOL } + { ParcelID LLUUID } + { Name Variable 1 } + { Desc Variable 2 } + { SnapshotID LLUUID } + { PosGlobal LLVector3d } + { SortOrder S32 } + { Enabled BOOL } + } +} + + +// PickDelete +// Delete a non-top pick from the database. +// viewer -> simulator -> dataserver +// reliable +{ + PickDelete Low 186 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { PickID LLUUID } + } +} + +// PickGodDelete +// Delete a pick from the database. +// QueryID is needed so database can send a repeat list of +// picks. +// viewer -> simulator -> dataserver +// reliable +{ + PickGodDelete Low 187 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { PickID LLUUID } + { QueryID LLUUID } + } +} + + +// ScriptQuestion +// reliable +{ + ScriptQuestion Low 188 Trusted Unencoded + { + Data Single + { TaskID LLUUID } + { ItemID LLUUID } + { ObjectName Variable 1 } + { ObjectOwner Variable 1 } + { Questions S32 } + } +} + +// ScriptControlChange +// reliable +{ + ScriptControlChange Low 189 Trusted Unencoded + { + Data Variable + { TakeControls BOOL } + { Controls U32 } + { PassToAgent BOOL } + } +} + +// ScriptDialog +// sim -> viewer +// reliable +{ + ScriptDialog Low 190 Trusted Zerocoded + { + Data Single + { ObjectID LLUUID } + { FirstName Variable 1 } + { LastName Variable 1 } + { ObjectName Variable 1 } + { Message Variable 2 } + { ChatChannel S32 } + { ImageID LLUUID } + } + { + Buttons Variable + { ButtonLabel Variable 1 } + } + { + OwnerData Variable + { OwnerID LLUUID } + } +} + + +// ScriptDialogReply +// viewer -> sim +// reliable +{ + ScriptDialogReply Low 191 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ObjectID LLUUID } + { ChatChannel S32 } + { ButtonIndex S32 } + { ButtonLabel Variable 1 } + } +} + + +// ForceScriptControlRelease +// reliable +{ + ForceScriptControlRelease Low 192 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// RevokePermissions +// reliable +{ + RevokePermissions Low 193 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { ObjectID LLUUID } + { ObjectPermissions U32 } + } +} + +// LoadURL +// sim -> viewer +// Ask the user if they would like to load a URL +// reliable +{ + LoadURL Low 194 Trusted Unencoded + { + Data Single + { ObjectName Variable 1 } + { ObjectID LLUUID } + { OwnerID LLUUID } + { OwnerIsGroup BOOL } + { Message Variable 1 } + { URL Variable 1 } + } +} + +// ScriptTeleportRequest +// reliable +{ + ScriptTeleportRequest Low 195 Trusted Unencoded + { + Data Single + { ObjectName Variable 1 } + { SimName Variable 1 } + { SimPosition LLVector3 } + { LookAt LLVector3 } + } +} + + + + +// *************************************************************************** +// Land Parcel system +// *************************************************************************** + +// ParcelOverlay +// We send N packets per region to the viewer. +// N = 4, currently. At 256x256 meter regions, 4x4 meter parcel grid, +// there are 4096 parcel units per region. At N = 4, that's 1024 units +// per packet, allowing 8 bit bytes. +// sim -> viewer +// reliable +{ + ParcelOverlay Low 196 Trusted Zerocoded + { + ParcelData Single + { SequenceID S32 } // 0...3, which piece of region + { Data Variable 2 } // packed bit-field, (grids*grids)/N + } +} + + +// ParcelPropertiesRequest +// SequenceID should be -1 or -2, and is echoed back in the +// parcel properties message. +// viewer -> sim +// reliable +{ + ParcelPropertiesRequest Medium 11 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { SequenceID S32 } + { West F32 } + { South F32 } + { East F32 } + { North F32 } + { SnapSelection BOOL } + } +} + +// ParcelPropertiesRequestByID +// viewer -> sim +// reliable +{ + ParcelPropertiesRequestByID Low 197 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { SequenceID S32 } + { LocalID S32 } + } +} + +// ParcelProperties +// sequence id = -1 for parcels that you explicitly selected +// For agents, sequence id increments every time the agent transits into +// a new parcel. It is used to detect out-of-order agent parcel info updates. +// Bitmap = packed bit field, one bit per parcel grid, on if that grid is +// part of the selected parcel. +// sim -> viewer +// WARNING: This packet is potentially large. With max length name, +// description, music URL and media URL, it is 1526 + sizeof ( LLUUID ) bytes. +{ + ParcelProperties High 23 Trusted Zerocoded + { + ParcelData Single + { RequestResult S32 } + { SequenceID S32 } + { SnapSelection BOOL } + { SelfCount S32 } + { OtherCount S32 } + { PublicCount S32 } + { LocalID S32 } + { OwnerID LLUUID } + { IsGroupOwned BOOL } + { AuctionID U32 } + { ClaimDate S32 } // time_t + { ClaimPrice S32 } + { RentPrice S32 } + { AABBMin LLVector3 } + { AABBMax LLVector3 } + { Bitmap Variable 2 } // packed bit-field + { Area S32 } + { Status U8 } // owned vs. pending + { SimWideMaxPrims S32 } + { SimWideTotalPrims S32 } + { MaxPrims S32 } + { TotalPrims S32 } + { OwnerPrims S32 } + { GroupPrims S32 } + { OtherPrims S32 } + { SelectedPrims S32 } + { ParcelPrimBonus F32 } + + { OtherCleanTime S32 } + + { ParcelFlags U32 } + { SalePrice S32 } + { Name Variable 1 } // string + { Desc Variable 1 } // string + { MusicURL Variable 1 } // string + { MediaURL Variable 1 } // string + { MediaID LLUUID } + { MediaAutoScale U8 } + { GroupID LLUUID } + { PassPrice S32 } + { PassHours F32 } + { Category U8 } + { AuthBuyerID LLUUID } + { SnapshotID LLUUID } + { UserLocation LLVector3 } + { UserLookAt LLVector3 } + { LandingType U8 } + { RegionPushOverride BOOL } + { RegionDenyAnonymous BOOL } + { RegionDenyIdentified BOOL } + { RegionDenyTransacted BOOL } + } + { + AgeVerificationBlock Single + { RegionDenyAgeUnverified BOOL } + } +} + +// ParcelPropertiesUpdate +// viewer -> sim +// reliable +{ + ParcelPropertiesUpdate Low 198 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + { Flags U32 } + + { ParcelFlags U32 } + { SalePrice S32 } + { Name Variable 1 } // string + { Desc Variable 1 } // string + { MusicURL Variable 1 } // string + { MediaURL Variable 1 } // string + { MediaID LLUUID } + { MediaAutoScale U8 } + { GroupID LLUUID } + { PassPrice S32 } + { PassHours F32 } + { Category U8 } + { AuthBuyerID LLUUID } + { SnapshotID LLUUID } + { UserLocation LLVector3 } + { UserLookAt LLVector3 } + { LandingType U8 } + } +} + +// ParcelReturnObjects +// viewer -> sim +// reliable +{ + ParcelReturnObjects Low 199 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + { ReturnType U32 } + } + { + TaskIDs Variable + { TaskID LLUUID } + } + { + OwnerIDs Variable + { OwnerID LLUUID } + } +} + +// ParcelSetOtherCleanTime +// viewer -> sim +// reliable +{ + ParcelSetOtherCleanTime Low 200 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + { OtherCleanTime S32 } + } +} + + +// Disable makes objects nonphysical and turns off their scripts. +// ParcelDisableObjects +// viewer -> sim +// reliable +{ + ParcelDisableObjects Low 201 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + { ReturnType U32 } + } + { + TaskIDs Variable + { TaskID LLUUID } + } + { + OwnerIDs Variable + { OwnerID LLUUID } + } +} + + +// ParcelSelectObjects +// viewer -> sim +// reliable +{ + ParcelSelectObjects Low 202 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + { ReturnType U32 } + } + { + ReturnIDs Variable + { ReturnID LLUUID } + } +} + + +// EstateCovenantRequest +// viewer -> sim +// reliable +{ + EstateCovenantRequest Low 203 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// EstateCovenantReply +// sim -> viewer +// reliable +{ + EstateCovenantReply Low 204 Trusted Unencoded + { + Data Single + { CovenantID LLUUID } + { CovenantTimestamp U32 } + { EstateName Variable 1 } // string + { EstateOwnerID LLUUID } + } +} + + +// ForceObjectSelect +// sim -> viewer +// reliable +{ + ForceObjectSelect Low 205 Trusted Unencoded + { + Header Single + { ResetList BOOL } + } + { + Data Variable + { LocalID U32 } + } +} + + +// ParcelBuyPass - purchase a temporary access pass +// viewer -> sim +// reliable +{ + ParcelBuyPass Low 206 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + } +} + +// ParcelDeedToGroup - deed a patch of land to a group +// viewer -> sim +// reliable +{ + ParcelDeedToGroup Low 207 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { GroupID LLUUID } + { LocalID S32 } // parcel id + } +} + +// reserved for when island owners force re-claim parcel +{ + ParcelReclaim Low 208 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { LocalID S32 } // parcel id + } +} + +// ParcelClaim - change the owner of a patch of land +// viewer -> sim +// reliable +{ + ParcelClaim Low 209 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { GroupID LLUUID } + { IsGroupOwned BOOL } + { Final BOOL } // true if buyer is in tier + } + { + ParcelData Variable + { West F32 } + { South F32 } + { East F32 } + { North F32 } + } +} + +// ParcelJoin - Take all parcels which are owned by agent and inside +// rectangle, and make them 1 parcel if they all are leased. +// viewer -> sim +// reliable +{ + ParcelJoin Low 210 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { West F32 } + { South F32 } + { East F32 } + { North F32 } + } +} + +// ParcelDivide +// If the selection is a subsection of exactly one parcel, +// chop out that section and make a new parcel of it. +// viewer -> sim +// reliable +{ + ParcelDivide Low 211 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { West F32 } + { South F32 } + { East F32 } + { North F32 } + } +} + +// ParcelRelease +// Release a parcel to public +// viewer -> sim +// reliable +{ + ParcelRelease Low 212 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { LocalID S32 } // parcel ID + } +} + +// ParcelBuy - change the owner of a patch of land. +// viewer -> sim +// reliable +{ + ParcelBuy Low 213 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { GroupID LLUUID } + { IsGroupOwned BOOL } + { RemoveContribution BOOL } + { LocalID S32 } + { Final BOOL } // true if buyer is in tier + } + { + ParcelData Single + { Price S32 } + { Area S32 } + } +} + + +// ParcelGodForceOwner Unencoded +{ + ParcelGodForceOwner Low 214 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { OwnerID LLUUID } + { LocalID S32 } // parcel ID + } +} + + +// viewer -> sim +// ParcelAccessListRequest +{ + ParcelAccessListRequest Low 215 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { SequenceID S32 } + { Flags U32 } + { LocalID S32 } + } +} + + +// sim -> viewer +// ParcelAccessListReply +{ + ParcelAccessListReply Low 216 Trusted Zerocoded + { + Data Single + { AgentID LLUUID } + { SequenceID S32 } + { Flags U32 } + { LocalID S32 } + } + { + List Variable + { ID LLUUID } + { Time S32 } // time_t + { Flags U32 } + } +} + +// viewer -> sim +// ParcelAccessListUpdate +{ + ParcelAccessListUpdate Low 217 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { Flags U32 } + { LocalID S32 } + { TransactionID LLUUID } + { SequenceID S32 } + { Sections S32 } + } + { + List Variable + { ID LLUUID } + { Time S32 } // time_t + { Flags U32 } + } +} + + +// viewer -> sim -> dataserver +// reliable +{ + ParcelDwellRequest Low 218 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { LocalID S32 } + { ParcelID LLUUID } // filled in on sim + } +} + + +// dataserver -> sim -> viewer +// reliable +{ + ParcelDwellReply Low 219 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + Data Single + { LocalID S32 } + { ParcelID LLUUID } + { Dwell F32 } + } +} + +// sim -> dataserver +// This message is used to check if a user can buy a parcel. If +// successful, the transaction is approved through a money balance reply +// with the same transaction id. +{ + RequestParcelTransfer Low 220 Trusted Zerocoded + { + Data Single + { TransactionID LLUUID } + { TransactionTime U32 } // utc seconds since epoch + { SourceID LLUUID } + { DestID LLUUID } + { OwnerID LLUUID } + { Flags U8 } // see lltransactiontypes.h + { TransactionType S32 } // see lltransactiontypes.h + { Amount S32 } + { BillableArea S32 } + { ActualArea S32 } + { Final BOOL } // true if buyer should be in tier + } + { + RegionData Single // included so region name shows up in transaction logs + { RegionID LLUUID } + { GridX U32 } + { GridY U32 } + } +} + +// sim ->dataserver +// This message is used to send up complete parcel properties for +// persistance in the database. +// If you add something here, you should probably also change the +// simulator's database update query on startup. +{ + UpdateParcel Low 221 Trusted Zerocoded + { + ParcelData Single + { ParcelID LLUUID } + { RegionHandle U64 } + { OwnerID LLUUID } + { GroupOwned BOOL } + { Status U8 } + { Name Variable 1 } + { Description Variable 1 } + { MusicURL Variable 1 } + { RegionX F32 } + { RegionY F32 } + { ActualArea S32 } + { BillableArea S32 } + { ShowDir BOOL } + { IsForSale BOOL } + { Category U8 } + { SnapshotID LLUUID } + { UserLocation LLVector3 } + { SalePrice S32 } + { AuthorizedBuyerID LLUUID } + { AllowPublish BOOL } + { MaturePublish BOOL } + } +} + +// sim -> dataserver or space ->sim +// This message is used to tell the dataserver that a parcel has been +// removed. +{ + RemoveParcel Low 222 Trusted Unencoded + { + ParcelData Variable + { ParcelID LLUUID } + } +} + +// sim -> dataserver +// Merges some of the database information for parcels (dwell). +{ + MergeParcel Low 223 Trusted Unencoded + { + MasterParcelData Single + { MasterID LLUUID } + } + { + SlaveParcelData Variable + { SlaveID LLUUID } + } +} + +// sim -> dataserver +{ + LogParcelChanges Low 224 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + RegionData Single + { RegionHandle U64 } + } + { + ParcelData Variable + { ParcelID LLUUID } + { OwnerID LLUUID } + { IsOwnerGroup BOOL } + { ActualArea S32 } + { Action S8 } + { TransactionID LLUUID } + } +} + +// sim -> dataserver +{ + CheckParcelSales Low 225 Trusted Unencoded + { + RegionData Variable + { RegionHandle U64 } + } +} + +// dataserver -> simulator +// tell a particular simulator to finish parcel sale. +{ + ParcelSales Low 226 Trusted Unencoded + { + ParcelData Variable + { ParcelID LLUUID } + { BuyerID LLUUID } + } +} + +// viewer -> sim +// mark parcel and double secret agent content on parcel as owned by +// governor/maint and adjusts permissions approriately. Godlike request. +{ + ParcelGodMarkAsContent Low 227 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + } +} + + +// viewer -> sim +// start an auction. viewer fills in the appropriate date, simulator +// validates and fills in the rest of the information to start an auction +// on a parcel. Processing currently requires that AgentID is a god. +{ + ViewerStartAuction Low 228 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ParcelData Single + { LocalID S32 } + { SnapshotID LLUUID } + } +} + +// sim -> dataserver +// Once all of the data has been gathered, +{ + StartAuction Low 229 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + ParcelData Single + { ParcelID LLUUID } + { SnapshotID LLUUID } + { Name Variable 1 } // string + } +} + +// dataserver -> sim +{ + ConfirmAuctionStart Low 230 Trusted Unencoded + { + AuctionData Single + { ParcelID LLUUID } + { AuctionID U32 } + } +} + +// sim -> dataserver +// Tell the dataserver that an auction has completed. +{ + CompleteAuction Low 231 Trusted Unencoded + { + ParcelData Variable + { ParcelID LLUUID } + } +} + +// Tell the dataserver that an auction has been canceled. +{ + CancelAuction Low 232 Trusted Unencoded + { + ParcelData Variable + { ParcelID LLUUID } + } +} + +// sim -> dataserver +{ + CheckParcelAuctions Low 233 Trusted Unencoded + { + RegionData Variable + { RegionHandle U64 } + } +} + +// dataserver -> sim +// tell a particular simulator to finish parcel sale. +{ + ParcelAuctions Low 234 Trusted Unencoded + { + ParcelData Variable + { ParcelID LLUUID } + { WinnerID LLUUID } + } +} + +// *************************************************************************** +// UUID to name lookup +// *************************************************************************** + +// UUIDNameRequest +// Translate a UUID into first and last names +{ + UUIDNameRequest Low 235 NotTrusted Unencoded + { + UUIDNameBlock Variable + { ID LLUUID } + } +} + +// UUIDNameReply +// Translate a UUID into first and last names +{ + UUIDNameReply Low 236 Trusted Unencoded + { + UUIDNameBlock Variable + { ID LLUUID } + { FirstName Variable 1 } + { LastName Variable 1 } + } +} + +// UUIDGroupNameRequest +// Translate a UUID into a group name +{ + UUIDGroupNameRequest Low 237 NotTrusted Unencoded + { + UUIDNameBlock Variable + { ID LLUUID } + } +} + +// UUIDGroupNameReply +// Translate a UUID into a group name +{ + UUIDGroupNameReply Low 238 Trusted Unencoded + { + UUIDNameBlock Variable + { ID LLUUID } + { GroupName Variable 1 } + } +} + +// end uuid to name lookup + +// *************************************************************************** +// Simulator to Simulator Messages +// *************************************************************************** + +// ChatPass +// Chat message transmission to neighbors +// Chat is region local to receiving simulator. +// Type is one of CHAT_TYPE_NORMAL, _WHISPER, _SHOUT +{ + ChatPass Low 239 Trusted Zerocoded + { + ChatData Single + { Channel S32 } + { Position LLVector3 } + { ID LLUUID } + { OwnerID LLUUID } + { Name Variable 1 } + { SourceType U8 } + { Type U8 } + { Radius F32 } + { SimAccess U8 } + { Message Variable 2 } + } +} + +// Edge data - compressed edge data + +{ + EdgeDataPacket High 24 Trusted Zerocoded + { + EdgeData Single + { LayerType U8 } + { Direction U8 } + { LayerData Variable 2 } + } +} + +// Sim status, condition of this sim +// sent reliably, when dirty +{ + SimStatus Medium 12 Trusted Unencoded + { + SimStatus Single + { CanAcceptAgents BOOL } + { CanAcceptTasks BOOL } + } +} + +// Child Agent Update - agents send child agents to neighboring simulators. +// This will create a child camera if there isn't one at the target already +// Can't send viewer IP and port between simulators -- the port may get remapped +// if the viewer is behind a Network Address Translation (NAT) box. +// +// Note: some of the fields of this message really only need to be sent when an +// agent crosses a region boundary and changes from a child to a main agent +// (such as Head/BodyRotation, ControlFlags, Animations etc) +// simulator -> simulator +// reliable +{ + ChildAgentUpdate High 25 Trusted Zerocoded + { + AgentData Single + + { RegionHandle U64 } + { ViewerCircuitCode U32 } + { AgentID LLUUID } + { SessionID LLUUID } + + { AgentPos LLVector3 } + { AgentVel LLVector3 } + { Center LLVector3 } + { Size LLVector3 } + { AtAxis LLVector3 } + { LeftAxis LLVector3 } + { UpAxis LLVector3 } + { ChangedGrid BOOL } // BOOL + + { Far F32 } + { Aspect F32 } + { Throttles Variable 1 } + { LocomotionState U32 } + { HeadRotation LLQuaternion } + { BodyRotation LLQuaternion } + { ControlFlags U32 } + { EnergyLevel F32 } + { GodLevel U8 } // Changed from BOOL to U8, and renamed GodLevel (from Godlike) + { AlwaysRun BOOL } + { PreyAgent LLUUID } + { AgentAccess U8 } + { AgentTextures Variable 2 } + { ActiveGroupID LLUUID } + } + { + GroupData Variable + { GroupID LLUUID } + { GroupPowers U64 } + { AcceptNotices BOOL } + } + { + AnimationData Variable + { Animation LLUUID } + { ObjectID LLUUID } + } + { + GranterBlock Variable + { GranterID LLUUID } + } + { + NVPairData Variable + { NVPairs Variable 2 } + } + { + VisualParam Variable + { ParamValue U8 } + } + { + AgentAccess Variable + { AgentLegacyAccess U8 } + { AgentMaxAccess U8 } + } + { + AgentInfo Variable + { Flags U32 } + } +} + +// ChildAgentAlive +// sent to child agents just to keep them alive +{ + ChildAgentAlive High 26 Trusted Unencoded + { + AgentData Single + { RegionHandle U64 } + { ViewerCircuitCode U32 } + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// ChildAgentPositionUpdate +// sent to child agents just to keep them alive +{ + ChildAgentPositionUpdate High 27 Trusted Unencoded + { + AgentData Single + + { RegionHandle U64 } + { ViewerCircuitCode U32 } + { AgentID LLUUID } + { SessionID LLUUID } + + { AgentPos LLVector3 } + { AgentVel LLVector3 } + { Center LLVector3 } + { Size LLVector3 } + { AtAxis LLVector3 } + { LeftAxis LLVector3 } + { UpAxis LLVector3 } + { ChangedGrid BOOL } + } +} + + +// Obituary for child agents - make sure the parent know the child is dead +// This way, children can be reliably restarted +{ + ChildAgentDying Low 240 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + + +// This is sent if a full child agent hasn't been accepted yet +{ + ChildAgentUnknown Low 241 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + + +// This message is sent how objects get passed between regions. +{ + AtomicPassObject High 28 Trusted Unencoded + { + TaskData Single + { TaskID LLUUID } + { AttachmentNeedsSave BOOL } // true iff is attachment and needs asset saved + } +} + + +// KillChildAgents - A new agent has connected to the simulator . . . make sure that any old child cameras are blitzed +{ + KillChildAgents Low 242 Trusted Unencoded + { + IDBlock Single + { AgentID LLUUID } + } +} + + +// GetScriptRunning - asks if a script is running or not. the simulator +// responds with ScriptRunningReply +{ + GetScriptRunning Low 243 NotTrusted Unencoded + { + Script Single + { ObjectID LLUUID } + { ItemID LLUUID } + } +} + +// ScriptRunningReply - response from simulator to message above +{ + ScriptRunningReply Low 244 NotTrusted Unencoded UDPDeprecated + { + Script Single + { ObjectID LLUUID } + { ItemID LLUUID } + { Running BOOL } +// { Mono BOOL } Added to LLSD message + } +} + + +// SetScriptRunning - makes a script active or inactive (Enable may be +// true or false) +{ + SetScriptRunning Low 245 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Script Single + { ObjectID LLUUID } + { ItemID LLUUID } + { Running BOOL } + } +} + +// ScriptReset - causes a script to reset +{ + ScriptReset Low 246 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Script Single + { ObjectID LLUUID } + { ItemID LLUUID } + } +} + +// ScriptSensorRequest - causes the receiving sim to run a script sensor and return the results +{ + ScriptSensorRequest Low 247 Trusted Zerocoded + { + Requester Single + { SourceID LLUUID } + { RequestID LLUUID } + { SearchID LLUUID } + { SearchPos LLVector3 } + { SearchDir LLQuaternion } + { SearchName Variable 1 } + { Type S32 } + { Range F32 } + { Arc F32 } + { RegionHandle U64 } + { SearchRegions U8 } + } +} + +// ScriptSensorReply - returns the request script search information back to the requester +{ + ScriptSensorReply Low 248 Trusted Zerocoded + { + Requester Single + { SourceID LLUUID } + } + { + SensedData Variable + { ObjectID LLUUID } + { OwnerID LLUUID } + { GroupID LLUUID } + { Position LLVector3 } + { Velocity LLVector3 } + { Rotation LLQuaternion } + { Name Variable 1 } + { Type S32 } + { Range F32 } + } +} + +//----------------------------------------------------------------------------- +// Login and Agent Motion +//----------------------------------------------------------------------------- + +// viewer -> sim +// agent is coming into the region. The region should be expecting the +// agent. +{ + CompleteAgentMovement Low 249 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { CircuitCode U32 } + } +} + +// sim -> viewer +{ + AgentMovementComplete Low 250 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { Position LLVector3 } + { LookAt LLVector3 } + { RegionHandle U64 } + { Timestamp U32 } + } + { + SimData Single + { ChannelVersion Variable 2 } + } +} + + +//----------------------------------------------------------------------------- +// Logout +//----------------------------------------------------------------------------- + +// userserver -> dataserver +{ + DataServerLogout Low 251 Trusted Unencoded + { + UserData Single + { AgentID LLUUID } + { ViewerIP IPADDR } + { Disconnect BOOL } + { SessionID LLUUID } + } +} + +// LogoutRequest +// viewer -> sim +// reliable +{ + LogoutRequest Low 252 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + + +// LogoutReply +// it's ok for the viewer to quit. +// sim -> viewer +// reliable +// Includes inventory items to update with new asset ids +{ + LogoutReply Low 253 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } // null if list is actually empty (but has one entry 'cause it can't have none) + } +} + + +//----------------------------------------------------------------------------- +// Instant Message +//----------------------------------------------------------------------------- + +// ImprovedInstantMessage +// This message can potentially route all over the place +// ParentEstateID: parent estate id of the source estate +// RegionID: region id of the source of the IM. +// Position: position of the sender in region local coordinates +// Dialog see llinstantmessage.h for values +// ID May be used by dialog. Interpretation depends on context. +// BinaryBucket May be used by some dialog types +// reliable +{ + ImprovedInstantMessage Low 254 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + MessageBlock Single + { FromGroup BOOL } + { ToAgentID LLUUID } + { ParentEstateID U32 } + { RegionID LLUUID } + { Position LLVector3 } + { Offline U8 } + { Dialog U8 } // U8 - IM type + { ID LLUUID } + { Timestamp U32 } + { FromAgentName Variable 1 } + { Message Variable 2 } + { BinaryBucket Variable 2 } + } +} + +// RetrieveInstantMessages - used to get instant messages that +// were persisted out to the database while the user was offline +{ + RetrieveInstantMessages Low 255 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// FindAgent - used to find an agent's global position. I used a +// variable sized LocationBlock so that the message can be recycled with +// minimum new messages and handlers. +{ + FindAgent Low 256 NotTrusted Unencoded + { + AgentBlock Single + { Hunter LLUUID } + { Prey LLUUID } + { SpaceIP IPADDR } + } + { + LocationBlock Variable + { GlobalX F64 } + { GlobalY F64 } + } +} + +// Set godlike to 1 if you want to become godlike. +// Set godlike to 0 if you want to relinquish god powers. +// viewer -> simulator -> dataserver +// reliable +{ + RequestGodlikePowers Low 257 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + RequestBlock Single + { Godlike BOOL } + { Token LLUUID } // viewer packs a null, sim packs token + } +} + +// At the simulator, turn the godlike bit on. +// At the viewer, show the god menu. +// dataserver -> simulator -> viewer +// reliable +{ + GrantGodlikePowers Low 258 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GrantData Single + { GodLevel U8 } + { Token LLUUID } // checked on sim, ignored on viewer + } +} + +// GodlikeMessage - generalized construct for Gods to send messages +// around the system. Each Request has it's own internal protocol. +{ + GodlikeMessage Low 259 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { TransactionID LLUUID } + } + { + MethodData Single + { Method Variable 1 } + { Invoice LLUUID } + } + { + ParamList Variable + { Parameter Variable 1 } + } +} + +// EstateOwnerMessage +// format must be identical to above +{ + EstateOwnerMessage Low 260 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { TransactionID LLUUID } + } + { + MethodData Single + { Method Variable 1 } + { Invoice LLUUID } + } + { + ParamList Variable + { Parameter Variable 1 } + } +} + +// GenericMessage +// format must be identical to above +// As above, but don't have to be god or estate owner to send. +{ + GenericMessage Low 261 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { TransactionID LLUUID } + } + { + MethodData Single + { Method Variable 1 } + { Invoice LLUUID } + } + { + ParamList Variable + { Parameter Variable 1 } + } +} + +// *************************************************************************** +// Requests for possessions, acquisition, money, etc +// *************************************************************************** + +// request for mute list +{ + MuteListRequest Low 262 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + MuteData Single + { MuteCRC U32 } + } +} + +// update/add someone in the mute list +{ + UpdateMuteListEntry Low 263 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + MuteData Single + { MuteID LLUUID } + { MuteName Variable 1 } + { MuteType S32 } + { MuteFlags U32 } + } +} + +// Remove a mute list entry. +{ + RemoveMuteListEntry Low 264 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + MuteData Single + { MuteID LLUUID } + { MuteName Variable 1 } + } +} + + +// +// Inventory update messages +// UDP DEPRECATED - Now a viewer capability. + +{ + CopyInventoryFromNotecard Low 265 NotTrusted Zerocoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + NotecardData Single + { NotecardItemID LLUUID } + { ObjectID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } + { FolderID LLUUID } + } +} + +// +// This is used bi-directionally between sim, dataserver, and viewer. +// THIS MESSAGE CAN NOT CREATE NEW INVENTORY ITEMS. +// +{ + UpdateInventoryItem Low 266 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { TransactionID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } + { FolderID LLUUID } + { CallbackID U32 } // Async Response + + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + + { TransactionID LLUUID } // TransactionID: new assets only + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +// +// For sim to request update/create. +// DO NOT ALLOW THIS FROM THE VIEWER. +// +{ + UpdateCreateInventoryItem Low 267 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SimApproved BOOL } + { TransactionID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } + { FolderID LLUUID } + { CallbackID U32 } // Async Response + + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + + { AssetID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +{ + MoveInventoryItem Low 268 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Stamp BOOL } // should the server re-timestamp? + } + { + InventoryData Variable + { ItemID LLUUID } + { FolderID LLUUID } + { NewName Variable 1 } + } +} + +// copy inventory item by item id to specified destination folder, +// send out bulk inventory update when done. +// +// Inventory items are only unique for {agent, inv_id} pairs; +// the OldItemID needs to be paired with the OldAgentID to +// produce a unique inventory item. +{ + CopyInventoryItem Low 269 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Variable + { CallbackID U32 } // Async response + { OldAgentID LLUUID } + { OldItemID LLUUID } + { NewFolderID LLUUID } + { NewName Variable 1 } + } +} + +{ + RemoveInventoryItem Low 270 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } + } +} + +{ + ChangeInventoryItemFlags Low 271 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } + { Flags U32 } + } +} + +// +// Sim outgoing only (to dataserver, to viewer) +// NOT viewer to sim, sim should not have handler, ever +// This message is currently only uses objects, so the viewer ignores +// the asset id. +{ + SaveAssetIntoInventory Low 272 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + InventoryData Single + { ItemID LLUUID } + { NewAssetID LLUUID } + } +} + +{ + CreateInventoryFolder Low 273 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + FolderData Single + { FolderID LLUUID } + { ParentID LLUUID } + { Type S8 } + { Name Variable 1 } + } +} + +{ + UpdateInventoryFolder Low 274 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + FolderData Variable + { FolderID LLUUID } + { ParentID LLUUID } + { Type S8 } + { Name Variable 1 } + } +} + +{ + MoveInventoryFolder Low 275 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Stamp BOOL } // should the server re-timestamp children + } + { + InventoryData Variable + { FolderID LLUUID } + { ParentID LLUUID } + } +} + +{ + RemoveInventoryFolder Low 276 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + FolderData Variable + { FolderID LLUUID } + } +} + +// Get inventory segment. +{ + FetchInventoryDescendents Low 277 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Single + { FolderID LLUUID } + { OwnerID LLUUID } + { SortOrder S32 } // 0 = name, 1 = time + { FetchFolders BOOL } // false will omit folders in query + { FetchItems BOOL } // false will omit items in query + } +} + +// return inventory segment. +// *NOTE: This could be compressed more since we already know the +// parent_id for folders and the folder_id for items, but this is +// reasonable until we heve server side inventory. +{ + InventoryDescendents Low 278 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { FolderID LLUUID } + { OwnerID LLUUID } // owner of the folders creatd. + { Version S32 } // version of the folder for caching + { Descendents S32 } // count to help with caching + } + { + FolderData Variable + { FolderID LLUUID } + { ParentID LLUUID } + { Type S8 } + { Name Variable 1 } + } + { + ItemData Variable + { ItemID LLUUID } + { FolderID LLUUID } + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + { AssetID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +// Get inventory item(s) - response comes through FetchInventoryReply +{ + FetchInventory Low 279 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Variable + { OwnerID LLUUID } + { ItemID LLUUID } + } +} + +// response to fetch inventory +{ + FetchInventoryReply Low 280 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } + { FolderID LLUUID } + + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + + { AssetID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +// Can only fit around 7 items per packet - that's the way it goes. At +// least many bulk updates can be packed. +// Only from dataserver->sim->viewer +{ + BulkUpdateInventory Low 281 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { TransactionID LLUUID } + } + { + FolderData Variable + { FolderID LLUUID } + { ParentID LLUUID } + { Type S8 } + { Name Variable 1 } + } + { + ItemData Variable + { ItemID LLUUID } + { CallbackID U32 } // Async Response + { FolderID LLUUID } + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + { AssetID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + + + +// request permissions for agent id to get the asset for owner_id's +// item_id. +{ + RequestInventoryAsset Low 282 Trusted Unencoded + { + QueryData Single + { QueryID LLUUID } + { AgentID LLUUID } + { OwnerID LLUUID } + { ItemID LLUUID } + } +} + +// response to RequestInventoryAsset +// lluuid will be null if agentid in the request above cannot read asset +{ + InventoryAssetResponse Low 283 Trusted Unencoded + { + QueryData Single + { QueryID LLUUID } + { AssetID LLUUID } + { IsReadable BOOL } + } +} + +// This is the new improved way to remove inventory items. It is +// currently only supported in viewer->userserver->dataserver +// messages typically initiated by an empty trash method. +{ + RemoveInventoryObjects Low 284 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + FolderData Variable + { FolderID LLUUID } + } + { + ItemData Variable + { ItemID LLUUID } + } +} + +// This is how you remove inventory when you're not even sure what it +// is - only it's parenting. +{ + PurgeInventoryDescendents Low 285 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Single + { FolderID LLUUID } + } +} + +// These messages are viewer->simulator requests to update a task's +// inventory. +// if Key == 0, itemid is the key. if Key == 1, assetid is the key. +{ + UpdateTaskInventory Low 286 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + UpdateData Single + { LocalID U32 } + { Key U8 } + } + { + InventoryData Single + { ItemID LLUUID } + { FolderID LLUUID } + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + { TransactionID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +{ + RemoveTaskInventory Low 287 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Single + { LocalID U32 } + { ItemID LLUUID } + } +} + +{ + MoveTaskInventory Low 288 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { FolderID LLUUID } + } + { + InventoryData Single + { LocalID U32 } + { ItemID LLUUID } + } +} + +{ + RequestTaskInventory Low 289 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Single + { LocalID U32 } + } +} + +{ + ReplyTaskInventory Low 290 Trusted Zerocoded + { + InventoryData Single + { TaskID LLUUID } + { Serial S16 } // S16 + { Filename Variable 1 } + } +} + +// These messages are viewer->simulator requests regarding objects +// which are currently being simulated. The viewer will get an +// UpdateInventoryItem response if a DeRez succeeds, and the object +// will appear if a RezObject succeeds. +// The Destination field tells where the derez should wind up, and the +// meaning of DestinationID depends on it. For example, if the +// destination is a category, then the destination is the category id. If +// the destination is a task inventory, then the destination id is the +// task id. +// The transaction id is generated by the viewer on derez, and then +// the packets are counted and numbered. The rest of the information is +// just duplicated (it's not that much, and derezzes that span multiple +// packets will be rare.) +{ + DeRezObject Low 291 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + AgentBlock Single + { GroupID LLUUID } + { Destination U8 } + { DestinationID LLUUID } // see above + { TransactionID LLUUID } + { PacketCount U8 } + { PacketNumber U8 } + } + { + ObjectData Variable + { ObjectLocalID U32 } // object id in world + } +} + +// This message is sent when a derez succeeds, but there's no way to +// know, since no inventory is created on the viewer. For example, when +// saving into task inventory. +{ + DeRezAck Low 292 Trusted Unencoded + { + TransactionData Single + { TransactionID LLUUID } + { Success BOOL } + } +} + +// This message is sent from viewer -> simulator when the viewer wants +// to rez an object out of inventory. +{ + RezObject Low 293 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + RezData Single + { FromTaskID LLUUID } + { BypassRaycast U8 } + { RayStart LLVector3 } + { RayEnd LLVector3 } + { RayTargetID LLUUID } + { RayEndIsIntersection BOOL } + { RezSelected BOOL } + { RemoveItem BOOL } + { ItemFlags U32 } + { GroupMask U32 } + { EveryoneMask U32 } + { NextOwnerMask U32 } + } + { + InventoryData Single + { ItemID LLUUID } + { FolderID LLUUID } + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + { TransactionID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +// This message is sent from viewer -> simulator when the viewer wants +// to rez an object from a notecard. +{ + RezObjectFromNotecard Low 294 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + RezData Single + { FromTaskID LLUUID } + { BypassRaycast U8 } + { RayStart LLVector3 } + { RayEnd LLVector3 } + { RayTargetID LLUUID } + { RayEndIsIntersection BOOL } + { RezSelected BOOL } + { RemoveItem BOOL } + { ItemFlags U32 } + { GroupMask U32 } + { EveryoneMask U32 } + { NextOwnerMask U32 } + } + { + NotecardData Single + { NotecardItemID LLUUID } + { ObjectID LLUUID } + } + { + InventoryData Variable + { ItemID LLUUID } + } +} + + +// sim -> dataserver +// sent during agent to agent inventory transfers +{ + TransferInventory Low 295 Trusted Zerocoded + { + InfoBlock Single + { SourceID LLUUID } + { DestID LLUUID } + { TransactionID LLUUID } + } + { + InventoryBlock Variable + { InventoryID LLUUID } + { Type S8 } + } +} + +// dataserver -> sim +// InventoryID is the id of the inventory object that the end user +// should discard if they deny the transfer. +{ + TransferInventoryAck Low 296 Trusted Zerocoded + { + InfoBlock Single + { TransactionID LLUUID } + { InventoryID LLUUID } + } +} + + +{ + AcceptFriendship Low 297 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + TransactionBlock Single + { TransactionID LLUUID } + } + { + FolderData Variable + { FolderID LLUUID } // place to put calling card. + } +} + +{ + DeclineFriendship Low 298 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + TransactionBlock Single + { TransactionID LLUUID } + } +} + +{ + FormFriendship Low 299 Trusted Unencoded + { + AgentBlock Single + { SourceID LLUUID } + { DestID LLUUID } + } +} + +// Cancels user relationship +// Updates inventory for both users. +// Stops agent tracking in userserver. +// viewer -> userserver -> dataserver +// reliable +{ + TerminateFriendship Low 300 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ExBlock Single + { OtherID LLUUID } + } +} + +// used to give someone a calling card. +{ + OfferCallingCard Low 301 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + AgentBlock Single + { DestID LLUUID } + { TransactionID LLUUID } + } +} + +{ + AcceptCallingCard Low 302 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + TransactionBlock Single + { TransactionID LLUUID } + } + { + FolderData Variable + { FolderID LLUUID } // place to put calling card. + } +} + +{ + DeclineCallingCard Low 303 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + TransactionBlock Single + { TransactionID LLUUID } + } +} + + +// Rez a script onto an object +{ + RezScript Low 304 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + UpdateBlock Single + { ObjectLocalID U32 } // object id in world + { Enabled BOOL } // is script rezzed in enabled? + } + { + InventoryBlock Single + { ItemID LLUUID } + { FolderID LLUUID } + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + { TransactionID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +// Create inventory +{ + CreateInventoryItem Low 305 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryBlock Single + { CallbackID U32 } // Async Response + { FolderID LLUUID } + { TransactionID LLUUID } // Going to become TransactionID + { NextOwnerMask U32 } + { Type S8 } + { InvType S8 } + { WearableType U8 } + { Name Variable 1 } + { Description Variable 1 } + } +} + +// give agent a landmark for an event. +{ + CreateLandmarkForEvent Low 306 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + EventData Single + { EventID U32 } + } + { + InventoryBlock Single + { FolderID LLUUID } + { Name Variable 1 } + } +} + +{ + EventLocationRequest Low 307 Trusted Zerocoded + { + QueryData Single + { QueryID LLUUID } + } + { + EventData Single + { EventID U32 } + } +} + +{ + EventLocationReply Low 308 Trusted Zerocoded + { + QueryData Single + { QueryID LLUUID } + } + { + EventData Single + { Success BOOL } + { RegionID LLUUID } + { RegionPos LLVector3 } + } +} + +// get information about landmarks. Used by viewers for determining +// the location of a landmark, and by simulators for teleport +{ + RegionHandleRequest Low 309 NotTrusted Unencoded + { + RequestBlock Single + { RegionID LLUUID } + } +} + +{ + RegionIDAndHandleReply Low 310 Trusted Unencoded + { + ReplyBlock Single + { RegionID LLUUID } + { RegionHandle U64 } + } +} + +// Move money from one agent to another. Validation will happen at the +// simulator, the dataserver will actually do the work. Dataserver +// generates a MoneyBalance message in reply. The simulator +// will generate a MoneyTransferBackend in response to this. +// viewer -> simulator -> dataserver +{ + MoneyTransferRequest Low 311 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + MoneyData Single + { SourceID LLUUID } + { DestID LLUUID } // destination of the transfer + { Flags U8 } + { Amount S32 } + { AggregatePermNextOwner U8 } + { AggregatePermInventory U8 } + { TransactionType S32 } // see lltransactiontypes.h + { Description Variable 1 } // string, name of item for purchases + } +} + +// And, the money transfer +// *NOTE: Unused as of 2010-04-06, because all back-end money transactions +// are done with web services via L$ API. JC +{ + MoneyTransferBackend Low 312 Trusted Zerocoded + { + MoneyData Single + { TransactionID LLUUID } + { TransactionTime U32 } // utc seconds since epoch + { SourceID LLUUID } + { DestID LLUUID } // destination of the transfer + { Flags U8 } + { Amount S32 } + { AggregatePermNextOwner U8 } + { AggregatePermInventory U8 } + { TransactionType S32 } // see lltransactiontypes.h + { RegionID LLUUID } // region sending the request, for logging + { GridX U32 } // *HACK: database doesn't have region_id in schema + { GridY U32 } // *HACK: database doesn't have region_id in schema + { Description Variable 1 } // string, name of item for purchases + } +} + + +// viewer -> userserver -> dataserver +// Reliable +{ + MoneyBalanceRequest Low 313 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + MoneyData Single + { TransactionID LLUUID } + } +} + + +// dataserver -> simulator -> viewer +{ + MoneyBalanceReply Low 314 Trusted Zerocoded + { + MoneyData Single + { AgentID LLUUID } + { TransactionID LLUUID } + { TransactionSuccess BOOL } // BOOL + { MoneyBalance S32 } + { SquareMetersCredit S32 } + { SquareMetersCommitted S32 } + { Description Variable 1 } // string + } + // For replies that are part of a transaction (buying something) provide + // metadata for localization. If TransactionType is 0, the message is + // purely a balance update. Added for server 1.40 and viewer 2.1. JC + { + TransactionInfo Single + { TransactionType S32 } // lltransactiontype.h + { SourceID LLUUID } + { IsSourceGroup BOOL } + { DestID LLUUID } + { IsDestGroup BOOL } + { Amount S32 } + { ItemDescription Variable 1 } // string + } +} + + +// RoutedMoneyBalanceReply +// This message is used when a dataserver needs to send updated +// money balance information to a simulator other than the one it +// is connected to. It uses the standard TransferBlock format. +// dataserver -> simulator -> spaceserver -> simulator -> viewer +// reliable +{ + RoutedMoneyBalanceReply Low 315 Trusted Zerocoded + { + TargetBlock Single + { TargetIP IPADDR } // U32 encoded IP + { TargetPort IPPORT } + } + { + MoneyData Single + { AgentID LLUUID } + { TransactionID LLUUID } + { TransactionSuccess BOOL } // BOOL + { MoneyBalance S32 } + { SquareMetersCredit S32 } + { SquareMetersCommitted S32 } + { Description Variable 1 } // string + } + // See MoneyBalanceReply above. + { + TransactionInfo Single + { TransactionType S32 } // lltransactiontype.h + { SourceID LLUUID } + { IsSourceGroup BOOL } + { DestID LLUUID } + { IsDestGroup BOOL } + { Amount S32 } + { ItemDescription Variable 1 } // string + } +} + + + +//--------------------------------------------------------------------------- +// Gesture saves/loads +//--------------------------------------------------------------------------- + + +// Tell the database that some gestures are now active +// viewer -> sim -> data +{ + ActivateGestures Low 316 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Flags U32 } + } + { + Data Variable + { ItemID LLUUID } + { AssetID LLUUID } + { GestureFlags U32 } + } +} + +// Tell the database some gestures are no longer active +// viewer -> sim -> data +{ + DeactivateGestures Low 317 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Flags U32 } + } + { + Data Variable + { ItemID LLUUID } + { GestureFlags U32 } + } +} + +//--------------------------------------------------------------------------- +// +//--------------------------------------------------------------------------- + +// userserver -> viewer, up-to-date inventory is here +// could be sent as a result of spam +// as well as in response to InventoryRequest +//{ +// InventoryUpdate Low Trusted Unencoded +// { +// AgentData Single +// { AgentID LLUUID } +// } +// { +// InventoryData Single +// { IsComplete U8 } +// { Filename Variable 1 } +// } +//} + +// dataserver-> userserver -> viewer to move around the mute list +{ + MuteListUpdate Low 318 Trusted Unencoded + { + MuteData Single + { AgentID LLUUID } + { Filename Variable 1 } + } +} + +// tell viewer to use the local mute cache +{ + UseCachedMuteList Low 319 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } +} + +// Sent from viewer to simulator to set user rights. This message will be +// relayed up to the dataserver through a PUT. If that +// succeeds, an UpdateUserRights will be relayed to the originating +// viewer, and a presence lookup will be performed to find +// agent-related and the same PUT will be issued to the sim host if +// they are online. +{ + GrantUserRights Low 320 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Rights Variable + { AgentRelated LLUUID } + { RelatedRights S32 } + } +} + +// This message is sent from the simulator to the viewer to indicate a +// targets granted rights. This is only sent to the originator of the +// request and the target agent if it is a modify or map +// right. Adding/removing online status rights will show up as an +// online/offline notification. +{ + ChangeUserRights Low 321 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + Rights Variable + { AgentRelated LLUUID } + { RelatedRights S32 } + } +} + +// notification for login and logout. +// source_sim -> dest_viewer +{ + OnlineNotification Low 322 Trusted Unencoded + { + AgentBlock Variable + { AgentID LLUUID } + } +} +{ + OfflineNotification Low 323 Trusted Unencoded + { + AgentBlock Variable + { AgentID LLUUID } + } +} + + +// SetStartLocationRequest +// viewer -> sim +// failure checked at sim and triggers ImprovedInstantMessage +// success triggers SetStartLocation +{ + SetStartLocationRequest Low 324 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + StartLocationData Single + { SimName Variable 1 } // string + { LocationID U32 } + { LocationPos LLVector3 } // region coords + { LocationLookAt LLVector3 } + } +} + +// SetStartLocation +// sim -> dataserver +{ + SetStartLocation Low 325 Trusted Zerocoded + { + StartLocationData Single + { AgentID LLUUID } + { RegionID LLUUID } + { LocationID U32 } + { RegionHandle U64 } + { LocationPos LLVector3 } // region coords + { LocationLookAt LLVector3 } + } +} + + +// *************************************************************************** +// Launcher messages +// *************************************************************************** + + +// NetTest - This goes back and forth to the space server because of +// problems determining the port +{ + NetTest Low 326 NotTrusted Unencoded + { + NetBlock Single + { Port IPPORT } + } +} + +// SetChildCount - Sent to launcher to adjust nominal child count +// Simulator sends this increase the sim/cpu ratio on startup +{ + SetCPURatio Low 327 NotTrusted Unencoded + { + Data Single + { Ratio U8 } + } +} + + + +// SimCrashed - Sent to dataserver when the sim goes down. +// Maybe we should notify the spaceserver as well? +{ + SimCrashed Low 328 NotTrusted Unencoded + { + Data Single + { RegionX U32 } + { RegionY U32 } + } + { + Users Variable + { AgentID LLUUID } + } +} + +// *************************************************************************** +// Name Value Pair messages +// *************************************************************************** + +// NameValuePair - if the specific task exists on simulator, add or replace this name value pair +{ + NameValuePair Low 329 Trusted Unencoded + { + TaskData Single + { ID LLUUID } + } + { + NameValueData Variable + { NVPair Variable 2 } + } +} + +// NameValuePair - if the specific task exists on simulator or dataserver, remove the name value pair (value is ignored) +{ + RemoveNameValuePair Low 330 Trusted Unencoded + { + TaskData Single + { ID LLUUID } + } + { + NameValueData Variable + { NVPair Variable 2 } + } +} + + +// *************************************************************************** +// Add/Remove Attachment messages +// *************************************************************************** + +// +// Simulator informs Dataserver of new attachment or attachment asset update +// DO NOT ALLOW THIS FROM THE VIEWER +// +{ + UpdateAttachment Low 331 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + AttachmentBlock Single + { AttachmentPoint U8 } + } + { + OperationData Single + { AddItem BOOL } + { UseExistingAsset BOOL } + } + { + InventoryData Single // Standard inventory item block + { ItemID LLUUID } + { FolderID LLUUID } + + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + + { AssetID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +// Simulator informs Dataserver that attachment has been taken off +{ + RemoveAttachment Low 332 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + AttachmentBlock Single + { AttachmentPoint U8 } + { ItemID LLUUID } + } +} + + +// *************************************************************************** +// GUIDed Sound messages +// *************************************************************************** + +// SoundTrigger - Sent by simulator to viewer to trigger sound outside current region +{ + SoundTrigger High 29 NotTrusted Unencoded + { + SoundData Single + { SoundID LLUUID } + { OwnerID LLUUID } + { ObjectID LLUUID } + { ParentID LLUUID } // null if this object is the parent + { Handle U64 } // region handle + { Position LLVector3 } // region local + { Gain F32 } + } +} + +// AttachedSound - Sent by simulator to viewer to play sound attached with an object +{ + AttachedSound Medium 13 Trusted Unencoded + { + DataBlock Single + { SoundID LLUUID } + { ObjectID LLUUID } + { OwnerID LLUUID } + { Gain F32 } + { Flags U8 } + } +} + +// AttachedSoundGainChange - Sent by simulator to viewer to change an attached sounds' volume + +{ + AttachedSoundGainChange Medium 14 Trusted Unencoded + { + DataBlock Single + { ObjectID LLUUID } + { Gain F32 } + } +} + + +// PreloadSound - Sent by simulator to viewer to preload sound for an object + +{ + PreloadSound Medium 15 Trusted Unencoded + { + DataBlock Variable + { ObjectID LLUUID } + { OwnerID LLUUID } + { SoundID LLUUID } + } +} + + +// ************************************************************************* +// Asset storage messages +// ************************************************************************* + +// current assumes an existing UUID, need to enhance for new assets +{ + AssetUploadRequest Low 333 NotTrusted Unencoded + { + AssetBlock Single + { TransactionID LLUUID } + { Type S8 } + { Tempfile BOOL } + { StoreLocal BOOL } + { AssetData Variable 2 } // Optional: the actual asset data if the whole thing will fit it this packet + } +} + +{ + AssetUploadComplete Low 334 NotTrusted Unencoded + { + AssetBlock Single + { UUID LLUUID } + { Type S8 } + { Success BOOL } + } +} + + +// Script on simulator asks dataserver if there are any email messages +// waiting. +{ + EmailMessageRequest Low 335 Trusted Unencoded + { + DataBlock Single + { ObjectID LLUUID } + { FromAddress Variable 1 } + { Subject Variable 1 } + } +} + +// Dataserver gives simulator the oldest email message in the queue, along with +// how many messages are left in the queue. And passes back the filter used to request emails. +{ + EmailMessageReply Low 336 Trusted Unencoded + { + DataBlock Single + { ObjectID LLUUID } + { More U32 } //U32 + { Time U32 } //U32 + { FromAddress Variable 1 } + { Subject Variable 1 } + { Data Variable 2 } + { MailFilter Variable 1 } + } +} + +// Script on simulator sends mail to another script +{ + InternalScriptMail Medium 16 Trusted Unencoded + { + DataBlock Single + { From Variable 1 } + { To LLUUID } + { Subject Variable 1 } + { Body Variable 2 } + } +} + +// Script on simulator asks dataserver for information +{ + ScriptDataRequest Low 337 Trusted Unencoded + { + DataBlock Variable + { Hash U64 } + { RequestType S8 } + { Request Variable 2 } + } +} + +// Data server responds with data +{ + ScriptDataReply Low 338 Trusted Unencoded + { + DataBlock Variable + { Hash U64 } + { Reply Variable 2 } + } +} + + +//----------------------------------------------------------------------------- +// Group messages +//----------------------------------------------------------------------------- + +// CreateGroupRequest +// viewer -> simulator +// simulator -> dataserver +// reliable +{ + CreateGroupRequest Low 339 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { Name Variable 1 } // string + { Charter Variable 2 } // string + { ShowInList BOOL } + { InsigniaID LLUUID } + { MembershipFee S32 } // S32 + { OpenEnrollment BOOL } // BOOL (U8) + { AllowPublish BOOL } // whether profile is externally visible or not + { MaturePublish BOOL } // profile is "mature" + } +} + +// CreateGroupReply +// dataserver -> simulator +// simulator -> viewer +// reliable +{ + CreateGroupReply Low 340 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + ReplyData Single + { GroupID LLUUID } + { Success BOOL } + { Message Variable 1 } // string + } +} + +// UpdateGroupInfo +// viewer -> simulator +// simulator -> dataserver +// reliable +{ + UpdateGroupInfo Low 341 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { Charter Variable 2 } // string + { ShowInList BOOL } + { InsigniaID LLUUID } + { MembershipFee S32 } + { OpenEnrollment BOOL } + { AllowPublish BOOL } + { MaturePublish BOOL } + } +} + +// GroupRoleChanges +// viewer -> simulator -> dataserver +// reliable +{ + GroupRoleChanges Low 342 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + RoleChange Variable + { RoleID LLUUID } + { MemberID LLUUID } + { Change U32 } + } +} + +// JoinGroupRequest +// viewer -> simulator -> dataserver +// reliable +{ + JoinGroupRequest Low 343 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } +} + +// JoinGroupReply +// dataserver -> simulator -> viewer +{ + JoinGroupReply Low 344 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { Success BOOL } + } +} + + +// EjectGroupMemberRequest +// viewer -> simulator -> dataserver +// reliable +{ + EjectGroupMemberRequest Low 345 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } + { + EjectData Variable + { EjecteeID LLUUID } + } +} + +// EjectGroupMemberReply +// dataserver -> simulator -> viewer +// reliable +{ + EjectGroupMemberReply Low 346 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } + { + EjectData Single + { Success BOOL } + } +} + +// LeaveGroupRequest +// viewer -> simulator -> dataserver +// reliable +{ + LeaveGroupRequest Low 347 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } +} + +// LeaveGroupReply +// dataserver -> simulator -> viewer +{ + LeaveGroupReply Low 348 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { Success BOOL } + } +} + +// InviteGroupRequest +// viewer -> simulator -> dataserver +// reliable +{ + InviteGroupRequest Low 349 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } // UUID of inviting agent + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } + { + InviteData Variable + { InviteeID LLUUID } + { RoleID LLUUID } + } +} + +// InviteGroupResponse +// simulator -> dataserver +// reliable +{ + InviteGroupResponse Low 350 Trusted Unencoded + { + InviteData Single + { AgentID LLUUID } + { InviteeID LLUUID } + { GroupID LLUUID } + { RoleID LLUUID } + { MembershipFee S32 } + } +} + +// GroupProfileRequest +// viewer-> simulator -> dataserver +// reliable +{ + GroupProfileRequest Low 351 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } +} + +// GroupProfileReply +// dataserver -> simulator -> viewer +// reliable +{ + GroupProfileReply Low 352 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { Name Variable 1 } // string + { Charter Variable 2 } // string + { ShowInList BOOL } + { MemberTitle Variable 1 } // string + { PowersMask U64 } // U32 mask + { InsigniaID LLUUID } + { FounderID LLUUID } + { MembershipFee S32 } + { OpenEnrollment BOOL } // BOOL (U8) + { Money S32 } + { GroupMembershipCount S32 } + { GroupRolesCount S32 } + { AllowPublish BOOL } + { MaturePublish BOOL } + { OwnerRole LLUUID } + } +} + +// CurrentInterval = 0 => this period (week, day, etc.) +// CurrentInterval = 1 => last period +// viewer -> simulator -> dataserver +// reliable +{ + GroupAccountSummaryRequest Low 353 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + MoneyData Single + { RequestID LLUUID } + { IntervalDays S32 } + { CurrentInterval S32 } + } +} + + +// dataserver -> simulator -> viewer +// Reliable +{ + GroupAccountSummaryReply Low 354 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + } + { + MoneyData Single + { RequestID LLUUID } + { IntervalDays S32 } + { CurrentInterval S32 } + { StartDate Variable 1 } // string + { Balance S32 } + { TotalCredits S32 } + { TotalDebits S32 } + { ObjectTaxCurrent S32 } + { LightTaxCurrent S32 } + { LandTaxCurrent S32 } + { GroupTaxCurrent S32 } + { ParcelDirFeeCurrent S32 } + { ObjectTaxEstimate S32 } + { LightTaxEstimate S32 } + { LandTaxEstimate S32 } + { GroupTaxEstimate S32 } + { ParcelDirFeeEstimate S32 } + { NonExemptMembers S32 } + { LastTaxDate Variable 1 } // string + { TaxDate Variable 1 } // string + } +} + + +// Reliable +{ + GroupAccountDetailsRequest Low 355 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + MoneyData Single + { RequestID LLUUID } + { IntervalDays S32 } + { CurrentInterval S32 } + } +} + +// Reliable +{ + GroupAccountDetailsReply Low 356 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + } + { + MoneyData Single + { RequestID LLUUID } + { IntervalDays S32 } + { CurrentInterval S32 } + { StartDate Variable 1 } // string + } + { + HistoryData Variable + { Description Variable 1 } // string + { Amount S32 } + } +} + + +// Reliable +{ + GroupAccountTransactionsRequest Low 357 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + MoneyData Single + { RequestID LLUUID } + { IntervalDays S32 } + { CurrentInterval S32 } + } +} + +// Reliable +{ + GroupAccountTransactionsReply Low 358 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + } + { + MoneyData Single + { RequestID LLUUID } + { IntervalDays S32 } + { CurrentInterval S32 } + { StartDate Variable 1 } // string + } + { + HistoryData Variable + { Time Variable 1 } // string + { User Variable 1 } // string + { Type S32 } + { Item Variable 1 } // string + { Amount S32 } + } +} + +// GroupActiveProposalsRequest +// viewer -> simulator -> dataserver +//reliable +{ + GroupActiveProposalsRequest Low 359 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } + { + TransactionData Single + { TransactionID LLUUID } + } +} + +// GroupActiveProposalItemReply +// dataserver -> simulator -> viewer +// reliable +{ + GroupActiveProposalItemReply Low 360 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + } + { + TransactionData Single + { TransactionID LLUUID } + { TotalNumItems U32 } + } + { + ProposalData Variable + { VoteID LLUUID } + { VoteInitiator LLUUID } + { TerseDateID Variable 1 } // string + { StartDateTime Variable 1 } // string + { EndDateTime Variable 1 } // string + { AlreadyVoted BOOL } + { VoteCast Variable 1 } // string + { Majority F32 } + { Quorum S32 } + { ProposalText Variable 1 } // string + } +} + +// GroupVoteHistoryRequest +// viewer -> simulator -> dataserver +//reliable +{ + GroupVoteHistoryRequest Low 361 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + } + { + TransactionData Single + { TransactionID LLUUID } + } +} + +// GroupVoteHistoryItemReply +// dataserver -> simulator -> viewer +// reliable +{ + GroupVoteHistoryItemReply Low 362 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + } + { + TransactionData Single + { TransactionID LLUUID } + { TotalNumItems U32 } + } + { + HistoryItemData Single + { VoteID LLUUID } + { TerseDateID Variable 1 } // string + { StartDateTime Variable 1 } // string + { EndDateTime Variable 1 } // string + { VoteInitiator LLUUID } + { VoteType Variable 1 } // string + { VoteResult Variable 1 } // string + { Majority F32 } + { Quorum S32 } + { ProposalText Variable 2 } // string + } + { + VoteItem Variable + { CandidateID LLUUID } + { VoteCast Variable 1 } // string + { NumVotes S32 } + } +} + +// StartGroupProposal +// viewer -> simulator -> dataserver +// reliable +{ + StartGroupProposal Low 363 NotTrusted Zerocoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ProposalData Single + { GroupID LLUUID } + { Quorum S32 } + { Majority F32 } // F32 + { Duration S32 } // S32, seconds + { ProposalText Variable 1 } // string + } +} + +// GroupProposalBallot +// viewer -> simulator -> dataserver +// reliable +{ + GroupProposalBallot Low 364 NotTrusted Unencoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ProposalData Single + { ProposalID LLUUID } + { GroupID LLUUID } + { VoteCast Variable 1 } // string + } +} + +// TallyVotes userserver -> dataserver +// reliable +{ + TallyVotes Low 365 Trusted Unencoded +} + + + +// GroupMembersRequest +// get the group members +// simulator -> dataserver +// reliable +{ + GroupMembersRequest Low 366 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { RequestID LLUUID } + } +} + +// GroupMembersReply +// list of uuids for the group members +// dataserver -> simulator +// reliable +{ + GroupMembersReply Low 367 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { RequestID LLUUID } + { MemberCount S32 } + } + { + MemberData Variable + { AgentID LLUUID } + { Contribution S32 } + { OnlineStatus Variable 1 } // string + { AgentPowers U64 } + { Title Variable 1 } // string + { IsOwner BOOL } + } +} + +// used to switch an agent's currently active group. +// viewer -> simulator -> dataserver -> AgentDataUpdate... +{ + ActivateGroup Low 368 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } +} + +// viewer -> simulator -> dataserver +{ + SetGroupContribution Low 369 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { GroupID LLUUID } + { Contribution S32 } + } +} + +// viewer -> simulator -> dataserver +{ + SetGroupAcceptNotices Low 370 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Data Single + { GroupID LLUUID } + { AcceptNotices BOOL } + } + { + NewData Single + { ListInProfile BOOL } + } +} + +// GroupRoleDataRequest +// viewer -> simulator -> dataserver +{ + GroupRoleDataRequest Low 371 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { RequestID LLUUID } + } +} + + +// GroupRoleDataReply +// All role data for this group +// dataserver -> simulator -> agent +{ + GroupRoleDataReply Low 372 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { RequestID LLUUID } + { RoleCount S32 } + } + { + RoleData Variable + { RoleID LLUUID } + { Name Variable 1 } + { Title Variable 1 } + { Description Variable 1 } + { Powers U64 } + { Members U32 } + } +} + +// GroupRoleMembersRequest +// viewer -> simulator -> dataserver +{ + GroupRoleMembersRequest Low 373 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + GroupData Single + { GroupID LLUUID } + { RequestID LLUUID } + } +} + +// GroupRoleMembersReply +// All role::member pairs for this group. +// dataserver -> simulator -> agent +{ + GroupRoleMembersReply Low 374 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + { RequestID LLUUID } + { TotalPairs U32 } + } + { + MemberData Variable + { RoleID LLUUID } + { MemberID LLUUID } + } +} + +// GroupTitlesRequest +// viewer -> simulator -> dataserver +{ + GroupTitlesRequest Low 375 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + { RequestID LLUUID } + } +} + + +// GroupTitlesReply +// dataserver -> simulator -> viewer +{ + GroupTitlesReply Low 376 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + { RequestID LLUUID } + } + { + GroupData Variable + { Title Variable 1 } // string + { RoleID LLUUID } + { Selected BOOL } + } +} + +// GroupTitleUpdate +// viewer -> simulator -> dataserver +{ + GroupTitleUpdate Low 377 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + { TitleRoleID LLUUID } + } +} + +// GroupRoleUpdate +// viewer -> simulator -> dataserver +{ + GroupRoleUpdate Low 378 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { GroupID LLUUID } + } + { + RoleData Variable + { RoleID LLUUID } + { Name Variable 1 } + { Description Variable 1 } + { Title Variable 1 } + { Powers U64 } + { UpdateType U8 } + } +} + + + +// Request the members of the live help group needed for requesting agent. +// userserver -> dataserver +{ + LiveHelpGroupRequest Low 379 Trusted Unencoded + { + RequestData Single + { RequestID LLUUID } + { AgentID LLUUID } + } +} + +// Send down the group +// dataserver -> userserver +{ + LiveHelpGroupReply Low 380 Trusted Unencoded + { + ReplyData Single + { RequestID LLUUID } + { GroupID LLUUID } + { Selection Variable 1 } // selection criteria all or active + } +} + +//----------------------------------------------------------------------------- +// Wearable messages +//----------------------------------------------------------------------------- + +// AgentWearablesRequest +// (a.k.a. "Tell me what the avatar is wearing.") +// viewer -> simulator -> dataserver +// reliable +{ + AgentWearablesRequest Low 381 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// AgentWearablesUpdate +// (a.k.a. "Here's what your avatar should be wearing now.") +// dataserver -> userserver -> viewer +// reliable +// NEVER from viewer to sim +{ + AgentWearablesUpdate Low 382 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { SerialNum U32 } // U32, Increases every time the wearables change for a given agent. Used to avoid processing out of order packets. + } + { + WearableData Variable + { ItemID LLUUID } + { AssetID LLUUID } + { WearableType U8 } // U8, LLWearable::EWearType + } +} + +// +// AgentIsNowWearing +// (a.k.a. "Here's what I'm wearing now.") +// viewer->sim->dataserver +// reliable +{ + AgentIsNowWearing Low 383 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + WearableData Variable + { ItemID LLUUID } + { WearableType U8 } + } +} + + +// AgentCachedTexture +// viewer queries for cached textures on dataserver (via simulator) +// viewer -> simulator -> dataserver +// reliable +{ + AgentCachedTexture Low 384 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { SerialNum S32 } + } + { + WearableData Variable + { ID LLUUID } + { TextureIndex U8 } + } +} + +// AgentCachedTextureResponse +// response to viewer queries for cached textures on dataserver (via simulator) +// dataserver -> simulator -> viewer +// reliable +{ + AgentCachedTextureResponse Low 385 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { SerialNum S32 } + } + { + WearableData Variable + { TextureID LLUUID } + { TextureIndex U8 } + { HostName Variable 1 } + } +} + +// Request an AgentDataUpdate without changing any agent data. +{ + AgentDataUpdateRequest Low 386 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +// AgentDataUpdate +// Updates a viewer or simulator's impression of agent-specific information. +// Used, for example, when an agent's group changes. +// dataserver -> simulator -> viewer +// reliable +{ + AgentDataUpdate Low 387 Trusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { FirstName Variable 1 } // string + { LastName Variable 1 } // string + { GroupTitle Variable 1 } // string + { ActiveGroupID LLUUID } // active group + { GroupPowers U64 } + { GroupName Variable 1 } // string + } +} + + +// GroupDataUpdate +// This is a bunch of group data that needs to be appropriatly routed based on presence info. +// dataserver -> simulator +{ + GroupDataUpdate Low 388 Trusted Zerocoded + { + AgentGroupData Variable + { AgentID LLUUID } + { GroupID LLUUID } + { AgentPowers U64 } + { GroupTitle Variable 1 } + } +} + +// AgentGroupDataUpdate +// Updates a viewer or simulator's impression of the groups an agent is in. +// dataserver -> simulator -> viewer +// reliable +{ + AgentGroupDataUpdate Low 389 Trusted Zerocoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + } + { + GroupData Variable + { GroupID LLUUID } + { GroupPowers U64 } + { AcceptNotices BOOL } + { GroupInsigniaID LLUUID } + { Contribution S32 } + { GroupName Variable 1 } // string + } +} + +// AgentDropGroup +// Updates the viewer / simulator that an agent is no longer part of a group +// dataserver -> simulator -> viewer +// dataserver -> userserver +// reliable +{ + AgentDropGroup Low 390 Trusted Zerocoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { GroupID LLUUID } + } +} + +// LogTextMessage +// Asks the dataserver to log the contents of this message in the +// chat and IM log table. +// Sent from userserver (IM logging) and simulator (chat logging). +{ + LogTextMessage Low 391 Trusted Zerocoded + { + DataBlock Variable + { FromAgentId LLUUID } + { ToAgentId LLUUID } + { GlobalX F64 } + { GlobalY F64 } + { Time U32 } // utc seconds since epoch + { Message Variable 2 } // string + } +} + +// ViewerEffect +// Viewer side effect that's sent from one viewer, and broadcast to other agents nearby +// viewer-->sim (single effect created by viewer) +// sim-->viewer (multiple effects that can be seen by viewer) +// the AgentData block used for authentication for viewer-->sim messages +{ + ViewerEffect Medium 17 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + Effect Variable + { ID LLUUID } // unique UUID of the effect + { AgentID LLUUID } // yes, pack AgentID again (note this block is variable) + { Type U8 } // Type of the effect + { Duration F32 } // F32 time (seconds) + { Color Fixed 4 } // Color4U + { TypeData Variable 1 } // Type specific data + } +} + + +// CreateTrustedCircuit +// Sent to establish a trust relationship between two components. +// Only sent in response to a DenyTrustedCircuit message. +{ + CreateTrustedCircuit Low 392 NotTrusted Unencoded + { + DataBlock Single + { EndPointID LLUUID } + { Digest Fixed 32 } // 32 hex digits == 1 MD5 Digest + } +} + +// DenyTrustedCircuit +// Sent : +// - in response to failed CreateTrustedCircuit +// - to force the remote end-point to try to establish a trusted circuit +// - the reception of a trusted message on a non-trusted circuit +// This allows us to re-auth a circuit if it gets closed due to timeouts or network failures. +{ + DenyTrustedCircuit Low 393 NotTrusted Unencoded + { + DataBlock Single + { EndPointID LLUUID } + } +} + +// RequestTrustedCircuit +// If the destination does not trust the sender, a Deny is sent back. +{ + RequestTrustedCircuit Low 394 Trusted Unencoded +} + + +{ + RezSingleAttachmentFromInv Low 395 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Single + { ItemID LLUUID } + { OwnerID LLUUID } + { AttachmentPt U8 } // 0 for default + { ItemFlags U32 } + { GroupMask U32 } + { EveryoneMask U32 } + { NextOwnerMask U32 } + { Name Variable 1 } + { Description Variable 1 } + } +} + +{ + RezMultipleAttachmentsFromInv Low 396 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + HeaderData Single + { CompoundMsgID LLUUID } // All messages a single "compound msg" must have the same id + { TotalObjects U8 } + { FirstDetachAll BOOL } + } + { + ObjectData Variable // 1 to 4 of these per packet + { ItemID LLUUID } + { OwnerID LLUUID } + { AttachmentPt U8 } // 0 for default + { ItemFlags U32 } + { GroupMask U32 } + { EveryoneMask U32 } + { NextOwnerMask U32 } + { Name Variable 1 } + { Description Variable 1 } + } +} + + +{ + DetachAttachmentIntoInv Low 397 NotTrusted Unencoded + { + ObjectData Single + { AgentID LLUUID } + { ItemID LLUUID } + } +} + + +// Viewer -> Sim +// Used in "Make New Outfit" +{ + CreateNewOutfitAttachments Low 398 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + HeaderData Single + { NewFolderID LLUUID } + } + { + ObjectData Variable + { OldItemID LLUUID } + { OldFolderID LLUUID } + } +} + +//----------------------------------------------------------------------------- +// Personal information messages +//----------------------------------------------------------------------------- + +{ + UserInfoRequest Low 399 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } +} + +{ + UserInfoReply Low 400 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + UserData Single + { IMViaEMail BOOL } + { DirectoryVisibility Variable 1 } + { EMail Variable 2 } + } +} + +{ + UpdateUserInfo Low 401 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + UserData Single + { IMViaEMail BOOL } + { DirectoryVisibility Variable 1 } + } +} + + +//----------------------------------------------------------------------------- +// System operations and maintenance +//----------------------------------------------------------------------------- + + +// spaceserver -> sim +// tell a particular simulator to rename a parcel +{ + ParcelRename Low 402 Trusted Unencoded + { + ParcelData Variable + { ParcelID LLUUID } + { NewName Variable 1 } // string + } +} + + +// sim -> viewer +// initiate upload. primarily used for uploading raw files. +{ + InitiateDownload Low 403 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + } + { + FileData Single + { SimFilename Variable 1 } // string + { ViewerFilename Variable 1 } // string + } +} + +// Generalized system message. Each Requst has its own protocol for +// the StringData block format and contents. +{ + SystemMessage Low 404 Trusted Zerocoded + { + MethodData Single + { Method Variable 1 } + { Invoice LLUUID } + { Digest Fixed 32 } // 32 hex digits == 1 MD5 Digest + } + { + ParamList Variable + { Parameter Variable 1 } + } +} + + +//----------------------------------------------------------------------------- +// map messages +//----------------------------------------------------------------------------- + +// viewer -> sim +// reliable +// This message is sent up from the viewer to (eventually) get a list +// of all map layers and NULL-layer sims. +// Returns: MapLayerReply and MapBlockReply +{ + MapLayerRequest Low 405 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Flags U32 } + { EstateID U32 } // filled in on sim + { Godlike BOOL } // filled in on sim + } +} + +// sim -> viewer +{ + MapLayerReply Low 406 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { Flags U32 } + } + { + LayerData Variable + { Left U32 } + { Right U32 } + { Top U32 } + { Bottom U32 } + { ImageID LLUUID } + } +} + +// viewer -> sim +// This message is sent up from the viewer to get a list +// of the sims in a specified region. +// Returns: MapBlockReply +{ + MapBlockRequest Low 407 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Flags U32 } + { EstateID U32 } // filled in on sim + { Godlike BOOL } // filled in on sim + } + { + PositionData Single + { MinX U16 } // in region-widths + { MaxX U16 } // in region-widths + { MinY U16 } // in region-widths + { MaxY U16 } // in region-widths + } +} + +// viewer -> sim +// This message is sent up from the viewer to get a list +// of the sims with a given name. +// Returns: MapBlockReply +{ + MapNameRequest Low 408 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Flags U32 } + { EstateID U32 } // filled in on sim + { Godlike BOOL } // filled in on sim + } + { + NameData Single + { Name Variable 1 } // string + } +} + +// sim -> viewer +{ + MapBlockReply Low 409 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { Flags U32 } + } + { + Data Variable + { X U16 } // in region-widths + { Y U16 } // in region-widths + { Name Variable 1 } // string + { Access U8 } // PG, mature, etc. + { RegionFlags U32 } + { WaterHeight U8 } // meters + { Agents U8 } + { MapImageID LLUUID } + } + { + Size Variable + { SizeX U16 } + { SizeY U16 } + } +} + +// viewer -> sim +// This message is sent up from the viewer to get a list +// of the items of a particular type on the map. +// Used for Telehubs, Agents, Events, Popular Places, etc. +// Returns: MapBlockReply +{ + MapItemRequest Low 410 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { Flags U32 } + { EstateID U32 } // filled in on sim + { Godlike BOOL } // filled in on sim + } + { + RequestData Single + { ItemType U32 } + { RegionHandle U64 } // filled in on sim + } +} + +// sim -> viewer +{ + MapItemReply Low 411 Trusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { Flags U32 } + } + { + RequestData Single + { ItemType U32 } + } + { + Data Variable + { X U32 } // global position + { Y U32 } // global position + { ID LLUUID } // identifier id + { Extra S32 } // extra information + { Extra2 S32 } // extra information + { Name Variable 1 } // identifier string + } +} + +//----------------------------------------------------------------------------- +// Postcard messages +//----------------------------------------------------------------------------- +// reliable +{ + SendPostcard Low 412 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + { AssetID LLUUID } + { PosGlobal LLVector3d } // Where snapshot was taken + { To Variable 1 } // dest email address(es) + { From Variable 1 } // src email address(es) + { Name Variable 1 } // src name + { Subject Variable 1 } // mail subject + { Msg Variable 2 } // message text + { AllowPublish BOOL } // Allow publishing on the web. + { MaturePublish BOOL } // profile is "mature" + } +} + +// RPC messages +// Script on simulator requests rpc channel from rpcserver +// simulator -> dataserver -> MySQL +{ + RpcChannelRequest Low 413 Trusted Unencoded + { + DataBlock Single + { GridX U32 } + { GridY U32 } + { TaskID LLUUID } + { ItemID LLUUID } + } +} + +// RpcServer allocated a session for the script +// ChannelID will be the NULL UUID if unable to register +// dataserver -> simulator +{ + RpcChannelReply Low 414 Trusted Unencoded + { + DataBlock Single + { TaskID LLUUID } + { ItemID LLUUID } + { ChannelID LLUUID } + } +} + +// Inbound RPC requests follow this path: +// RpcScriptRequestInbound: rpcserver -> spaceserver +// RpcScriptRequestInboundForward: spaceserver -> simulator +// reply: simulator -> rpcserver +{ + RpcScriptRequestInbound Low 415 NotTrusted Unencoded + { + TargetBlock Single + { GridX U32 } + { GridY U32 } + } + { + DataBlock Single + { TaskID LLUUID } + { ItemID LLUUID } + { ChannelID LLUUID } + { IntValue U32 } + { StringValue Variable 2 } // string + } +} + +// spaceserver -> simulator +{ + RpcScriptRequestInboundForward Low 416 Trusted Unencoded UDPDeprecated + { + DataBlock Single + { RPCServerIP IPADDR } + { RPCServerPort IPPORT } + { TaskID LLUUID } + { ItemID LLUUID } + { ChannelID LLUUID } + { IntValue U32 } + { StringValue Variable 2 } // string + } +} + +// simulator -> rpcserver +// Not trusted because trust establishment doesn't work here. +{ + RpcScriptReplyInbound Low 417 NotTrusted Unencoded + { + DataBlock Single + { TaskID LLUUID } + { ItemID LLUUID } + { ChannelID LLUUID } + { IntValue U32 } + { StringValue Variable 2 } // string + } +} + + +// ScriptMailRegistration +// Simulator -> dataserver +{ + ScriptMailRegistration Low 418 Trusted Unencoded + { + DataBlock Single + { TargetIP Variable 1 } // String IP + { TargetPort IPPORT } + { TaskID LLUUID } + { Flags U32 } + } +} + +// ParcelMediaCommandMessage +// Sends a parcel media command +{ + ParcelMediaCommandMessage Low 419 Trusted Unencoded + { + CommandBlock Single + { Flags U32 } + { Command U32 } + { Time F32 } + } +} + +// ParcelMediaUpdate +// Sends a parcel media update to a single user +// For global updates use the parcel manager. +{ + ParcelMediaUpdate Low 420 Trusted Unencoded + { + DataBlock Single + { MediaURL Variable 1 } // string + { MediaID LLUUID } + { MediaAutoScale U8 } + } + { + DataBlockExtended Single + { MediaType Variable 1 } + { MediaDesc Variable 1 } + { MediaWidth S32 } + { MediaHeight S32 } + { MediaLoop U8 } + } +} + +// LandStatRequest +// Sent by the viewer to request collider/script information for a parcel +{ + LandStatRequest Low 421 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + RequestData Single + { ReportType U32 } + { RequestFlags U32 } + { Filter Variable 1 } + { ParcelLocalID S32 } + } +} + +// LandStatReply +// Sent by the simulator in response to LandStatRequest +{ + LandStatReply Low 422 Trusted Unencoded UDPDeprecated + { + RequestData Single + { ReportType U32 } + { RequestFlags U32 } + { TotalObjectCount U32 } + } + { + ReportData Variable + { TaskLocalID U32 } + { TaskID LLUUID } + { LocationX F32 } + { LocationY F32 } + { LocationZ F32 } + { Score F32 } + { TaskName Variable 1 } + { OwnerName Variable 1 } + } +} + +// Generic Error -- this is used for sending an error message +// to a UDP recipient. The lowest common denominator is to at least +// log the message. More sophisticated receivers can do something +// smarter, for example, a money transaction failure can put up a +// more user visible UI widget. +{ + Error Low 423 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } // will forward to agentid if coming from trusted circuit + } + { + Data Single + { Code S32 } // matches http status codes + { Token Variable 1 } // some specific short string based message + { ID LLUUID } // the transactionid/uniqueid/sessionid whatever. + { System Variable 1 } // The hierarchical path to the system, eg, "message/handler" + { Message Variable 2 } // Human readable message + { Data Variable 2 } // Binary serialized LLSD for extra info. + } +} + +// ObjectIncludeInSearch +// viewer -> simulator +{ + ObjectIncludeInSearch Low 424 NotTrusted Unencoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { IncludeInSearch BOOL } + } +} + + +// This message is sent from viewer -> simulator when the viewer wants +// to rez an object out of inventory back to its position before it +// last moved into the inventory +{ + RezRestoreToWorld Low 425 NotTrusted Unencoded UDPDeprecated + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryData Single + { ItemID LLUUID } + { FolderID LLUUID } + { CreatorID LLUUID } // permissions + { OwnerID LLUUID } // permissions + { GroupID LLUUID } // permissions + { BaseMask U32 } // permissions + { OwnerMask U32 } // permissions + { GroupMask U32 } // permissions + { EveryoneMask U32 } // permissions + { NextOwnerMask U32 } // permissions + { GroupOwned BOOL } // permissions + { TransactionID LLUUID } + { Type S8 } + { InvType S8 } + { Flags U32 } + { SaleType U8 } + { SalePrice S32 } + { Name Variable 1 } + { Description Variable 1 } + { CreationDate S32 } + { CRC U32 } + } +} + +// Link inventory +{ + LinkInventoryItem Low 426 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + InventoryBlock Single + { CallbackID U32 } // Async Response + { FolderID LLUUID } + { TransactionID LLUUID } // Going to become TransactionID + { OldItemID LLUUID } + { Type S8 } + { InvType S8 } + { Name Variable 1 } + { Description Variable 1 } + + } +} + diff --git a/data/var_region1.patch b/data/var_region1.patch new file mode 100644 index 0000000..6920fd4 --- /dev/null +++ b/data/var_region1.patch @@ -0,0 +1,16 @@ +diff --git a/data/message_template.msg b/data/message_template.msg +index 6702de9..1ec83cb 100644 +--- a/data/message_template.msg ++++ b/data/message_template.msg +@@ -8707,6 +8707,11 @@ version 2.0 + { Agents U8 } + { MapImageID LLUUID } + } ++ { ++ Size Variable ++ { SizeX U16 } ++ { SizeY U16 } ++ } + } + + // viewer -> sim diff --git a/openjpeg-dotnet/DllOpenJPEG.vcproj b/openjpeg-dotnet/DllOpenJPEG.vcproj new file mode 100644 index 0000000..0a80166 --- /dev/null +++ b/openjpeg-dotnet/DllOpenJPEG.vcproj @@ -0,0 +1,1227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openjpeg-dotnet/Makefile b/openjpeg-dotnet/Makefile new file mode 100644 index 0000000..2e9383f --- /dev/null +++ b/openjpeg-dotnet/Makefile @@ -0,0 +1,95 @@ +# Linux makefile for OpenJPEG + +VER_MAJOR = 2 +VER_MINOR = 1.5.0-dotnet-1 + +SRCS = ./libopenjpeg/bio.c ./libopenjpeg/cio.c ./libopenjpeg/dwt.c ./libopenjpeg/event.c ./libopenjpeg/image.c ./libopenjpeg/j2k.c ./libopenjpeg/j2k_lib.c ./libopenjpeg/jp2.c ./libopenjpeg/jpt.c ./libopenjpeg/mct.c ./libopenjpeg/mqc.c ./libopenjpeg/openjpeg.c ./libopenjpeg/pi.c ./libopenjpeg/raw.c ./libopenjpeg/t1.c ./libopenjpeg/t2.c ./libopenjpeg/tcd.c ./libopenjpeg/tgt.c +CPPSRCS = ./dotnet/dotnet.cpp +INCLS = ./libopenjpeg/bio.h ./libopenjpeg/cio.h ./libopenjpeg/dwt.h ./libopenjpeg/event.h ./libopenjpeg/fix.h ./libopenjpeg/image.h ./libopenjpeg/int.h ./libopenjpeg/j2k.h ./libopenjpeg/j2k_lib.h ./libopenjpeg/jp2.h ./libopenjpeg/jpt.h ./libopenjpeg/mct.h ./libopenjpeg/mqc.h ./libopenjpeg/openjpeg.h ./libopenjpeg/pi.h ./libopenjpeg/raw.h ./libopenjpeg/t1.h ./libopenjpeg/t2.h ./libopenjpeg/tcd.h ./libopenjpeg/tgt.h ./libopenjpeg/opj_malloc.h ./libopenjpeg/opj_includes.h ./dotnet/dotnet.h +INCLUDE = -Ilibopenjpeg + +# General configuration variables: +CC = gcc +AR = ar + +OSNAME = $(shell uname -s) + +ifeq ($(OSNAME), Linux) + ARCH = $(shell uname -m) + ARCHSET = 0 + ifeq ($(ARCH), x86_64) + ARCH=-x86_64 + ARCHFLAGS=-m64 + ARCHSET=1 + endif + ifeq ($(ARCH), s390x) + ARCH=-s390x + ARCHFLAGS=-m64 + ARCHSET=1 + endif + ifeq ($(ARCH), ppc64) + ARCH=-ppc64 + ARCHFLAGS=-m64 + ARCHSET=1 + endif + ifeq ($(ARCHSET), 0) + ARCH=-i686 + ARCHFLAGS=-m32 + endif +endif + + +# Converts cr/lf to just lf +DOS2UNIX = dos2unix + +COMPILERFLAGS = -O3 -fPIC $(ARCHFLAGS) +LIBRARIES = -lstdc++ + +MODULES = $(SRCS:.c=.o) +CPPMODULES = $(CPPSRCS:.cpp=.o) +CFLAGS = $(COMPILERFLAGS) $(INCLUDE) + +TARGET = openjpeg-dotnet +SHAREDLIB = lib$(TARGET)-$(VER_MAJOR)-$(VER_MINOR)$(ARCH).so +LIBNAME = lib$(TARGET).so.$(VER_MAJOR) + +default: all + +# Force 32 bit binary on 64 bit platform +32bit: OpenJPEG + +all: OpenJPEG + +dist: OpenJPEG + install -d ../bin + cp $(SHAREDLIB) ../bin/ + +dos2unix: + @$(DOS2UNIX) $(SRCS) $(INCLS) + +OpenJPEG: $(SHAREDLIB) + +$(MODULES): %.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(CPPMODULES): %.o: %.cpp + $(CC) $(CFLAGS) -c $< -o $@ + +$(SHAREDLIB): $(MODULES) $(CPPMODULES) + $(CC) $(ARCHFLAGS) -s -shared -Wl,-soname,$(LIBNAME) -o $@ $(MODULES) $(CPPMODULES) $(LIBRARIES) + +install: OpenJPEG + install -d ../bin + cp $(SHAREDLIB) ../bin/ + +clean: + rm -rf core dist/ u2dtmp* $(MODULES) $(CPPMODULES) $(SHAREDLIB) $(LIBNAME) + +osx: + make -f Makefile.osx + +osxinstall: + make -f Makefile.osx install + +osxclean: + make -f Makefile.osx clean diff --git a/openjpeg-dotnet/Makefile.osx b/openjpeg-dotnet/Makefile.osx new file mode 100644 index 0000000..cfa6e8a --- /dev/null +++ b/openjpeg-dotnet/Makefile.osx @@ -0,0 +1,65 @@ +# MacOSX makefile for OpenJPEG + +VER_MAJOR = 2 +VER_MINOR = 1.5.0-dotnet-1 + +SRCS = ./libopenjpeg/bio.c ./libopenjpeg/cio.c ./libopenjpeg/dwt.c ./libopenjpeg/event.c ./libopenjpeg/image.c ./libopenjpeg/j2k.c ./libopenjpeg/j2k_lib.c ./libopenjpeg/jp2.c ./libopenjpeg/jpt.c ./libopenjpeg/mct.c ./libopenjpeg/mqc.c ./libopenjpeg/openjpeg.c ./libopenjpeg/pi.c ./libopenjpeg/raw.c ./libopenjpeg/t1.c ./libopenjpeg/t2.c ./libopenjpeg/tcd.c ./libopenjpeg/tgt.c ./libopenjpeg/cidx_manager.c ./libopenjpeg/phix_manager.c ./libopenjpeg/ppix_manager.c ./libopenjpeg/thix_manager.c ./libopenjpeg/tpix_manager.c +CPPSRCS = ./dotnet/dotnet.cpp +INCLS = ./libopenjpeg/bio.h ./libopenjpeg/cio.h ./libopenjpeg/dwt.h ./libopenjpeg/event.h ./libopenjpeg/fix.h ./libopenjpeg/image.h ./libopenjpeg/int.h ./libopenjpeg/j2k.h ./libopenjpeg/j2k_lib.h ./libopenjpeg/jp2.h ./libopenjpeg/jpt.h ./libopenjpeg/mct.h ./libopenjpeg/mqc.h ./libopenjpeg/openjpeg.h ./libopenjpeg/pi.h ./libopenjpeg/raw.h ./libopenjpeg/t1.h ./libopenjpeg/t2.h ./libopenjpeg/tcd.h ./libopenjpeg/tgt.h ./libopenjpeg/opj_includes.h ./dotnet/dotnet.h ./libopenjpeg/cidx_manager.h ./libopenjpeg/indexbox_manager.h +INCLUDE = -Ilibopenjpeg + +# General configuration variables: +CC = gcc +LIBTOOLSTAT = libtool +LIBTOOLDYN = g++ + + +COMPILERFLAGS = -O3 -fPIC -m32 + +MODULES = $(SRCS:.c=.o) +CPPMODULES = $(CPPSRCS:.cpp=.o) +CFLAGS = $(COMPILERFLAGS) $(INCLUDE) + +TARGET = openjpeg-dotnet +SHAREDLIB = lib$(TARGET)-$(VER_MAJOR)-$(VER_MINOR).dylib +LIBNAME = lib$(TARGET).dylib + + + + +default: all + +all: OpenJPEG + +dos2unix: + @$(DOS2UNIX) $(SRCS) $(INCLS) + +dist: OpenJPEG + install -d ../bin + cp $(SHAREDLIB) ../bin/ + +OpenJPEG: $(STATICLIB) $(SHAREDLIB) + +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ + +$(STATICLIB): $(MODULES) + $(LIBTOOLSTAT) -o $@ $(MODULES) + + +.cpp.o: + $(CC) $(CFLAGS) -c $< -o $@ + +$(SHAREDLIB): $(MODULES) $(CPPMODULES) + $(LIBTOOLDYN) -m32 -dynamiclib -o $@ $(MODULES) $(CPPMODULES) $(LIBRARIES) + + + +install: + install -d ../bin + cp $(SHAREDLIB) ../bin/ + + +clean: + rm -rf core dist/ u2dtmp* $(MODULES) $(STATICLIB) $(SHAREDLIB) $(LIBNAME) + diff --git a/openjpeg-dotnet/OpenJPEG.rc b/openjpeg-dotnet/OpenJPEG.rc new file mode 100644 index 0000000..2ddc653 --- /dev/null +++ b/openjpeg-dotnet/OpenJPEG.rc @@ -0,0 +1,110 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +//#include "afxres.h" +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,0,0 + PRODUCTVERSION 1,1,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "The OpenJPEG library is an open-source JPEG 2000 codec. \0" + VALUE "CompanyName", "OpenJPEG\0" + VALUE "FileDescription", "OpenJPEG\0" + VALUE "FileVersion", "1, 1, 0, 0\0" + VALUE "InternalName", "OpenJPEG\0" + VALUE "LegalCopyright", "Copyright © 2002-2007, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium\0" + VALUE "LegalTrademarks", "See http://www.openjpeg.org for details\0" + VALUE "OriginalFilename", "OpenJPEG.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "OpenJPEG\0" + VALUE "ProductVersion", "1, 1, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/openjpeg-dotnet/Resource.h b/openjpeg-dotnet/Resource.h new file mode 100644 index 0000000..08177e5 --- /dev/null +++ b/openjpeg-dotnet/Resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by foob.rc +// + +#define IDS_APP_TITLE 103 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/openjpeg-dotnet/dotnet/dotnet.cpp b/openjpeg-dotnet/dotnet/dotnet.cpp new file mode 100644 index 0000000..bdf2859 --- /dev/null +++ b/openjpeg-dotnet/dotnet/dotnet.cpp @@ -0,0 +1,243 @@ +// This is the main DLL file. + +#include "dotnet.h" +extern "C" { +#include "../libopenjpeg/openjpeg.h" +} +#include + +bool DotNetAllocEncoded64(MarshalledImage* image) +{ + return DotNetAllocEncoded(image); +} + +bool DotNetAllocEncoded(MarshalledImage* image) +{ + DotNetFree(image); + + try + { + image->encoded = new unsigned char[image->length]; + image->decoded = 0; + } + catch (...) + { + return false; + } + + return true; +} +bool DotNetAllocDecoded64(MarshalledImage* image) +{ + return DotNetAllocDecoded(image); +} + +bool DotNetAllocDecoded(MarshalledImage* image) +{ + DotNetFree(image); + + try + { + image->decoded = new unsigned char[image->width * image->height * image->components]; + image->encoded = 0; + } + catch (...) + { + return false; + } + + return true; +} +void DotNetFree64(MarshalledImage* image) +{ + DotNetFree(image); +} + +void DotNetFree(MarshalledImage* image) +{ + if (image->encoded != 0) delete[] image->encoded; + if (image->decoded != 0) delete[] image->decoded; +} + +bool DotNetEncode64(MarshalledImage* image, bool lossless) +{ + return DotNetEncode(image, lossless); +} + +bool DotNetEncode(MarshalledImage* image, bool lossless) +{ + try + { + opj_cparameters cparameters; + opj_set_default_encoder_parameters(&cparameters); + cparameters.cp_disto_alloc = 1; + + if (lossless) + { + cparameters.tcp_numlayers = 1; + cparameters.tcp_rates[0] = 0; + } + else + { + cparameters.tcp_numlayers = 5; + cparameters.tcp_rates[0] = 1920; + cparameters.tcp_rates[1] = 480; + cparameters.tcp_rates[2] = 120; + cparameters.tcp_rates[3] = 30; + cparameters.tcp_rates[4] = 10; + cparameters.irreversible = 1; + if (image->components >= 3) + { + cparameters.tcp_mct = 1; + } + } + + cparameters.cp_comment = (char*)""; + + opj_image_comptparm comptparm[5]; + + for (int i = 0; i < image->components; i++) + { + comptparm[i].bpp = 8; + comptparm[i].prec = 8; + comptparm[i].sgnd = 0; + comptparm[i].dx = 1; + comptparm[i].dy = 1; + comptparm[i].x0 = 0; + comptparm[i].y0 = 0; + comptparm[i].w = image->width; + comptparm[i].h = image->height; + } + + opj_image_t* jp2_image = opj_image_create(image->components, comptparm, CLRSPC_SRGB); + if (jp2_image == NULL) + throw "opj_image_create failed"; + + jp2_image->x0 = 0; + jp2_image->y0 = 0; + jp2_image->x1 = image->width; + jp2_image->y1 = image->height; + int n = image->width * image->height; + + for (int i = 0; i < image->components; i++) + std::copy(image->decoded + i * n, image->decoded + (i + 1) * n, jp2_image->comps[i].data); + + opj_cinfo* cinfo = opj_create_compress(CODEC_J2K); + opj_setup_encoder(cinfo, &cparameters, jp2_image); + opj_cio* cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + if (cio == NULL) + throw "opj_cio_open failed"; + + if (!opj_encode(cinfo, cio, jp2_image, cparameters.index)) + return false; + + image->length = cio_tell(cio); + image->encoded = new unsigned char[image->length]; + std::copy(cio->buffer, cio->buffer + image->length, image->encoded); + + opj_image_destroy(jp2_image); + opj_destroy_compress(cinfo); + opj_cio_close(cio); + + return true; + } + + catch (...) + { + return false; + } +} + +bool DotNetDecode64(MarshalledImage* image) +{ + return DotNetDecode(image); +} + +bool DotNetDecode(MarshalledImage* image) +{ + opj_dparameters dparameters; + + try + { + opj_set_default_decoder_parameters(&dparameters); + opj_dinfo_t* dinfo = opj_create_decompress(CODEC_J2K); + opj_setup_decoder(dinfo, &dparameters); + opj_cio* cio = opj_cio_open((opj_common_ptr)dinfo, image->encoded, image->length); + + opj_image* jp2_image = opj_decode(dinfo, cio); // decode happens here + if (jp2_image == NULL) + throw "opj_decode failed"; + + image->width = jp2_image->x1 - jp2_image->x0; + image->height = jp2_image->y1 - jp2_image->y0; + image->components = jp2_image->numcomps; + int n = image->width * image->height; + image->decoded = new unsigned char[n * image->components]; + + for (int i = 0; i < image->components; i++) + std::copy(jp2_image->comps[i].data, jp2_image->comps[i].data + n, image->decoded + i * n); + + opj_image_destroy(jp2_image); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + + return true; + } + catch (...) + { + return false; + } +} +bool DotNetDecodeWithInfo64(MarshalledImage* image) +{ + return DotNetDecodeWithInfo(image); +} + +bool DotNetDecodeWithInfo(MarshalledImage* image) +{ + opj_dparameters dparameters; + opj_codestream_info_t info; + + try + { + opj_set_default_decoder_parameters(&dparameters); + opj_dinfo_t* dinfo = opj_create_decompress(CODEC_J2K); + opj_setup_decoder(dinfo, &dparameters); + opj_cio* cio = opj_cio_open((opj_common_ptr)dinfo, image->encoded, image->length); + + opj_image* jp2_image = opj_decode_with_info(dinfo, cio, &info); // decode happens here + if (jp2_image == NULL) + throw "opj_decode failed"; + + // maximum number of decompositions + int max_numdecompos = 0; + for (int compno = 0; compno < info.numcomps; compno++) + { + if (max_numdecompos < info.numdecompos[compno]) + max_numdecompos = info.numdecompos[compno]; + } + + image->width = jp2_image->x1 - jp2_image->x0; + image->height = jp2_image->y1 - jp2_image->y0; + image->layers = info.numlayers; + image->resolutions = max_numdecompos + 1; + image->components = info.numcomps; + image->packet_count = info.packno; + image->packets = info.tile->packet; + int n = image->width * image->height; + image->decoded = new unsigned char[n * image->components]; + + for (int i = 0; i < image->components; i++) + std::copy(jp2_image->comps[i].data, jp2_image->comps[i].data + n, image->decoded + i * n); + + opj_image_destroy(jp2_image); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + + return true; + } + catch (...) + { + return false; + } +} diff --git a/openjpeg-dotnet/dotnet/dotnet.h b/openjpeg-dotnet/dotnet/dotnet.h new file mode 100644 index 0000000..67c87e8 --- /dev/null +++ b/openjpeg-dotnet/dotnet/dotnet.h @@ -0,0 +1,44 @@ + +#ifndef LIBSL_H +#define LIBSL_H + +#include "../libopenjpeg/openjpeg.h" + +struct MarshalledImage +{ + unsigned char* encoded; + int length; + int dummy; // padding for 64-bit alignment + + unsigned char* decoded; + int width; + int height; + int layers; + int resolutions; + int components; + int packet_count; + opj_packet_info_t* packets; +}; + +#ifdef WIN32 +#define DLLEXPORT extern "C" __declspec(dllexport) +#else +#define DLLEXPORT extern "C" +#endif + +// uncompresed images are raw RGBA 8bit/channel +DLLEXPORT bool DotNetEncode(MarshalledImage* image, bool lossless); +DLLEXPORT bool DotNetDecode(MarshalledImage* image); +DLLEXPORT bool DotNetDecodeWithInfo(MarshalledImage* image); +DLLEXPORT bool DotNetAllocEncoded(MarshalledImage* image); +DLLEXPORT bool DotNetAllocDecoded(MarshalledImage* image); +DLLEXPORT void DotNetFree(MarshalledImage* image); + +DLLEXPORT bool DotNetEncode64(MarshalledImage* image, bool lossless); +DLLEXPORT bool DotNetDecode64(MarshalledImage* image); +DLLEXPORT bool DotNetDecodeWithInfo64(MarshalledImage* image); +DLLEXPORT bool DotNetAllocEncoded64(MarshalledImage* image); +DLLEXPORT bool DotNetAllocDecoded64(MarshalledImage* image); +DLLEXPORT void DotNetFree64(MarshalledImage* image); + +#endif diff --git a/openjpeg-dotnet/libopenjpeg/bio.c b/openjpeg-dotnet/libopenjpeg/bio.c new file mode 100644 index 0000000..4c02f46 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/bio.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Write a bit +@param bio BIO handle +@param b Bit to write (0 or 1) +*/ +static void bio_putbit(opj_bio_t *bio, int b); +/** +Read a bit +@param bio BIO handle +@return Returns the read bit +*/ +static int bio_getbit(opj_bio_t *bio); +/** +Write a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static int bio_byteout(opj_bio_t *bio); +/** +Read a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static int bio_bytein(opj_bio_t *bio); + +/*@}*/ + +/*@}*/ + +/* +========================================================== + local functions +========================================================== +*/ + +static int bio_byteout(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return 1; + } + *bio->bp++ = bio->buf >> 8; + return 0; +} + +static int bio_bytein(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return 1; + } + bio->buf |= *bio->bp++; + return 0; +} + +static void bio_putbit(opj_bio_t *bio, int b) { + if (bio->ct == 0) { + bio_byteout(bio); + } + bio->ct--; + bio->buf |= b << bio->ct; +} + +static int bio_getbit(opj_bio_t *bio) { + if (bio->ct == 0) { + bio_bytein(bio); + } + bio->ct--; + return (bio->buf >> bio->ct) & 1; +} + +/* +========================================================== + Bit Input/Output interface +========================================================== +*/ + +opj_bio_t* bio_create(void) { + opj_bio_t *bio = (opj_bio_t*)opj_malloc(sizeof(opj_bio_t)); + return bio; +} + +void bio_destroy(opj_bio_t *bio) { + if(bio) { + opj_free(bio); + } +} + +int bio_numbytes(opj_bio_t *bio) { + return (bio->bp - bio->start); +} + +void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 8; +} + +void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 0; +} + +void bio_write(opj_bio_t *bio, int v, int n) { + int i; + for (i = n - 1; i >= 0; i--) { + bio_putbit(bio, (v >> i) & 1); + } +} + +int bio_read(opj_bio_t *bio, int n) { + int i, v; + v = 0; + for (i = n - 1; i >= 0; i--) { + v += bio_getbit(bio) << i; + } + return v; +} + +int bio_flush(opj_bio_t *bio) { + bio->ct = 0; + if (bio_byteout(bio)) { + return 1; + } + if (bio->ct == 7) { + bio->ct = 0; + if (bio_byteout(bio)) { + return 1; + } + } + return 0; +} + +int bio_inalign(opj_bio_t *bio) { + bio->ct = 0; + if ((bio->buf & 0xff) == 0xff) { + if (bio_bytein(bio)) { + return 1; + } + bio->ct = 0; + } + return 0; +} diff --git a/openjpeg-dotnet/libopenjpeg/bio.h b/openjpeg-dotnet/libopenjpeg/bio.h new file mode 100644 index 0000000..764d7cb --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/bio.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __BIO_H +#define __BIO_H +/** +@file bio.h +@brief Implementation of an individual bit input-output (BIO) + +The functions in BIO.C have for goal to realize an individual bit input - output. +*/ + +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** +Individual bit input-output stream (BIO) +*/ +typedef struct opj_bio { + /** pointer to the start of the buffer */ + unsigned char *start; + /** pointer to the end of the buffer */ + unsigned char *end; + /** pointer to the present position in the buffer */ + unsigned char *bp; + /** temporary place where each byte is read or written */ + unsigned int buf; + /** coder : number of bits free to write. decoder : number of bits read */ + int ct; +} opj_bio_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new BIO handle +@return Returns a new BIO handle if successful, returns NULL otherwise +*/ +opj_bio_t* bio_create(void); +/** +Destroy a previously created BIO handle +@param bio BIO handle to destroy +*/ +void bio_destroy(opj_bio_t *bio); +/** +Number of bytes written. +@param bio BIO handle +@return Returns the number of bytes written +*/ +int bio_numbytes(opj_bio_t *bio); +/** +Init encoder +@param bio BIO handle +@param bp Output buffer +@param len Output buffer length +*/ +void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len); +/** +Init decoder +@param bio BIO handle +@param bp Input buffer +@param len Input buffer length +*/ +void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len); +/** +Write bits +@param bio BIO handle +@param v Value of bits +@param n Number of bits to write +*/ +void bio_write(opj_bio_t *bio, int v, int n); +/** +Read bits +@param bio BIO handle +@param n Number of bits to read +@return Returns the corresponding read number +*/ +int bio_read(opj_bio_t *bio, int n); +/** +Flush bits +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +int bio_flush(opj_bio_t *bio); +/** +Passes the ending bits (coming from flushing) +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +int bio_inalign(opj_bio_t *bio); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __BIO_H */ + diff --git a/openjpeg-dotnet/libopenjpeg/cidx_manager.c b/openjpeg-dotnet/libopenjpeg/cidx_manager.c new file mode 100644 index 0000000..6131b93 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/cidx_manager.c @@ -0,0 +1,213 @@ +/* + * $Id: cidx_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $ + * + * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2011, Professor Benoit Macq + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include +#include +#include "opj_includes.h" + + +/* + * Write CPTR Codestream finder box + * + * @param[in] coff offset of j2k codestream + * @param[in] clen length of j2k codestream + * @param[in] cio file output handle + */ +void write_cptr(int coff, int clen, opj_cio_t *cio); + + +/* + * Write main header index table (box) + * + * @param[in] coff offset of j2k codestream + * @param[in] cstr_info codestream information + * @param[in] cio file output handle + * @return length of mainmhix box + */ +int write_mainmhix( int coff, opj_codestream_info_t cstr_info, opj_cio_t *cio); + + +/* + * Check if EPH option is used + * + * @param[in] coff offset of j2k codestream + * @param[in] markers marker information + * @param[in] marknum number of markers + * @param[in] cio file output handle + * @return true if EPH is used + */ +opj_bool check_EPHuse( int coff, opj_marker_info_t *markers, int marknum, opj_cio_t *cio); + + +int write_cidx( int offset, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t cstr_info, int j2klen) +{ + int len, i, lenp; + opj_jp2_box_t *box; + int num_box = 0; + opj_bool EPHused; + (void)image; /* unused ? */ + + lenp = -1; + box = (opj_jp2_box_t *)opj_calloc( 32, sizeof(opj_jp2_box_t)); + + for (i=0;i<2;i++){ + + if(i) + cio_seek( cio, lenp); + + lenp = cio_tell( cio); + + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_CIDX, 4); /* CIDX */ + write_cptr( offset, cstr_info.codestream_size, cio); + + write_manf( i, num_box, box, cio); + + num_box = 0; + box[num_box].length = write_mainmhix( offset, cstr_info, cio); + box[num_box].type = JPIP_MHIX; + num_box++; + + box[num_box].length = write_tpix( offset, cstr_info, j2klen, cio); + box[num_box].type = JPIP_TPIX; + num_box++; + + box[num_box].length = write_thix( offset, cstr_info, cio); + box[num_box].type = JPIP_THIX; + num_box++; + + EPHused = check_EPHuse( offset, cstr_info.marker, cstr_info.marknum, cio); + + box[num_box].length = write_ppix( offset, cstr_info, EPHused, j2klen, cio); + box[num_box].type = JPIP_PPIX; + num_box++; + + box[num_box].length = write_phix( offset, cstr_info, EPHused, j2klen, cio); + box[num_box].type = JPIP_PHIX; + num_box++; + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); + } + + opj_free( box); + + return len; +} + +void write_cptr(int coff, int clen, opj_cio_t *cio) +{ + int len, lenp; + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_CPTR, 4); /* T */ + cio_write( cio, 0, 2); /* DR A PRECISER !! */ + cio_write( cio, 0, 2); /* CONT */ + cio_write( cio, coff, 8); /* COFF A PRECISER !! */ + cio_write( cio, clen, 8); /* CLEN */ + len = cio_tell( cio) - lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); +} + +void write_manf(int second, int v, opj_jp2_box_t *box, opj_cio_t *cio) +{ + int len, lenp, i; + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_MANF,4); /* T */ + + if (second){ /* Write only during the second pass */ + for( i=0; i> 2) & 1)) + EPHused = OPJ_TRUE; + cio_seek( cio, org_pos); + + break; + } + } + return EPHused; +} diff --git a/openjpeg-dotnet/libopenjpeg/cidx_manager.h b/openjpeg-dotnet/libopenjpeg/cidx_manager.h new file mode 100644 index 0000000..23eebd5 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/cidx_manager.h @@ -0,0 +1,56 @@ +/* + * $Id: cidx_manager.h 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $ + * + * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2011, Professor Benoit Macq + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +/*! \file + * \brief Modification of jpip.h from 2KAN indexer + */ + + +#ifndef CIDX_MANAGER_H_ +# define CIDX_MANAGER_H_ + +#include "openjpeg.h" + + +/* + * Write Codestream index box (superbox) + * + * @param[in] offset offset of j2k codestream + * @param[in] cio file output handle + * @param[in] image image data + * @param[in] cstr_info codestream information + * @param[in] j2klen length of j2k codestream + * @return length of cidx box + */ +int write_cidx( int offset, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t cstr_info, int j2klen); + + +#endif /* !CIDX_MANAGER_H_ */ diff --git a/openjpeg-dotnet/libopenjpeg/cio.c b/openjpeg-dotnet/libopenjpeg/cio.c new file mode 100644 index 0000000..b8a7ecf --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/cio.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/* ----------------------------------------------------------------------- */ + +opj_cio_t* OPJ_CALLCONV opj_cio_open(opj_common_ptr cinfo, unsigned char *buffer, int length) { + opj_cp_t *cp = NULL; + opj_cio_t *cio = (opj_cio_t*)opj_malloc(sizeof(opj_cio_t)); + if(!cio) return NULL; + cio->cinfo = cinfo; + if(buffer && length) { + /* wrap a user buffer containing the encoded image */ + cio->openmode = OPJ_STREAM_READ; + cio->buffer = buffer; + cio->length = length; + } + else if(!buffer && !length && cinfo) { + /* allocate a buffer for the encoded image */ + cio->openmode = OPJ_STREAM_WRITE; + switch(cinfo->codec_format) { + case CODEC_J2K: + cp = ((opj_j2k_t*)cinfo->j2k_handle)->cp; + break; + case CODEC_JP2: + cp = ((opj_jp2_t*)cinfo->jp2_handle)->j2k->cp; + break; + default: + opj_free(cio); + return NULL; + } + cio->length = (unsigned int) (0.1625 * cp->img_size + 2000); /* 0.1625 = 1.3/8 and 2000 bytes as a minimum for headers */ + cio->buffer = (unsigned char *)opj_malloc(cio->length); + if(!cio->buffer) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error allocating memory for compressed bitstream\n"); + opj_free(cio); + return NULL; + } + } + else { + opj_free(cio); + return NULL; + } + + /* Initialize byte IO */ + cio->start = cio->buffer; + cio->end = cio->buffer + cio->length; + cio->bp = cio->buffer; + + return cio; +} + +void OPJ_CALLCONV opj_cio_close(opj_cio_t *cio) { + if(cio) { + if(cio->openmode == OPJ_STREAM_WRITE) { + /* destroy the allocated buffer */ + opj_free(cio->buffer); + } + /* destroy the cio */ + opj_free(cio); + } +} + + +/* ----------------------------------------------------------------------- */ + +/* + * Get position in byte stream. + */ +int OPJ_CALLCONV cio_tell(opj_cio_t *cio) { + return cio->bp - cio->start; +} + +/* + * Set position in byte stream. + * + * pos : position, in number of bytes, from the beginning of the stream + */ +void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos) { + cio->bp = cio->start + pos; +} + +/* + * Number of bytes left before the end of the stream. + */ +int cio_numbytesleft(opj_cio_t *cio) { + return cio->end - cio->bp; +} + +/* + * Get pointer to the current position in the stream. + */ +unsigned char *cio_getbp(opj_cio_t *cio) { + return cio->bp; +} + +/* + * Write a byte. + */ +opj_bool cio_byteout(opj_cio_t *cio, unsigned char v) { + if (cio->bp >= cio->end) { + opj_event_msg(cio->cinfo, EVT_ERROR, "write error\n"); + return OPJ_FALSE; + } + *cio->bp++ = v; + return OPJ_TRUE; +} + +/* + * Read a byte. + */ +unsigned char cio_bytein(opj_cio_t *cio) { + if (cio->bp >= cio->end) { + opj_event_msg(cio->cinfo, EVT_ERROR, "read error: passed the end of the codestream (start = %d, current = %d, end = %d\n", cio->start, cio->bp, cio->end); + return 0; + } + return *cio->bp++; +} + +/* + * Write some bytes. + * + * v : value to write + * n : number of bytes to write + */ +unsigned int cio_write(opj_cio_t *cio, unsigned long long int v, int n) { + int i; + for (i = n - 1; i >= 0; i--) { + if( !cio_byteout(cio, (unsigned char) ((v >> (i << 3)) & 0xff)) ) + return 0; + } + return n; +} + +/* + * Read some bytes. + * + * n : number of bytes to read + * + * return : value of the n bytes read + */ +unsigned int cio_read(opj_cio_t *cio, int n) { + int i; + unsigned int v; + v = 0; + for (i = n - 1; i >= 0; i--) { + v += cio_bytein(cio) << (i << 3); + } + return v; +} + +/* + * Skip some bytes. + * + * n : number of bytes to skip + */ +void cio_skip(opj_cio_t *cio, int n) { + cio->bp += n; +} + + + diff --git a/openjpeg-dotnet/libopenjpeg/cio.h b/openjpeg-dotnet/libopenjpeg/cio.h new file mode 100644 index 0000000..ce1a13e --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/cio.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __CIO_H +#define __CIO_H +/** +@file cio.h +@brief Implementation of a byte input-output process (CIO) + +The functions in CIO.C have for goal to realize a byte input / output process. +*/ + +/** @defgroup CIO CIO - byte input-output stream */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Number of bytes left before the end of the stream +@param cio CIO handle +@return Returns the number of bytes before the end of the stream +*/ +int cio_numbytesleft(opj_cio_t *cio); +/** +Get pointer to the current position in the stream +@param cio CIO handle +@return Returns a pointer to the current position +*/ +unsigned char *cio_getbp(opj_cio_t *cio); +/** +Write some bytes +@param cio CIO handle +@param v Value to write +@param n Number of bytes to write +@return Returns the number of bytes written or 0 if an error occured +*/ +unsigned int cio_write(opj_cio_t *cio, unsigned long long int v, int n); +/** +Read some bytes +@param cio CIO handle +@param n Number of bytes to read +@return Returns the value of the n bytes read +*/ +unsigned int cio_read(opj_cio_t *cio, int n); +/** +Skip some bytes +@param cio CIO handle +@param n Number of bytes to skip +*/ +void cio_skip(opj_cio_t *cio, int n); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __CIO_H */ + diff --git a/openjpeg-dotnet/libopenjpeg/dwt.c b/openjpeg-dotnet/libopenjpeg/dwt.c new file mode 100644 index 0000000..0fbfc20 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/dwt.c @@ -0,0 +1,858 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Jonathan Ballard + * Copyright (c) 2007, Callum Lerwick + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef __SSE__ +#include +#endif + +#include "opj_includes.h" + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + +#define WS(i) v->mem[(i)*2] +#define WD(i) v->mem[(1+(i)*2)] + +/** @name Local data structures */ +/*@{*/ + +typedef struct dwt_local { + int* mem; + int dn; + int sn; + int cas; +} dwt_t; + +typedef union { + float f[4]; +} v4; + +typedef struct v4dwt_local { + v4* wavelet ; + int dn ; + int sn ; + int cas ; +} v4dwt_t ; + +static const float dwt_alpha = 1.586134342f; /* 12994 */ +static const float dwt_beta = 0.052980118f; /* 434 */ +static const float dwt_gamma = -0.882911075f; /* -7233 */ +static const float dwt_delta = -0.443506852f; /* -3633 */ + +static const float K = 1.230174105f; /* 10078 */ +/* FIXME: What is this constant? */ +static const float c13318 = 1.625732422f; + +/*@}*/ + +/** +Virtual function type for wavelet transform in 1-D +*/ +typedef void (*DWT1DFN)(dwt_t* v); + +/** @name Local static functions */ +/*@{*/ + +/** +Forward lazy transform (horizontal) +*/ +static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas); +/** +Forward lazy transform (vertical) +*/ +static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas); +/** +Inverse lazy transform (horizontal) +*/ +static void dwt_interleave_h(dwt_t* h, int *a); +/** +Inverse lazy transform (vertical) +*/ +static void dwt_interleave_v(dwt_t* v, int *a, int x); +/** +Forward 5-3 wavelet transform in 1-D +*/ +static void dwt_encode_1(int *a, int dn, int sn, int cas); +/** +Inverse 5-3 wavelet transform in 1-D +*/ +static void dwt_decode_1(dwt_t *v); +/** +Forward 9-7 wavelet transform in 1-D +*/ +static void dwt_encode_1_real(int *a, int dn, int sn, int cas); +/** +Explicit calculation of the Quantization Stepsizes +*/ +static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize); +/** +Inverse wavelet transform in 2-D. +*/ +static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int i, DWT1DFN fn); + +/*@}*/ + +/*@}*/ + +#define S(i) a[(i)*2] +#define D(i) a[(1+(i)*2)] +#define S_(i) ((i)<0?S(0):((i)>=sn?S(sn-1):S(i))) +#define D_(i) ((i)<0?D(0):((i)>=dn?D(dn-1):D(i))) +/* new */ +#define SS_(i) ((i)<0?S(0):((i)>=dn?S(dn-1):S(i))) +#define DD_(i) ((i)<0?D(0):((i)>=sn?D(sn-1):D(i))) + +/* */ +/* This table contains the norms of the 5-3 wavelets for different bands. */ +/* */ +static const double dwt_norms[4][10] = { + {1.000, 1.500, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.7186, .9218, 1.586, 3.043, 6.019, 12.01, 24.00, 47.97, 95.93} +}; + +/* */ +/* This table contains the norms of the 9-7 wavelets for different bands. */ +/* */ +static const double dwt_norms_real[4][10] = { + {1.000, 1.965, 4.177, 8.403, 16.90, 33.84, 67.69, 135.3, 270.6, 540.9}, + {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, + {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, + {2.080, 3.865, 8.307, 17.18, 34.71, 69.59, 139.3, 278.6, 557.2} +}; + +/* +========================================================== + local functions +========================================================== +*/ + +/* */ +/* Forward lazy transform (horizontal). */ +/* */ +static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas) { + int i; + for (i=0; i */ +/* Forward lazy transform (vertical). */ +/* */ +static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas) { + int i; + for (i=0; i */ +/* Inverse lazy transform (horizontal). */ +/* */ +static void dwt_interleave_h(dwt_t* h, int *a) { + int *ai = a; + int *bi = h->mem + h->cas; + int i = h->sn; + while( i-- ) { + *bi = *(ai++); + bi += 2; + } + ai = a + h->sn; + bi = h->mem + 1 - h->cas; + i = h->dn ; + while( i-- ) { + *bi = *(ai++); + bi += 2; + } +} + +/* */ +/* Inverse lazy transform (vertical). */ +/* */ +static void dwt_interleave_v(dwt_t* v, int *a, int x) { + int *ai = a; + int *bi = v->mem + v->cas; + int i = v->sn; + while( i-- ) { + *bi = *ai; + bi += 2; + ai += x; + } + ai = a + (v->sn * x); + bi = v->mem + 1 - v->cas; + i = v->dn ; + while( i-- ) { + *bi = *ai; + bi += 2; + ai += x; + } +} + + +/* */ +/* Forward 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_encode_1(int *a, int dn, int sn, int cas) { + int i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) D(i) -= (S_(i) + S_(i + 1)) >> 1; + for (i = 0; i < sn; i++) S(i) += (D_(i - 1) + D_(i) + 2) >> 2; + } + } else { + if (!sn && dn == 1) /* NEW : CASE ONE ELEMENT */ + S(0) *= 2; + else { + for (i = 0; i < dn; i++) S(i) -= (DD_(i) + DD_(i - 1)) >> 1; + for (i = 0; i < sn; i++) D(i) += (SS_(i) + SS_(i + 1) + 2) >> 2; + } + } +} + +/* */ +/* Inverse 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_decode_1_(int *a, int dn, int sn, int cas) { + int i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < sn; i++) S(i) -= (D_(i - 1) + D_(i) + 2) >> 2; + for (i = 0; i < dn; i++) D(i) += (S_(i) + S_(i + 1)) >> 1; + } + } else { + if (!sn && dn == 1) /* NEW : CASE ONE ELEMENT */ + S(0) /= 2; + else { + for (i = 0; i < sn; i++) D(i) -= (SS_(i) + SS_(i + 1) + 2) >> 2; + for (i = 0; i < dn; i++) S(i) += (DD_(i) + DD_(i - 1)) >> 1; + } + } +} + +/* */ +/* Inverse 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_decode_1(dwt_t *v) { + dwt_decode_1_(v->mem, v->dn, v->sn, v->cas); +} + +/* */ +/* Forward 9-7 wavelet transform in 1-D. */ +/* */ +static void dwt_encode_1_real(int *a, int dn, int sn, int cas) { + int i; + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + D(i) -= fix_mul(S_(i) + S_(i + 1), 12993); + for (i = 0; i < sn; i++) + S(i) -= fix_mul(D_(i - 1) + D_(i), 434); + for (i = 0; i < dn; i++) + D(i) += fix_mul(S_(i) + S_(i + 1), 7233); + for (i = 0; i < sn; i++) + S(i) += fix_mul(D_(i - 1) + D_(i), 3633); + for (i = 0; i < dn; i++) + D(i) = fix_mul(D(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + S(i) = fix_mul(S(i), 6659); /*6660 */ + } + } else { + if ((sn > 0) || (dn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + S(i) -= fix_mul(DD_(i) + DD_(i - 1), 12993); + for (i = 0; i < sn; i++) + D(i) -= fix_mul(SS_(i) + SS_(i + 1), 434); + for (i = 0; i < dn; i++) + S(i) += fix_mul(DD_(i) + DD_(i - 1), 7233); + for (i = 0; i < sn; i++) + D(i) += fix_mul(SS_(i) + SS_(i + 1), 3633); + for (i = 0; i < dn; i++) + S(i) = fix_mul(S(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + D(i) = fix_mul(D(i), 6659); /*6660 */ + } + } +} + +static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize) { + int p, n; + p = int_floorlog2(stepsize) - 13; + n = 11 - int_floorlog2(stepsize); + bandno_stepsize->mant = (n < 0 ? stepsize >> -n : stepsize << n) & 0x7ff; + bandno_stepsize->expn = numbps - p; +} + +/* +========================================================== + DWT interface +========================================================== +*/ + +/* */ +/* Forward 5-3 wavelet transform in 2-D. */ +/* */ +void dwt_encode(opj_tcd_tilecomp_t * tilec) { + int i, j, k; + int *a = NULL; + int *aj = NULL; + int *bj = NULL; + int w, l; + + w = tilec->x1-tilec->x0; + l = tilec->numresolutions-1; + a = tilec->data; + + for (i = 0; i < l; i++) { + int rw; /* width of the resolution level computed */ + int rh; /* height of the resolution level computed */ + int rw1; /* width of the resolution level once lower than computed one */ + int rh1; /* height of the resolution level once lower than computed one */ + int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + int dn, sn; + + rw = tilec->resolutions[l - i].x1 - tilec->resolutions[l - i].x0; + rh = tilec->resolutions[l - i].y1 - tilec->resolutions[l - i].y0; + rw1= tilec->resolutions[l - i - 1].x1 - tilec->resolutions[l - i - 1].x0; + rh1= tilec->resolutions[l - i - 1].y1 - tilec->resolutions[l - i - 1].y0; + + cas_row = tilec->resolutions[l - i].x0 % 2; + cas_col = tilec->resolutions[l - i].y0 % 2; + + sn = rh1; + dn = rh - rh1; + bj = (int*)opj_malloc(rh * sizeof(int)); + for (j = 0; j < rw; j++) { + aj = a + j; + for (k = 0; k < rh; k++) bj[k] = aj[k*w]; + dwt_encode_1(bj, dn, sn, cas_col); + dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); + } + opj_free(bj); + + sn = rw1; + dn = rw - rw1; + bj = (int*)opj_malloc(rw * sizeof(int)); + for (j = 0; j < rh; j++) { + aj = a + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + dwt_encode_1(bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + opj_free(bj); + } +} + + +/* */ +/* Inverse 5-3 wavelet transform in 2-D. */ +/* */ +void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres) { + dwt_decode_tile(tilec, numres, &dwt_decode_1); +} + + +/* */ +/* Get gain of 5-3 wavelet transform. */ +/* */ +int dwt_getgain(int orient) { + if (orient == 0) + return 0; + if (orient == 1 || orient == 2) + return 1; + return 2; +} + +/* */ +/* Get norm of 5-3 wavelet. */ +/* */ +double dwt_getnorm(int level, int orient) { + return dwt_norms[orient][level]; +} + +/* */ +/* Forward 9-7 wavelet transform in 2-D. */ +/* */ + +void dwt_encode_real(opj_tcd_tilecomp_t * tilec) { + int i, j, k; + int *a = NULL; + int *aj = NULL; + int *bj = NULL; + int w, l; + + w = tilec->x1-tilec->x0; + l = tilec->numresolutions-1; + a = tilec->data; + + for (i = 0; i < l; i++) { + int rw; /* width of the resolution level computed */ + int rh; /* height of the resolution level computed */ + int rw1; /* width of the resolution level once lower than computed one */ + int rh1; /* height of the resolution level once lower than computed one */ + int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + int dn, sn; + + rw = tilec->resolutions[l - i].x1 - tilec->resolutions[l - i].x0; + rh = tilec->resolutions[l - i].y1 - tilec->resolutions[l - i].y0; + rw1= tilec->resolutions[l - i - 1].x1 - tilec->resolutions[l - i - 1].x0; + rh1= tilec->resolutions[l - i - 1].y1 - tilec->resolutions[l - i - 1].y0; + + cas_row = tilec->resolutions[l - i].x0 % 2; + cas_col = tilec->resolutions[l - i].y0 % 2; + + sn = rh1; + dn = rh - rh1; + bj = (int*)opj_malloc(rh * sizeof(int)); + for (j = 0; j < rw; j++) { + aj = a + j; + for (k = 0; k < rh; k++) bj[k] = aj[k*w]; + dwt_encode_1_real(bj, dn, sn, cas_col); + dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); + } + opj_free(bj); + + sn = rw1; + dn = rw - rw1; + bj = (int*)opj_malloc(rw * sizeof(int)); + for (j = 0; j < rh; j++) { + aj = a + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + dwt_encode_1_real(bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + opj_free(bj); + } +} + + +/* */ +/* Get gain of 9-7 wavelet transform. */ +/* */ +int dwt_getgain_real(int orient) { + (void)orient; + return 0; +} + +/* */ +/* Get norm of 9-7 wavelet. */ +/* */ +double dwt_getnorm_real(int level, int orient) { + return dwt_norms_real[orient][level]; +} + +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { + int numbands, bandno; + numbands = 3 * tccp->numresolutions - 2; + for (bandno = 0; bandno < numbands; bandno++) { + double stepsize; + int resno, level, orient, gain; + + resno = (bandno == 0) ? 0 : ((bandno - 1) / 3 + 1); + orient = (bandno == 0) ? 0 : ((bandno - 1) % 3 + 1); + level = tccp->numresolutions - 1 - resno; + gain = (tccp->qmfbid == 0) ? 0 : ((orient == 0) ? 0 : (((orient == 1) || (orient == 2)) ? 1 : 2)); + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + stepsize = 1.0; + } else { + double norm = dwt_norms_real[orient][level]; + stepsize = (1 << (gain)) / norm; + } + dwt_encode_stepsize((int) floor(stepsize * 8192.0), prec + gain, &tccp->stepsizes[bandno]); + } +} + + +/* */ +/* Determine maximum computed resolution level for inverse wavelet transform */ +/* */ +static int dwt_decode_max_resolution(opj_tcd_resolution_t* restrict r, int i) { + int mr = 1; + int w; + while( --i ) { + r++; + if( mr < ( w = r->x1 - r->x0 ) ) + mr = w ; + if( mr < ( w = r->y1 - r->y0 ) ) + mr = w ; + } + return mr ; +} + + +/* */ +/* Inverse wavelet transform in 2-D. */ +/* */ +static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1D) { + dwt_t h; + dwt_t v; + + opj_tcd_resolution_t* tr = tilec->resolutions; + + int rw = tr->x1 - tr->x0; /* width of the resolution level computed */ + int rh = tr->y1 - tr->y0; /* height of the resolution level computed */ + + int w = tilec->x1 - tilec->x0; + + h.mem = (int*)opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int)); + v.mem = h.mem; + + while( --numres) { + int * restrict tiledp = tilec->data; + int j; + + ++tr; + h.sn = rw; + v.sn = rh; + + rw = tr->x1 - tr->x0; + rh = tr->y1 - tr->y0; + + h.dn = rw - h.sn; + h.cas = tr->x0 % 2; + + for(j = 0; j < rh; ++j) { + dwt_interleave_h(&h, &tiledp[j*w]); + (dwt_1D)(&h); + memcpy(&tiledp[j*w], h.mem, rw * sizeof(int)); + } + + v.dn = rh - v.sn; + v.cas = tr->y0 % 2; + + for(j = 0; j < rw; ++j){ + int k; + dwt_interleave_v(&v, &tiledp[j], w); + (dwt_1D)(&v); + for(k = 0; k < rh; ++k) { + tiledp[k * w + j] = v.mem[k]; + } + } + } + opj_aligned_free(h.mem); +} + +static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, int size){ + float* restrict bi = (float*) (w->wavelet + w->cas); + int count = w->sn; + int i, k; + for(k = 0; k < 2; ++k){ + if (count + 3 * x < size && ((size_t) a & 0x0f) == 0 && ((size_t) bi & 0x0f) == 0 && (x & 0x0f) == 0) { + /* Fast code path */ + for(i = 0; i < count; ++i){ + int j = i; + bi[i*8 ] = a[j]; + j += x; + bi[i*8 + 1] = a[j]; + j += x; + bi[i*8 + 2] = a[j]; + j += x; + bi[i*8 + 3] = a[j]; + } + } else { + /* Slow code path */ + for(i = 0; i < count; ++i){ + int j = i; + bi[i*8 ] = a[j]; + j += x; + if(j > size) continue; + bi[i*8 + 1] = a[j]; + j += x; + if(j > size) continue; + bi[i*8 + 2] = a[j]; + j += x; + if(j > size) continue; + bi[i*8 + 3] = a[j]; + } + } + bi = (float*) (w->wavelet + 1 - w->cas); + a += w->sn; + size -= w->sn; + count = w->dn; + } +} + +static void v4dwt_interleave_v(v4dwt_t* restrict v , float* restrict a , int x){ + v4* restrict bi = v->wavelet + v->cas; + int i; + for(i = 0; i < v->sn; ++i){ + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float)); + } + a += v->sn * x; + bi = v->wavelet + 1 - v->cas; + for(i = 0; i < v->dn; ++i){ + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float)); + } +} + +#ifdef __SSE__ + +static void v4dwt_decode_step1_sse(v4* w, int count, const __m128 c){ + __m128* restrict vw = (__m128*) w; + int i; + /* 4x unrolled loop */ + for(i = 0; i < count >> 2; ++i){ + *vw = _mm_mul_ps(*vw, c); + vw += 2; + *vw = _mm_mul_ps(*vw, c); + vw += 2; + *vw = _mm_mul_ps(*vw, c); + vw += 2; + *vw = _mm_mul_ps(*vw, c); + vw += 2; + } + count &= 3; + for(i = 0; i < count; ++i){ + *vw = _mm_mul_ps(*vw, c); + vw += 2; + } +} + +static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){ + __m128* restrict vl = (__m128*) l; + __m128* restrict vw = (__m128*) w; + int i; + __m128 tmp1, tmp2, tmp3; + tmp1 = vl[0]; + for(i = 0; i < m; ++i){ + tmp2 = vw[-1]; + tmp3 = vw[ 0]; + vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c)); + tmp1 = tmp3; + vw += 2; + } + vl = vw - 2; + if(m >= k){ + return; + } + c = _mm_add_ps(c, c); + c = _mm_mul_ps(c, vl[0]); + for(; m < k; ++m){ + __m128 tmp = vw[-1]; + vw[-1] = _mm_add_ps(tmp, c); + vw += 2; + } +} + +#else + +static void v4dwt_decode_step1(v4* w, int count, const float c){ + float* restrict fw = (float*) w; + int i; + for(i = 0; i < count; ++i){ + float tmp1 = fw[i*8 ]; + float tmp2 = fw[i*8 + 1]; + float tmp3 = fw[i*8 + 2]; + float tmp4 = fw[i*8 + 3]; + fw[i*8 ] = tmp1 * c; + fw[i*8 + 1] = tmp2 * c; + fw[i*8 + 2] = tmp3 * c; + fw[i*8 + 3] = tmp4 * c; + } +} + +static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){ + float* restrict fl = (float*) l; + float* restrict fw = (float*) w; + int i; + for(i = 0; i < m; ++i){ + float tmp1_1 = fl[0]; + float tmp1_2 = fl[1]; + float tmp1_3 = fl[2]; + float tmp1_4 = fl[3]; + float tmp2_1 = fw[-4]; + float tmp2_2 = fw[-3]; + float tmp2_3 = fw[-2]; + float tmp2_4 = fw[-1]; + float tmp3_1 = fw[0]; + float tmp3_2 = fw[1]; + float tmp3_3 = fw[2]; + float tmp3_4 = fw[3]; + fw[-4] = tmp2_1 + ((tmp1_1 + tmp3_1) * c); + fw[-3] = tmp2_2 + ((tmp1_2 + tmp3_2) * c); + fw[-2] = tmp2_3 + ((tmp1_3 + tmp3_3) * c); + fw[-1] = tmp2_4 + ((tmp1_4 + tmp3_4) * c); + fl = fw; + fw += 8; + } + if(m < k){ + float c1; + float c2; + float c3; + float c4; + c += c; + c1 = fl[0] * c; + c2 = fl[1] * c; + c3 = fl[2] * c; + c4 = fl[3] * c; + for(; m < k; ++m){ + float tmp1 = fw[-4]; + float tmp2 = fw[-3]; + float tmp3 = fw[-2]; + float tmp4 = fw[-1]; + fw[-4] = tmp1 + c1; + fw[-3] = tmp2 + c2; + fw[-2] = tmp3 + c3; + fw[-1] = tmp4 + c4; + fw += 8; + } + } +} + +#endif + +/* */ +/* Inverse 9-7 wavelet transform in 1-D. */ +/* */ +static void v4dwt_decode(v4dwt_t* restrict dwt){ + int a, b; + if(dwt->cas == 0) { + if(!((dwt->dn > 0) || (dwt->sn > 1))){ + return; + } + a = 0; + b = 1; + }else{ + if(!((dwt->sn > 0) || (dwt->dn > 1))) { + return; + } + a = 1; + b = 0; + } +#ifdef __SSE__ + v4dwt_decode_step1_sse(dwt->wavelet+a, dwt->sn, _mm_set1_ps(K)); + v4dwt_decode_step1_sse(dwt->wavelet+b, dwt->dn, _mm_set1_ps(c13318)); + v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_delta)); + v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma)); + v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta)); + v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha)); +#else + v4dwt_decode_step1(dwt->wavelet+a, dwt->sn, K); + v4dwt_decode_step1(dwt->wavelet+b, dwt->dn, c13318); + v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_delta); + v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma); + v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta); + v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha); +#endif +} + +/* */ +/* Inverse 9-7 wavelet transform in 2-D. */ +/* */ +void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ + v4dwt_t h; + v4dwt_t v; + + opj_tcd_resolution_t* res = tilec->resolutions; + + int rw = res->x1 - res->x0; /* width of the resolution level computed */ + int rh = res->y1 - res->y0; /* height of the resolution level computed */ + + int w = tilec->x1 - tilec->x0; + + h.wavelet = (v4*) opj_aligned_malloc((dwt_decode_max_resolution(res, numres)+5) * sizeof(v4)); + v.wavelet = h.wavelet; + + while( --numres) { + float * restrict aj = (float*) tilec->data; + int bufsize = (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0); + int j; + + h.sn = rw; + v.sn = rh; + + ++res; + + rw = res->x1 - res->x0; /* width of the resolution level computed */ + rh = res->y1 - res->y0; /* height of the resolution level computed */ + + h.dn = rw - h.sn; + h.cas = res->x0 % 2; + + for(j = rh; j > 3; j -= 4){ + int k; + v4dwt_interleave_h(&h, aj, w, bufsize); + v4dwt_decode(&h); + for(k = rw; --k >= 0;){ + aj[k ] = h.wavelet[k].f[0]; + aj[k+w ] = h.wavelet[k].f[1]; + aj[k+w*2] = h.wavelet[k].f[2]; + aj[k+w*3] = h.wavelet[k].f[3]; + } + aj += w*4; + bufsize -= w*4; + } + if (rh & 0x03) { + int k; + j = rh & 0x03; + v4dwt_interleave_h(&h, aj, w, bufsize); + v4dwt_decode(&h); + for(k = rw; --k >= 0;){ + switch(j) { + case 3: aj[k+w*2] = h.wavelet[k].f[2]; + case 2: aj[k+w ] = h.wavelet[k].f[1]; + case 1: aj[k ] = h.wavelet[k].f[0]; + } + } + } + + v.dn = rh - v.sn; + v.cas = res->y0 % 2; + + aj = (float*) tilec->data; + for(j = rw; j > 3; j -= 4){ + int k; + v4dwt_interleave_v(&v, aj, w); + v4dwt_decode(&v); + for(k = 0; k < rh; ++k){ + memcpy(&aj[k*w], &v.wavelet[k], 4 * sizeof(float)); + } + aj += 4; + } + if (rw & 0x03){ + int k; + j = rw & 0x03; + v4dwt_interleave_v(&v, aj, w); + v4dwt_decode(&v); + for(k = 0; k < rh; ++k){ + memcpy(&aj[k*w], &v.wavelet[k], j * sizeof(float)); + } + } + } + + opj_aligned_free(h.wavelet); +} + diff --git a/openjpeg-dotnet/libopenjpeg/dwt.h b/openjpeg-dotnet/libopenjpeg/dwt.h new file mode 100644 index 0000000..adf73e5 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/dwt.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __DWT_H +#define __DWT_H +/** +@file dwt.h +@brief Implementation of a discrete wavelet transform (DWT) + +The functions in DWT.C have for goal to realize forward and inverse discret wavelet +transform with filter 5-3 (reversible) and filter 9-7 (irreversible). The functions in +DWT.C are used by some function in TCD.C. +*/ + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Forward 5-3 wavelet tranform in 2-D. +Apply a reversible DWT transform to a component of an image. +@param tilec Tile component information (current tile) +*/ +void dwt_encode(opj_tcd_tilecomp_t * tilec); +/** +Inverse 5-3 wavelet tranform in 2-D. +Apply a reversible inverse DWT transform to a component of an image. +@param tilec Tile component information (current tile) +@param numres Number of resolution levels to decode +*/ +void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres); +/** +Get the gain of a subband for the reversible 5-3 DWT. +@param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) +@return Returns 0 if orient = 0, returns 1 if orient = 1 or 2, returns 2 otherwise +*/ +int dwt_getgain(int orient); +/** +Get the norm of a wavelet function of a subband at a specified level for the reversible 5-3 DWT. +@param level Level of the wavelet function +@param orient Band of the wavelet function +@return Returns the norm of the wavelet function +*/ +double dwt_getnorm(int level, int orient); +/** +Forward 9-7 wavelet transform in 2-D. +Apply an irreversible DWT transform to a component of an image. +@param tilec Tile component information (current tile) +*/ +void dwt_encode_real(opj_tcd_tilecomp_t * tilec); +/** +Inverse 9-7 wavelet transform in 2-D. +Apply an irreversible inverse DWT transform to a component of an image. +@param tilec Tile component information (current tile) +@param numres Number of resolution levels to decode +*/ +void dwt_decode_real(opj_tcd_tilecomp_t* tilec, int numres); +/** +Get the gain of a subband for the irreversible 9-7 DWT. +@param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) +@return Returns the gain of the 9-7 wavelet transform +*/ +int dwt_getgain_real(int orient); +/** +Get the norm of a wavelet function of a subband at a specified level for the irreversible 9-7 DWT +@param level Level of the wavelet function +@param orient Band of the wavelet function +@return Returns the norm of the 9-7 wavelet +*/ +double dwt_getnorm_real(int level, int orient); +/** +Explicit calculation of the Quantization Stepsizes +@param tccp Tile-component coding parameters +@param prec Precint analyzed +*/ +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __DWT_H */ diff --git a/openjpeg-dotnet/libopenjpeg/event.c b/openjpeg-dotnet/libopenjpeg/event.c new file mode 100644 index 0000000..0dc22f1 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/event.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/* ========================================================== + Utility functions + ==========================================================*/ + +#ifdef OPJ_CODE_NOT_USED +#ifndef _WIN32 +static char* +i2a(unsigned i, char *a, unsigned r) { + if (i/r > 0) a = i2a(i/r,a,r); + *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r]; + return a+1; +} + +/** + Transforms integer i into an ascii string and stores the result in a; + string is encoded in the base indicated by r. + @param i Number to be converted + @param a String result + @param r Base of value; must be in the range 2 - 36 + @return Returns a +*/ +static char * +_itoa(int i, char *a, int r) { + r = ((r < 2) || (r > 36)) ? 10 : r; + if(i < 0) { + *a = '-'; + *i2a(-i, a+1, r) = 0; + } + else *i2a(i, a, r) = 0; + return a; +} + +#endif /* !_WIN32 */ +#endif +/* ----------------------------------------------------------------------- */ + +opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) { + if(cinfo) { + opj_event_mgr_t *previous = cinfo->event_mgr; + cinfo->event_mgr = event_mgr; + cinfo->client_data = context; + return previous; + } + + return NULL; +} + +opj_bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) { +#define MSG_SIZE 512 /* 512 bytes should be more than enough for a short message */ + opj_msg_callback msg_handler = NULL; + + opj_event_mgr_t *event_mgr = cinfo->event_mgr; + if(event_mgr != NULL) { + switch(event_type) { + case EVT_ERROR: + msg_handler = event_mgr->error_handler; + break; + case EVT_WARNING: + msg_handler = event_mgr->warning_handler; + break; + case EVT_INFO: + msg_handler = event_mgr->info_handler; + break; + default: + break; + } + if(msg_handler == NULL) { + return OPJ_FALSE; + } + } else { + return OPJ_FALSE; + } + + if ((fmt != NULL) && (event_mgr != NULL)) { + va_list arg; + int str_length/*, i, j*/; /* UniPG */ + char message[MSG_SIZE]; + memset(message, 0, MSG_SIZE); + /* initialize the optional parameter list */ + va_start(arg, fmt); + /* check the length of the format string */ + str_length = (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt); + /* parse the format string and put the result in 'message' */ + vsprintf(message, fmt, arg); /* UniPG */ + /* deinitialize the optional parameter list */ + va_end(arg); + + /* output the message to the user program */ + msg_handler(message, cinfo->client_data); + } + + return OPJ_TRUE; +} + diff --git a/openjpeg-dotnet/libopenjpeg/event.h b/openjpeg-dotnet/libopenjpeg/event.h new file mode 100644 index 0000000..9c59787 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/event.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __EVENT_H +#define __EVENT_H +/** +@file event.h +@brief Implementation of a event callback system + +The functions in EVENT.C have for goal to send output messages (errors, warnings, debug) to the user. +*/ + +#define EVT_ERROR 1 /**< Error event type */ +#define EVT_WARNING 2 /**< Warning event type */ +#define EVT_INFO 4 /**< Debug event type */ + +/** @defgroup EVENT EVENT - Implementation of a event callback system */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write formatted data to a string and send the string to a user callback. +@param cinfo Codec context info +@param event_type Event type or callback to use to send the message +@param fmt Format-control string (plus optionnal arguments) +@return Returns true if successful, returns false otherwise +*/ +opj_bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __EVENT_H */ diff --git a/openjpeg-dotnet/libopenjpeg/fix.h b/openjpeg-dotnet/libopenjpeg/fix.h new file mode 100644 index 0000000..bcb2acb --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/fix.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __FIX_H +#define __FIX_H + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define int64 __int64 +#else +#define int64 long long +#endif + +/** +@file fix.h +@brief Implementation of operations of specific multiplication (FIX) + +The functions in FIX.H have for goal to realize specific multiplication. +*/ + +/** @defgroup FIX FIX - Implementation of operations of specific multiplication */ +/*@{*/ + +/** +Multiply two fixed-precision rational numbers. +@param a +@param b +@return Returns a * b +*/ +static INLINE int fix_mul(int a, int b) { + int64 temp = (int64) a * (int64) b ; + temp += temp & 4096; + return (int) (temp >> 13) ; +} + +/*@}*/ + +#endif /* __FIX_H */ diff --git a/openjpeg-dotnet/libopenjpeg/image.c b/openjpeg-dotnet/libopenjpeg/image.c new file mode 100644 index 0000000..a4d2c01 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/image.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +opj_image_t* opj_image_create0(void) { + opj_image_t *image = (opj_image_t*)opj_calloc(1, sizeof(opj_image_t)); + return image; +} + +opj_image_t* OPJ_CALLCONV opj_image_create(int numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { + int compno; + opj_image_t *image = NULL; + + image = (opj_image_t*) opj_calloc(1, sizeof(opj_image_t)); + if(image) { + image->color_space = clrspc; + image->numcomps = numcmpts; + /* allocate memory for the per-component information */ + image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t)); + if(!image->comps) { + fprintf(stderr,"Unable to allocate memory for image.\n"); + opj_image_destroy(image); + return NULL; + } + /* create the individual image components */ + for(compno = 0; compno < numcmpts; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + comp->dx = cmptparms[compno].dx; + comp->dy = cmptparms[compno].dy; + comp->w = cmptparms[compno].w; + comp->h = cmptparms[compno].h; + comp->x0 = cmptparms[compno].x0; + comp->y0 = cmptparms[compno].y0; + comp->prec = cmptparms[compno].prec; + comp->bpp = cmptparms[compno].bpp; + comp->sgnd = cmptparms[compno].sgnd; + comp->data = (int*) opj_calloc(comp->w * comp->h, sizeof(int)); + if(!comp->data) { + fprintf(stderr,"Unable to allocate memory for image.\n"); + opj_image_destroy(image); + return NULL; + } + } + } + + return image; +} + +void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) { + int i; + if(image) { + if(image->comps) { + /* image components */ + for(i = 0; i < image->numcomps; i++) { + opj_image_comp_t *image_comp = &image->comps[i]; + if(image_comp->data) { + opj_free(image_comp->data); + } + } + opj_free(image->comps); + } + opj_free(image); + } +} + diff --git a/openjpeg-dotnet/libopenjpeg/image.h b/openjpeg-dotnet/libopenjpeg/image.h new file mode 100644 index 0000000..f828b5b --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/image.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __IMAGE_H +#define __IMAGE_H +/** +@file image.h +@brief Implementation of operations on images (IMAGE) + +The functions in IMAGE.C have for goal to realize operations on images. +*/ + +/** @defgroup IMAGE IMAGE - Implementation of operations on images */ +/*@{*/ + +/** +Create an empty image +@todo this function should be removed +@return returns an empty image if successful, returns NULL otherwise +*/ +opj_image_t* opj_image_create0(void); + +/*@}*/ + +#endif /* __IMAGE_H */ + diff --git a/openjpeg-dotnet/libopenjpeg/indexbox_manager.h b/openjpeg-dotnet/libopenjpeg/indexbox_manager.h new file mode 100644 index 0000000..7364df6 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/indexbox_manager.h @@ -0,0 +1,118 @@ +/* + * $Id: indexbox_manager.h 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $ + * + * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2011, Professor Benoit Macq + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +/*! \file + * \brief Modification of jpip.c from 2KAN indexer + */ + +#ifndef INDEXBOX_MANAGER_H_ +# define INDEXBOX_MANAGER_H_ + +#include "openjpeg.h" +#include "j2k.h" /* needed to use jp2.h */ +#include "jp2.h" + +#define JPIP_CIDX 0x63696478 /* Codestream index */ +#define JPIP_CPTR 0x63707472 /* Codestream Finder Box */ +#define JPIP_MANF 0x6d616e66 /* Manifest Box */ +#define JPIP_FAIX 0x66616978 /* Fragment array Index box */ +#define JPIP_MHIX 0x6d686978 /* Main Header Index Table */ +#define JPIP_TPIX 0x74706978 /* Tile-part Index Table box */ +#define JPIP_THIX 0x74686978 /* Tile header Index Table box */ +#define JPIP_PPIX 0x70706978 /* Precinct Packet Index Table box */ +#define JPIP_PHIX 0x70686978 /* Packet Header index Table */ +#define JPIP_FIDX 0x66696478 /* File Index */ +#define JPIP_FPTR 0x66707472 /* File Finder */ +#define JPIP_PRXY 0x70727879 /* Proxy boxes */ +#define JPIP_IPTR 0x69707472 /* Index finder box */ +#define JPIP_PHLD 0x70686c64 /* Place holder */ + + +/* + * Write tile-part Index table box (superbox) + * + * @param[in] coff offset of j2k codestream + * @param[in] cstr_info codestream information + * @param[in] j2klen length of j2k codestream + * @param[in] cio file output handle + * @return length of tpix box + */ +int write_tpix( int coff, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio); + + +/* + * Write tile header index table box (superbox) + * + * @param[in] coff offset of j2k codestream + * @param[in] cstr_info codestream information pointer + * @param[in] cio file output handle + * @return length of thix box + */ +int write_thix( int coff, opj_codestream_info_t cstr_info, opj_cio_t *cio); + + +/* + * Write precinct packet index table box (superbox) + * + * @param[in] coff offset of j2k codestream + * @param[in] cstr_info codestream information + * @param[in] EPHused true if EPH option used + * @param[in] j2klen length of j2k codestream + * @param[in] cio file output handle + * @return length of ppix box + */ +int write_ppix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio); + + +/* + * Write packet header index table box (superbox) + * + * @param[in] coff offset of j2k codestream + * @param[in] cstr_info codestream information + * @param[in] EPHused true if EPH option used + * @param[in] j2klen length of j2k codestream + * @param[in] cio file output handle + * @return length of ppix box + */ +int write_phix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio); + +/* + * Wriet manifest box (box) + * + * @param[in] second number to be visited + * @param[in] v number of boxes + * @param[in] box box to be manifested + * @param[in] cio file output handle + */ +void write_manf(int second, int v, opj_jp2_box_t *box, opj_cio_t *cio); + + +#endif /* !INDEXBOX_MANAGER_H_ */ diff --git a/openjpeg-dotnet/libopenjpeg/int.h b/openjpeg-dotnet/libopenjpeg/int.h new file mode 100644 index 0000000..4e5fe08 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/int.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __INT_H +#define __INT_H +/** +@file int.h +@brief Implementation of operations on integers (INT) + +The functions in INT.H have for goal to realize operations on integers. +*/ + +/** @defgroup INT INT - Implementation of operations on integers */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Get the minimum of two integers +@return Returns a if a < b else b +*/ +static INLINE int int_min(int a, int b) { + return a < b ? a : b; +} +/** +Get the maximum of two integers +@return Returns a if a > b else b +*/ +static INLINE int int_max(int a, int b) { + return (a > b) ? a : b; +} +/** +Clamp an integer inside an interval +@return +
    +
  • Returns a if (min < a < max) +
  • Returns max if (a > max) +
  • Returns min if (a < min) +
+*/ +static INLINE int int_clamp(int a, int min, int max) { + if (a < min) + return min; + if (a > max) + return max; + return a; +} +/** +@return Get absolute value of integer +*/ +static INLINE int int_abs(int a) { + return a < 0 ? -a : a; +} +/** +Divide an integer and round upwards +@return Returns a divided by b +*/ +static INLINE int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} +/** +Divide an integer by a power of 2 and round upwards +@return Returns a divided by 2^b +*/ +static INLINE int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} +/** +Divide an integer by a power of 2 and round downwards +@return Returns a divided by 2^b +*/ +static INLINE int int_floordivpow2(int a, int b) { + return a >> b; +} +/** +Get logarithm of an integer and round downwards +@return Returns log2(a) +*/ +static INLINE int int_floorlog2(int a) { + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif diff --git a/openjpeg-dotnet/libopenjpeg/j2k.c b/openjpeg-dotnet/libopenjpeg/j2k.c new file mode 100644 index 0000000..d34c75f --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/j2k.c @@ -0,0 +1,2534 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Write the SOC marker (Start Of Codestream) +@param j2k J2K handle +*/ +static void j2k_write_soc(opj_j2k_t *j2k); +/** +Read the SOC marker (Start of Codestream) +@param j2k J2K handle +*/ +static void j2k_read_soc(opj_j2k_t *j2k); +/** +Write the SIZ marker (image and tile size) +@param j2k J2K handle +*/ +static void j2k_write_siz(opj_j2k_t *j2k); +/** +Read the SIZ marker (image and tile size) +@param j2k J2K handle +*/ +static void j2k_read_siz(opj_j2k_t *j2k); +/** +Write the COM marker (comment) +@param j2k J2K handle +*/ +static void j2k_write_com(opj_j2k_t *j2k); +/** +Read the COM marker (comment) +@param j2k J2K handle +*/ +static void j2k_read_com(opj_j2k_t *j2k); +/** +Write the value concerning the specified component in the marker COD and COC +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_cox(opj_j2k_t *j2k, int compno); +/** +Read the value concerning the specified component in the marker COD and COC +@param j2k J2K handle +@param compno Number of the component concerned by the information read +*/ +static void j2k_read_cox(opj_j2k_t *j2k, int compno); +/** +Write the COD marker (coding style default) +@param j2k J2K handle +*/ +static void j2k_write_cod(opj_j2k_t *j2k); +/** +Read the COD marker (coding style default) +@param j2k J2K handle +*/ +static void j2k_read_cod(opj_j2k_t *j2k); +/** +Write the COC marker (coding style component) +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_coc(opj_j2k_t *j2k, int compno); +/** +Read the COC marker (coding style component) +@param j2k J2K handle +*/ +static void j2k_read_coc(opj_j2k_t *j2k); +/** +Write the value concerning the specified component in the marker QCD and QCC +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_qcx(opj_j2k_t *j2k, int compno); +/** +Read the value concerning the specified component in the marker QCD and QCC +@param j2k J2K handle +@param compno Number of the component concern by the information read +@param len Length of the information in the QCX part of the marker QCD/QCC +*/ +static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len); +/** +Write the QCD marker (quantization default) +@param j2k J2K handle +*/ +static void j2k_write_qcd(opj_j2k_t *j2k); +/** +Read the QCD marker (quantization default) +@param j2k J2K handle +*/ +static void j2k_read_qcd(opj_j2k_t *j2k); +/** +Write the QCC marker (quantization component) +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_qcc(opj_j2k_t *j2k, int compno); +/** +Read the QCC marker (quantization component) +@param j2k J2K handle +*/ +static void j2k_read_qcc(opj_j2k_t *j2k); +/** +Write the POC marker (progression order change) +@param j2k J2K handle +*/ +static void j2k_write_poc(opj_j2k_t *j2k); +/** +Read the POC marker (progression order change) +@param j2k J2K handle +*/ +static void j2k_read_poc(opj_j2k_t *j2k); +/** +Read the CRG marker (component registration) +@param j2k J2K handle +*/ +static void j2k_read_crg(opj_j2k_t *j2k); +/** +Read the TLM marker (tile-part lengths) +@param j2k J2K handle +*/ +static void j2k_read_tlm(opj_j2k_t *j2k); +/** +Read the PLM marker (packet length, main header) +@param j2k J2K handle +*/ +static void j2k_read_plm(opj_j2k_t *j2k); +/** +Read the PLT marker (packet length, tile-part header) +@param j2k J2K handle +*/ +static void j2k_read_plt(opj_j2k_t *j2k); +/** +Read the PPM marker (packet packet headers, main header) +@param j2k J2K handle +*/ +static void j2k_read_ppm(opj_j2k_t *j2k); +/** +Read the PPT marker (packet packet headers, tile-part header) +@param j2k J2K handle +*/ +static void j2k_read_ppt(opj_j2k_t *j2k); +/** +Write the TLM marker (Mainheader) +@param j2k J2K handle +*/ +static void j2k_write_tlm(opj_j2k_t *j2k); +/** +Write the SOT marker (start of tile-part) +@param j2k J2K handle +*/ +static void j2k_write_sot(opj_j2k_t *j2k); +/** +Read the SOT marker (start of tile-part) +@param j2k J2K handle +*/ +static void j2k_read_sot(opj_j2k_t *j2k); +/** +Write the SOD marker (start of data) +@param j2k J2K handle +@param tile_coder Pointer to a TCD handle +*/ +static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder); +/** +Read the SOD marker (start of data) +@param j2k J2K handle +*/ +static void j2k_read_sod(opj_j2k_t *j2k); +/** +Write the RGN marker (region-of-interest) +@param j2k J2K handle +@param compno Number of the component concerned by the information written +@param tileno Number of the tile concerned by the information written +*/ +static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno); +/** +Read the RGN marker (region-of-interest) +@param j2k J2K handle +*/ +static void j2k_read_rgn(opj_j2k_t *j2k); +/** +Write the EOC marker (end of codestream) +@param j2k J2K handle +*/ +static void j2k_write_eoc(opj_j2k_t *j2k); +/** +Read the EOC marker (end of codestream) +@param j2k J2K handle +*/ +static void j2k_read_eoc(opj_j2k_t *j2k); +/** +Read an unknown marker +@param j2k J2K handle +*/ +static void j2k_read_unk(opj_j2k_t *j2k); +/** +Add main header marker information +@param cstr_info Codestream information structure +@param type marker type +@param pos byte offset of marker segment +@param len length of marker segment + */ +static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len); +/** +Add tile header marker information +@param tileno tile index number +@param cstr_info Codestream information structure +@param type marker type +@param pos byte offset of marker segment +@param len length of marker segment + */ +static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ +typedef struct j2k_prog_order{ + OPJ_PROG_ORDER enum_prog; + char str_prog[5]; +}j2k_prog_order_t; + +j2k_prog_order_t j2k_prog_order_list[] = { + {CPRL, "CPRL"}, + {LRCP, "LRCP"}, + {PCRL, "PCRL"}, + {RLCP, "RLCP"}, + {RPCL, "RPCL"}, + {(OPJ_PROG_ORDER)-1, ""} +}; + +char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order){ + j2k_prog_order_t *po; + for(po = j2k_prog_order_list; po->enum_prog != -1; po++ ){ + if(po->enum_prog == prg_order){ + break; + } + } + return po->str_prog; +} + +/* ----------------------------------------------------------------------- */ +static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){ + char *prog; + int i; + int tpnum=1,tpend=0; + opj_tcp_t *tcp = &cp->tcps[tileno]; + prog = j2k_convert_progression_order(tcp->prg); + + if(cp->tp_on == 1){ + for(i=0;i<4;i++){ + if(tpend!=1){ + if( cp->tp_flag == prog[i] ){ + tpend=1;cp->tp_pos=i; + } + switch(prog[i]){ + case 'C': + tpnum= tpnum * tcp->pocs[pino].compE; + break; + case 'R': + tpnum= tpnum * tcp->pocs[pino].resE; + break; + case 'P': + tpnum= tpnum * tcp->pocs[pino].prcE; + break; + case 'L': + tpnum= tpnum * tcp->pocs[pino].layE; + break; + } + } + } + }else{ + tpnum=1; + } + return tpnum; +} + +/** mem allocation for TLM marker*/ +int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t *j2k ){ + int pino,tileno,totnum_tp=0; + + OPJ_ARG_NOT_USED(img_numcomp); + + j2k->cur_totnum_tp = (int *) opj_malloc(cp->tw * cp->th * sizeof(int)); + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + int cur_totnum_tp = 0; + opj_tcp_t *tcp = &cp->tcps[tileno]; + for(pino = 0; pino <= tcp->numpocs; pino++) { + int tp_num=0; + opj_pi_iterator_t *pi = pi_initialise_encode(image, cp, tileno,FINAL_PASS); + if(!pi) { return -1;} + tp_num = j2k_get_num_tp(cp,pino,tileno); + totnum_tp = totnum_tp + tp_num; + cur_totnum_tp = cur_totnum_tp + tp_num; + pi_destroy(pi, cp, tileno); + } + j2k->cur_totnum_tp[tileno] = cur_totnum_tp; + /* INDEX >> */ + if (j2k->cstr_info) { + j2k->cstr_info->tile[tileno].num_tps = cur_totnum_tp; + j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(cur_totnum_tp * sizeof(opj_tp_info_t)); + } + /* << INDEX */ + } + return totnum_tp; +} + +static void j2k_write_soc(opj_j2k_t *j2k) { + opj_cio_t *cio = j2k->cio; + cio_write(cio, J2K_MS_SOC, 2); + + if(j2k->cstr_info) + j2k_add_mhmarker(j2k->cstr_info, J2K_MS_SOC, cio_tell(cio), 0); + +/* UniPG>> */ +#ifdef USE_JPWL + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_SOC, cio_tell(cio) - 2, 2); +#endif /* USE_JPWL */ +/* <state = J2K_STATE_MHSIZ; + /* Index */ + if (j2k->cstr_info) { + j2k->cstr_info->main_head_start = cio_tell(j2k->cio) - 2; + j2k->cstr_info->codestream_size = cio_numbytesleft(j2k->cio) + 2 - j2k->cstr_info->main_head_start; + } +} + +static void j2k_write_siz(opj_j2k_t *j2k) { + int i; + int lenp, len; + + opj_cio_t *cio = j2k->cio; + opj_image_t *image = j2k->image; + opj_cp_t *cp = j2k->cp; + + cio_write(cio, J2K_MS_SIZ, 2); /* SIZ */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, cp->rsiz, 2); /* Rsiz (capabilities) */ + cio_write(cio, image->x1, 4); /* Xsiz */ + cio_write(cio, image->y1, 4); /* Ysiz */ + cio_write(cio, image->x0, 4); /* X0siz */ + cio_write(cio, image->y0, 4); /* Y0siz */ + cio_write(cio, cp->tdx, 4); /* XTsiz */ + cio_write(cio, cp->tdy, 4); /* YTsiz */ + cio_write(cio, cp->tx0, 4); /* XT0siz */ + cio_write(cio, cp->ty0, 4); /* YT0siz */ + cio_write(cio, image->numcomps, 2); /* Csiz */ + for (i = 0; i < image->numcomps; i++) { + cio_write(cio, image->comps[i].prec - 1 + (image->comps[i].sgnd << 7), 1); /* Ssiz_i */ + cio_write(cio, image->comps[i].dx, 1); /* XRsiz_i */ + cio_write(cio, image->comps[i].dy, 1); /* YRsiz_i */ + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsiz */ + cio_seek(cio, lenp + len); + + if(j2k->cstr_info) + j2k_add_mhmarker(j2k->cstr_info, J2K_MS_SIZ, lenp, len); +} + +static void j2k_read_siz(opj_j2k_t *j2k) { + int len, i; + + opj_cio_t *cio = j2k->cio; + opj_image_t *image = j2k->image; + opj_cp_t *cp = j2k->cp; + + len = cio_read(cio, 2); /* Lsiz */ + cio_read(cio, 2); /* Rsiz (capabilities) */ + image->x1 = cio_read(cio, 4); /* Xsiz */ + image->y1 = cio_read(cio, 4); /* Ysiz */ + image->x0 = cio_read(cio, 4); /* X0siz */ + image->y0 = cio_read(cio, 4); /* Y0siz */ + cp->tdx = cio_read(cio, 4); /* XTsiz */ + cp->tdy = cio_read(cio, 4); /* YTsiz */ + cp->tx0 = cio_read(cio, 4); /* XT0siz */ + cp->ty0 = cio_read(cio, 4); /* YT0siz */ + + if ((image->x0<0)||(image->x1<0)||(image->y0<0)||(image->y1<0)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "%s: invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n", + image->x0,image->x1,image->y0,image->y1); + return; + } + + image->numcomps = cio_read(cio, 2); /* Csiz */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if (!(image->x1 * image->y1)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad image size (%d x %d)\n", + image->x1, image->y1); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + if (image->numcomps != ((len - 38) / 3)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: Csiz is %d => space in SIZ only for %d comps.!!!\n", + image->numcomps, ((len - 38) / 3)); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n"); + if (image->numcomps < ((len - 38) / 3)) { + len = 38 + 3 * image->numcomps; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting Lsiz to %d => HYPOTHESIS!!!\n", + len); + } else { + image->numcomps = ((len - 38) / 3); + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting Csiz to %d => HYPOTHESIS!!!\n", + image->numcomps); + } + } + + /* update components number in the jpwl_exp_comps filed */ + cp->exp_comps = image->numcomps; + } +#endif /* USE_JPWL */ + + image->comps = (opj_image_comp_t*) opj_calloc(image->numcomps, sizeof(opj_image_comp_t)); + for (i = 0; i < image->numcomps; i++) { + int tmp, w, h; + tmp = cio_read(cio, 1); /* Ssiz_i */ + image->comps[i].prec = (tmp & 0x7f) + 1; + image->comps[i].sgnd = tmp >> 7; + image->comps[i].dx = cio_read(cio, 1); /* XRsiz_i */ + image->comps[i].dy = cio_read(cio, 1); /* YRsiz_i */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters, again */ + if (!(image->comps[i].dx * image->comps[i].dy)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad XRsiz_%d/YRsiz_%d (%d x %d)\n", + i, i, image->comps[i].dx, image->comps[i].dy); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (!image->comps[i].dx) { + image->comps[i].dx = 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting XRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dx); + } + if (!image->comps[i].dy) { + image->comps[i].dy = 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting YRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dy); + } + } + + } +#endif /* USE_JPWL */ + + /* TODO: unused ? */ + w = int_ceildiv(image->x1 - image->x0, image->comps[i].dx); + h = int_ceildiv(image->y1 - image->y0, image->comps[i].dy); + + image->comps[i].resno_decoded = 0; /* number of resolution decoded */ + image->comps[i].factor = cp->reduce; /* reducing factor per component */ + } + + cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if ((cp->tw < 1) || (cp->th < 1) || (cp->tw > cp->max_tiles) || (cp->th > cp->max_tiles)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of tiles (%d x %d)\n", + cp->tw, cp->th); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (cp->tw < 1) { + cp->tw= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->tw); + } + if (cp->tw > cp->max_tiles) { + cp->tw= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- too large x, increase expectance of %d\n" + "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->max_tiles, cp->tw); + } + if (cp->th < 1) { + cp->th= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->th); + } + if (cp->th > cp->max_tiles) { + cp->th= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- too large y, increase expectance of %d to continue\n", + "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->max_tiles, cp->th); + } + } + } +#endif /* USE_JPWL */ + + cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + cp->tileno = (int*) opj_malloc(cp->tw * cp->th * sizeof(int)); + cp->tileno_size = 0; + +#ifdef USE_JPWL + if (j2k->cp->correct) { + if (!cp->tcps) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: could not alloc tcps field of cp\n"); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + } +#endif /* USE_JPWL */ + + for (i = 0; i < cp->tw * cp->th; i++) { + cp->tcps[i].POC = 0; + cp->tcps[i].numpocs = 0; + cp->tcps[i].first = 1; + } + + /* Initialization for PPM marker */ + cp->ppm = 0; + cp->ppm_data = NULL; + cp->ppm_data_first = NULL; + cp->ppm_previous = 0; + cp->ppm_store = 0; + + j2k->default_tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + for (i = 0; i < cp->tw * cp->th; i++) { + cp->tcps[i].tccps = (opj_tccp_t*) opj_malloc(image->numcomps * sizeof(opj_tccp_t)); + } + j2k->tile_data = (unsigned char**) opj_calloc(cp->tw * cp->th, sizeof(unsigned char*)); + j2k->tile_len = (int*) opj_calloc(cp->tw * cp->th, sizeof(int)); + j2k->state = J2K_STATE_MH; + + /* Index */ + if (j2k->cstr_info) { + opj_codestream_info_t *cstr_info = j2k->cstr_info; + cstr_info->image_w = image->x1 - image->x0; + cstr_info->image_h = image->y1 - image->y0; + cstr_info->numcomps = image->numcomps; + cstr_info->tw = cp->tw; + cstr_info->th = cp->th; + cstr_info->tile_x = cp->tdx; + cstr_info->tile_y = cp->tdy; + cstr_info->tile_Ox = cp->tx0; + cstr_info->tile_Oy = cp->ty0; + cstr_info->tile = (opj_tile_info_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tile_info_t)); + } +} + +static void j2k_write_com(opj_j2k_t *j2k) { + unsigned int i; + int lenp, len; + + if(j2k->cp->comment) { + opj_cio_t *cio = j2k->cio; + char *comment = j2k->cp->comment; + + cio_write(cio, J2K_MS_COM, 2); + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, 1, 2); /* General use (IS 8859-15:1999 (Latin) values) */ + for (i = 0; i < strlen(comment); i++) { + cio_write(cio, comment[i], 1); + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); + cio_seek(cio, lenp + len); + + + if(j2k->cstr_info) + j2k_add_mhmarker(j2k->cstr_info, J2K_MS_COM, lenp, len); + + } +} + +static void j2k_read_com(opj_j2k_t *j2k) { + int len; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + cio_skip(cio, len - 2); +} + +static void j2k_write_cox(opj_j2k_t *j2k, int compno) { + int i; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + cio_write(cio, tccp->numresolutions - 1, 1); /* SPcox (D) */ + cio_write(cio, tccp->cblkw - 2, 1); /* SPcox (E) */ + cio_write(cio, tccp->cblkh - 2, 1); /* SPcox (F) */ + cio_write(cio, tccp->cblksty, 1); /* SPcox (G) */ + cio_write(cio, tccp->qmfbid, 1); /* SPcox (H) */ + + if (tccp->csty & J2K_CCP_CSTY_PRT) { + for (i = 0; i < tccp->numresolutions; i++) { + cio_write(cio, tccp->prcw[i] + (tccp->prch[i] << 4), 1); /* SPcox (I_i) */ + } + } +} + +static void j2k_read_cox(opj_j2k_t *j2k, int compno) { + int i; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + tccp->numresolutions = cio_read(cio, 1) + 1; /* SPcox (D) */ + + /* If user wants to remove more resolutions than the codestream contains, return error*/ + if (cp->reduce >= tccp->numresolutions) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions to remove is higher than the number " + "of resolutions of this component\nModify the cp_reduce parameter.\n\n", compno); + j2k->state |= J2K_STATE_ERR; + } + + tccp->cblkw = cio_read(cio, 1) + 2; /* SPcox (E) */ + tccp->cblkh = cio_read(cio, 1) + 2; /* SPcox (F) */ + tccp->cblksty = cio_read(cio, 1); /* SPcox (G) */ + tccp->qmfbid = cio_read(cio, 1); /* SPcox (H) */ + if (tccp->csty & J2K_CP_CSTY_PRT) { + for (i = 0; i < tccp->numresolutions; i++) { + int tmp = cio_read(cio, 1); /* SPcox (I_i) */ + tccp->prcw[i] = tmp & 0xf; + tccp->prch[i] = tmp >> 4; + } + } + + /* INDEX >> */ + if(j2k->cstr_info && compno == 0) { + for (i = 0; i < tccp->numresolutions; i++) { + if (tccp->csty & J2K_CP_CSTY_PRT) { + j2k->cstr_info->tile[j2k->curtileno].pdx[i] = tccp->prcw[i]; + j2k->cstr_info->tile[j2k->curtileno].pdy[i] = tccp->prch[i]; + } + else { + j2k->cstr_info->tile[j2k->curtileno].pdx[i] = 15; + j2k->cstr_info->tile[j2k->curtileno].pdx[i] = 15; + } + } + } + /* << INDEX */ +} + +static void j2k_write_cod(opj_j2k_t *j2k) { + opj_cp_t *cp = NULL; + opj_tcp_t *tcp = NULL; + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_COD, 2); /* COD */ + + lenp = cio_tell(cio); + cio_skip(cio, 2); + + cp = j2k->cp; + tcp = &cp->tcps[j2k->curtileno]; + + cio_write(cio, tcp->csty, 1); /* Scod */ + cio_write(cio, tcp->prg, 1); /* SGcod (A) */ + cio_write(cio, tcp->numlayers, 2); /* SGcod (B) */ + cio_write(cio, tcp->mct, 1); /* SGcod (C) */ + + j2k_write_cox(j2k, 0); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lcod */ + cio_seek(cio, lenp + len); + + if(j2k->cstr_info) + j2k_add_mhmarker(j2k->cstr_info, J2K_MS_COD, lenp, len); + +} + +static void j2k_read_cod(opj_j2k_t *j2k) { + int len, i, pos; + + opj_cio_t *cio = j2k->cio; + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_image_t *image = j2k->image; + + len = cio_read(cio, 2); /* Lcod */ + tcp->csty = cio_read(cio, 1); /* Scod */ + tcp->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* SGcod (A) */ + tcp->numlayers = cio_read(cio, 2); /* SGcod (B) */ + tcp->mct = cio_read(cio, 1); /* SGcod (C) */ + + pos = cio_tell(cio); + for (i = 0; i < image->numcomps; i++) { + tcp->tccps[i].csty = tcp->csty & J2K_CP_CSTY_PRT; + cio_seek(cio, pos); + j2k_read_cox(j2k, i); + } + + /* Index */ + if (j2k->cstr_info) { + opj_codestream_info_t *cstr_info = j2k->cstr_info; + cstr_info->prog = tcp->prg; + cstr_info->numlayers = tcp->numlayers; + cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); + for (i = 0; i < image->numcomps; i++) { + cstr_info->numdecompos[i] = tcp->tccps[i].numresolutions - 1; + } + } +} + +static void j2k_write_coc(opj_j2k_t *j2k, int compno) { + int lenp, len; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_image_t *image = j2k->image; + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_COC, 2); /* COC */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, compno, image->numcomps <= 256 ? 1 : 2); /* Ccoc */ + cio_write(cio, tcp->tccps[compno].csty, 1); /* Scoc */ + j2k_write_cox(j2k, compno); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lcoc */ + cio_seek(cio, lenp + len); +} + +static void j2k_read_coc(opj_j2k_t *j2k) { + int len, compno; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_image_t *image = j2k->image; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lcoc */ + compno = cio_read(cio, image->numcomps <= 256 ? 1 : 2); /* Ccoc */ + tcp->tccps[compno].csty = cio_read(cio, 1); /* Scoc */ + j2k_read_cox(j2k, compno); +} + +static void j2k_write_qcx(opj_j2k_t *j2k, int compno) { + int bandno, numbands; + int expn, mant; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + cio_write(cio, tccp->qntsty + (tccp->numgbits << 5), 1); /* Sqcx */ + numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolutions * 3 - 2; + + for (bandno = 0; bandno < numbands; bandno++) { + expn = tccp->stepsizes[bandno].expn; + mant = tccp->stepsizes[bandno].mant; + + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + cio_write(cio, expn << 3, 1); /* SPqcx_i */ + } else { + cio_write(cio, (expn << 11) + mant, 2); /* SPqcx_i */ + } + } +} + +static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len) { + int tmp; + int bandno, numbands; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + tmp = cio_read(cio, 1); /* Sqcx */ + tccp->qntsty = tmp & 0x1f; + tccp->numgbits = tmp >> 5; + numbands = (tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? + 1 : ((tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) ? len - 1 : (len - 1) / 2); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + /* if JPWL is on, we check whether there are too many subbands */ + if ((numbands < 0) || (numbands >= J2K_MAXBANDS)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of subbands in Sqcx (%d)\n", + numbands); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + numbands = 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n" + "- setting number of bands to %d => HYPOTHESIS!!!\n", + numbands); + }; + + }; + +#else + /* We check whether there are too many subbands */ + if ((numbands < 0) || (numbands >= J2K_MAXBANDS)) { + opj_event_msg(j2k->cinfo, EVT_WARNING , + "bad number of subbands in Sqcx (%d) regarding to J2K_MAXBANDS (%d) \n" + "- limiting number of bands to J2K_MAXBANDS and try to move to the next markers\n", numbands, J2K_MAXBANDS); + } + +#endif /* USE_JPWL */ + + for (bandno = 0; bandno < numbands; bandno++) { + int expn, mant; + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + expn = cio_read(cio, 1) >> 3; /* SPqcx_i */ + mant = 0; + } else { + tmp = cio_read(cio, 2); /* SPqcx_i */ + expn = tmp >> 11; + mant = tmp & 0x7ff; + } + if (bandno < J2K_MAXBANDS){ + tccp->stepsizes[bandno].expn = expn; + tccp->stepsizes[bandno].mant = mant; + } + } + + /* Add Antonin : if scalar_derived -> compute other stepsizes */ + if (tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) { + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + tccp->stepsizes[bandno].expn = + ((tccp->stepsizes[0].expn) - ((bandno - 1) / 3) > 0) ? + (tccp->stepsizes[0].expn) - ((bandno - 1) / 3) : 0; + tccp->stepsizes[bandno].mant = tccp->stepsizes[0].mant; + } + } + /* ddA */ +} + +static void j2k_write_qcd(opj_j2k_t *j2k) { + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_QCD, 2); /* QCD */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + j2k_write_qcx(j2k, 0); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lqcd */ + cio_seek(cio, lenp + len); + + if(j2k->cstr_info) + j2k_add_mhmarker(j2k->cstr_info, J2K_MS_QCD, lenp, len); +} + +static void j2k_read_qcd(opj_j2k_t *j2k) { + int len, i, pos; + + opj_cio_t *cio = j2k->cio; + opj_image_t *image = j2k->image; + + len = cio_read(cio, 2); /* Lqcd */ + pos = cio_tell(cio); + for (i = 0; i < image->numcomps; i++) { + cio_seek(cio, pos); + j2k_read_qcx(j2k, i, len - 2); + } +} + +static void j2k_write_qcc(opj_j2k_t *j2k, int compno) { + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_QCC, 2); /* QCC */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, compno, j2k->image->numcomps <= 256 ? 1 : 2); /* Cqcc */ + j2k_write_qcx(j2k, compno); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lqcc */ + cio_seek(cio, lenp + len); +} + +static void j2k_read_qcc(opj_j2k_t *j2k) { + int len, compno; + int numcomp = j2k->image->numcomps; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lqcc */ + compno = cio_read(cio, numcomp <= 256 ? 1 : 2); /* Cqcc */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + static int backup_compno = 0; + + /* compno is negative or larger than the number of components!!! */ + if ((compno < 0) || (compno >= numcomp)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in QCC (%d out of a maximum of %d)\n", + compno, numcomp); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + compno = backup_compno % numcomp; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting component number to %d\n", + compno); + } + + /* keep your private count of tiles */ + backup_compno++; + }; +#endif /* USE_JPWL */ + + j2k_read_qcx(j2k, compno, len - 2 - (numcomp <= 256 ? 1 : 2)); +} + +static void j2k_write_poc(opj_j2k_t *j2k) { + int len, numpchgs, i; + + int numcomps = j2k->image->numcomps; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[0]; + opj_cio_t *cio = j2k->cio; + + numpchgs = 1 + tcp->numpocs; + cio_write(cio, J2K_MS_POC, 2); /* POC */ + len = 2 + (5 + 2 * (numcomps <= 256 ? 1 : 2)) * numpchgs; + cio_write(cio, len, 2); /* Lpoc */ + for (i = 0; i < numpchgs; i++) { + opj_poc_t *poc = &tcp->pocs[i]; + cio_write(cio, poc->resno0, 1); /* RSpoc_i */ + cio_write(cio, poc->compno0, (numcomps <= 256 ? 1 : 2)); /* CSpoc_i */ + cio_write(cio, poc->layno1, 2); /* LYEpoc_i */ + poc->layno1 = int_min(poc->layno1, tcp->numlayers); + cio_write(cio, poc->resno1, 1); /* REpoc_i */ + poc->resno1 = int_min(poc->resno1, tccp->numresolutions); + cio_write(cio, poc->compno1, (numcomps <= 256 ? 1 : 2)); /* CEpoc_i */ + poc->compno1 = int_min(poc->compno1, numcomps); + cio_write(cio, poc->prg, 1); /* Ppoc_i */ + } +} + +static void j2k_read_poc(opj_j2k_t *j2k) { + int len, numpchgs, i, old_poc; + + int numcomps = j2k->image->numcomps; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_cio_t *cio = j2k->cio; + + old_poc = tcp->POC ? tcp->numpocs + 1 : 0; + tcp->POC = 1; + len = cio_read(cio, 2); /* Lpoc */ + numpchgs = (len - 2) / (5 + 2 * (numcomps <= 256 ? 1 : 2)); + + for (i = old_poc; i < numpchgs + old_poc; i++) { + opj_poc_t *poc; + poc = &tcp->pocs[i]; + poc->resno0 = cio_read(cio, 1); /* RSpoc_i */ + poc->compno0 = cio_read(cio, numcomps <= 256 ? 1 : 2); /* CSpoc_i */ + poc->layno1 = cio_read(cio, 2); /* LYEpoc_i */ + poc->resno1 = cio_read(cio, 1); /* REpoc_i */ + poc->compno1 = int_min( + cio_read(cio, numcomps <= 256 ? 1 : 2), (unsigned int) numcomps); /* CEpoc_i */ + poc->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* Ppoc_i */ + } + + tcp->numpocs = numpchgs + old_poc - 1; +} + +static void j2k_read_crg(opj_j2k_t *j2k) { + int len, i, Xcrg_i, Ycrg_i; + + opj_cio_t *cio = j2k->cio; + int numcomps = j2k->image->numcomps; + + len = cio_read(cio, 2); /* Lcrg */ + for (i = 0; i < numcomps; i++) { + Xcrg_i = cio_read(cio, 2); /* Xcrg_i */ + Ycrg_i = cio_read(cio, 2); /* Ycrg_i */ + } +} + +static void j2k_read_tlm(opj_j2k_t *j2k) { + int len, Ztlm, Stlm, ST, SP, tile_tlm, i; + long int Ttlm_i, Ptlm_i; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Ltlm */ + Ztlm = cio_read(cio, 1); /* Ztlm */ + Stlm = cio_read(cio, 1); /* Stlm */ + ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02); + SP = (Stlm >> 6) & 0x01; + tile_tlm = (len - 4) / ((SP + 1) * 2 + ST); + for (i = 0; i < tile_tlm; i++) { + Ttlm_i = cio_read(cio, ST); /* Ttlm_i */ + Ptlm_i = cio_read(cio, SP ? 4 : 2); /* Ptlm_i */ + } +} + +static void j2k_read_plm(opj_j2k_t *j2k) { + int len, i, Zplm, Nplm, add, packet_len = 0; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lplm */ + Zplm = cio_read(cio, 1); /* Zplm */ + len -= 3; + while (len > 0) { + Nplm = cio_read(cio, 4); /* Nplm */ + len -= 4; + for (i = Nplm; i > 0; i--) { + add = cio_read(cio, 1); + len--; + packet_len = (packet_len << 7) + add; /* Iplm_ij */ + if ((add & 0x80) == 0) { + /* New packet */ + packet_len = 0; + } + if (len <= 0) + break; + } + } +} + +static void j2k_read_plt(opj_j2k_t *j2k) { + int len, i, Zplt, packet_len = 0, add; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lplt */ + Zplt = cio_read(cio, 1); /* Zplt */ + for (i = len - 3; i > 0; i--) { + add = cio_read(cio, 1); + packet_len = (packet_len << 7) + add; /* Iplt_i */ + if ((add & 0x80) == 0) { + /* New packet */ + packet_len = 0; + } + } +} + +static void j2k_read_ppm(opj_j2k_t *j2k) { + int len, Z_ppm, i, j; + int N_ppm; + + opj_cp_t *cp = j2k->cp; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + cp->ppm = 1; + + Z_ppm = cio_read(cio, 1); /* Z_ppm */ + len -= 3; + while (len > 0) { + if (cp->ppm_previous == 0) { + N_ppm = cio_read(cio, 4); /* N_ppm */ + len -= 4; + } else { + N_ppm = cp->ppm_previous; + } + j = cp->ppm_store; + if (Z_ppm == 0) { /* First PPM marker */ + cp->ppm_data = (unsigned char *) opj_malloc(N_ppm * sizeof(unsigned char)); + cp->ppm_data_first = cp->ppm_data; + cp->ppm_len = N_ppm; + } else { /* NON-first PPM marker */ + cp->ppm_data = (unsigned char *) opj_realloc(cp->ppm_data, (N_ppm + cp->ppm_store) * sizeof(unsigned char)); + +#ifdef USE_JPWL + /* this memory allocation check could be done even in non-JPWL cases */ + if (cp->correct) { + if (!cp->ppm_data) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: failed memory allocation during PPM marker parsing (pos. %x)\n", + cio_tell(cio)); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_free(cp->ppm_data); + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + } +#endif + + cp->ppm_data_first = cp->ppm_data; + cp->ppm_len = N_ppm + cp->ppm_store; + } + for (i = N_ppm; i > 0; i--) { /* Read packet header */ + cp->ppm_data[j] = cio_read(cio, 1); + j++; + len--; + if (len == 0) + break; /* Case of non-finished packet header in present marker but finished in next one */ + } + cp->ppm_previous = i - 1; + cp->ppm_store = j; + } +} + +static void j2k_read_ppt(opj_j2k_t *j2k) { + int len, Z_ppt, i, j = 0; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = cp->tcps + j2k->curtileno; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + Z_ppt = cio_read(cio, 1); + tcp->ppt = 1; + if (Z_ppt == 0) { /* First PPT marker */ + tcp->ppt_data = (unsigned char *) opj_malloc((len - 3) * sizeof(unsigned char)); + tcp->ppt_data_first = tcp->ppt_data; + tcp->ppt_store = 0; + tcp->ppt_len = len - 3; + } else { /* NON-first PPT marker */ + tcp->ppt_data = (unsigned char *) opj_realloc(tcp->ppt_data, (len - 3 + tcp->ppt_store) * sizeof(unsigned char)); + tcp->ppt_data_first = tcp->ppt_data; + tcp->ppt_len = len - 3 + tcp->ppt_store; + } + j = tcp->ppt_store; + for (i = len - 3; i > 0; i--) { + tcp->ppt_data[j] = cio_read(cio, 1); + j++; + } + tcp->ppt_store = j; +} + +static void j2k_write_tlm(opj_j2k_t *j2k){ + int lenp; + opj_cio_t *cio = j2k->cio; + j2k->tlm_start = cio_tell(cio); + cio_write(cio, J2K_MS_TLM, 2);/* TLM */ + lenp = 4 + (5*j2k->totnum_tp); + cio_write(cio,lenp,2); /* Ltlm */ + cio_write(cio, 0,1); /* Ztlm=0*/ + cio_write(cio,80,1); /* Stlm ST=1(8bits-255 tiles max),SP=1(Ptlm=32bits) */ + cio_skip(cio,5*j2k->totnum_tp); +} + +static void j2k_write_sot(opj_j2k_t *j2k) { + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + j2k->sot_start = cio_tell(cio); + cio_write(cio, J2K_MS_SOT, 2); /* SOT */ + lenp = cio_tell(cio); + cio_skip(cio, 2); /* Lsot (further) */ + cio_write(cio, j2k->curtileno, 2); /* Isot */ + cio_skip(cio, 4); /* Psot (further in j2k_write_sod) */ + cio_write(cio, j2k->cur_tp_num , 1); /* TPsot */ + cio_write(cio, j2k->cur_totnum_tp[j2k->curtileno], 1); /* TNsot */ + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsot */ + cio_seek(cio, lenp + len); + + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_SOT, j2k->sot_start, len + 2); +#endif /* USE_JPWL */ + /* <cstr_info && j2k->cur_tp_num==0){ + j2k_add_tlmarker( j2k->curtileno, j2k->cstr_info, J2K_MS_SOT, lenp, len); + } +} + +static void j2k_read_sot(opj_j2k_t *j2k) { + int len, tileno, totlen, partno, numparts, i; + opj_tcp_t *tcp = NULL; + char status = 0; + + opj_cp_t *cp = j2k->cp; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + tileno = cio_read(cio, 2); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + static int backup_tileno = 0; + + /* tileno is negative or larger than the number of tiles!!! */ + if ((tileno < 0) || (tileno > (cp->tw * cp->th))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad tile number (%d out of a maximum of %d)\n", + tileno, (cp->tw * cp->th)); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + tileno = backup_tileno; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting tile number to %d\n", + tileno); + } + + /* keep your private count of tiles */ + backup_tileno++; + }; +#endif /* USE_JPWL */ + + if (cp->tileno_size == 0) { + cp->tileno[cp->tileno_size] = tileno; + cp->tileno_size++; + } else { + i = 0; + while (i < cp->tileno_size && status == 0) { + status = cp->tileno[i] == tileno ? 1 : 0; + i++; + } + if (status == 0) { + cp->tileno[cp->tileno_size] = tileno; + cp->tileno_size++; + } + } + + totlen = cio_read(cio, 4); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + /* totlen is negative or larger than the bytes left!!! */ + if ((totlen < 0) || (totlen > (cio_numbytesleft(cio) + 8))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad tile byte size (%d bytes against %d bytes left)\n", + totlen, cio_numbytesleft(cio) + 8); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + totlen = 0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting Psot to %d => assuming it is the last tile\n", + totlen); + } + + }; +#endif /* USE_JPWL */ + + if (!totlen) + totlen = cio_numbytesleft(cio) + 8; + + partno = cio_read(cio, 1); + numparts = cio_read(cio, 1); + + if (partno >= numparts) { + opj_event_msg(j2k->cinfo, EVT_WARNING, "SOT marker inconsistency in tile %d: tile-part index greater (%d) than number of tile-parts (%d)\n", tileno, partno, numparts); + numparts = partno+1; + } + + j2k->curtileno = tileno; + j2k->cur_tp_num = partno; + j2k->eot = cio_getbp(cio) - 12 + totlen; + j2k->state = J2K_STATE_TPH; + tcp = &cp->tcps[j2k->curtileno]; + + /* Index */ + if (j2k->cstr_info) { + if (tcp->first) { + if (tileno == 0) + j2k->cstr_info->main_head_end = cio_tell(cio) - 13; + j2k->cstr_info->tile[tileno].tileno = tileno; + j2k->cstr_info->tile[tileno].start_pos = cio_tell(cio) - 12; + j2k->cstr_info->tile[tileno].end_pos = j2k->cstr_info->tile[tileno].start_pos + totlen - 1; + } else { + j2k->cstr_info->tile[tileno].end_pos += totlen; + } + j2k->cstr_info->tile[tileno].num_tps = numparts; + if (numparts) + j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_realloc(j2k->cstr_info->tile[tileno].tp, numparts * sizeof(opj_tp_info_t)); + else + j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_realloc(j2k->cstr_info->tile[tileno].tp, 10 * sizeof(opj_tp_info_t)); /* Fixme (10)*/ + j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = cio_tell(cio) - 12; + j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos = + j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1; + } + + if (tcp->first == 1) { + /* Initialization PPT */ + opj_tccp_t *tmp = tcp->tccps; + memcpy(tcp, j2k->default_tcp, sizeof(opj_tcp_t)); + tcp->ppt = 0; + tcp->ppt_data = NULL; + tcp->ppt_data_first = NULL; + tcp->tccps = tmp; + + for (i = 0; i < j2k->image->numcomps; i++) { + tcp->tccps[i] = j2k->default_tcp->tccps[i]; + } + cp->tcps[j2k->curtileno].first = 0; + } +} + +static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder) { + int l, layno; + int totlen; + opj_tcp_t *tcp = NULL; + opj_codestream_info_t *cstr_info = NULL; + + opj_tcd_t *tcd = (opj_tcd_t*)tile_coder; /* cast is needed because of conflicts in header inclusions */ + opj_cp_t *cp = j2k->cp; + opj_cio_t *cio = j2k->cio; + + tcd->tp_num = j2k->tp_num ; + tcd->cur_tp_num = j2k->cur_tp_num; + + cio_write(cio, J2K_MS_SOD, 2); + + if( j2k->cstr_info && j2k->cur_tp_num==0){ + j2k_add_tlmarker( j2k->curtileno, j2k->cstr_info, J2K_MS_SOD, cio_tell(cio), 0); + } + + if (j2k->curtileno == 0) { + j2k->sod_start = cio_tell(cio) + j2k->pos_correction; + } + + /* INDEX >> */ + cstr_info = j2k->cstr_info; + if (cstr_info) { + if (!j2k->cur_tp_num ) { + cstr_info->tile[j2k->curtileno].end_header = cio_tell(cio) + j2k->pos_correction - 1; + j2k->cstr_info->tile[j2k->curtileno].tileno = j2k->curtileno; + } + else{ + if(cstr_info->tile[j2k->curtileno].packet[cstr_info->packno - 1].end_pos < cio_tell(cio)) + cstr_info->tile[j2k->curtileno].packet[cstr_info->packno].start_pos = cio_tell(cio); + } + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_SOD, j2k->sod_start, 2); +#endif /* USE_JPWL */ + /* <tcps[j2k->curtileno]; + for (layno = 0; layno < tcp->numlayers; layno++) { + if (tcp->rates[layno]>(j2k->sod_start / (cp->th * cp->tw))) { + tcp->rates[layno]-=(j2k->sod_start / (cp->th * cp->tw)); + } else if (tcp->rates[layno]) { + tcp->rates[layno]=1; + } + } + if(j2k->cur_tp_num == 0){ + tcd->tcd_image->tiles->packno = 0; + if(cstr_info) + cstr_info->packno = 0; + } + + l = tcd_encode_tile(tcd, j2k->curtileno, cio_getbp(cio), cio_numbytesleft(cio) - 2, cstr_info); + + /* Writing Psot in SOT marker */ + totlen = cio_tell(cio) + l - j2k->sot_start; + cio_seek(cio, j2k->sot_start + 6); + cio_write(cio, totlen, 4); + cio_seek(cio, j2k->sot_start + totlen); + /* Writing Ttlm and Ptlm in TLM marker */ + if(cp->cinema){ + cio_seek(cio, j2k->tlm_start + 6 + (5*j2k->cur_tp_num)); + cio_write(cio, j2k->curtileno, 1); + cio_write(cio, totlen, 4); + } + cio_seek(cio, j2k->sot_start + totlen); +} + +static void j2k_read_sod(opj_j2k_t *j2k) { + int len, truncate = 0, i; + unsigned char *data = NULL, *data_ptr = NULL; + + opj_cio_t *cio = j2k->cio; + int curtileno = j2k->curtileno; + + /* Index */ + if (j2k->cstr_info) { + j2k->cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = + cio_tell(cio) + j2k->pos_correction - 1; + if (j2k->cur_tp_num == 0) + j2k->cstr_info->tile[j2k->curtileno].end_header = cio_tell(cio) + j2k->pos_correction - 1; + j2k->cstr_info->packno = 0; + } + + len = int_min(j2k->eot - cio_getbp(cio), cio_numbytesleft(cio) + 1); + + if (len == cio_numbytesleft(cio) + 1) { + truncate = 1; /* Case of a truncate codestream */ + } + + data = j2k->tile_data[curtileno]; + data = (unsigned char*) opj_realloc(data, (j2k->tile_len[curtileno] + len) * sizeof(unsigned char)); + + data_ptr = data + j2k->tile_len[curtileno]; + for (i = 0; i < len; i++) { + data_ptr[i] = cio_read(cio, 1); + } + + j2k->tile_len[curtileno] += len; + j2k->tile_data[curtileno] = data; + + if (!truncate) { + j2k->state = J2K_STATE_TPHSOT; + } else { + j2k->state = J2K_STATE_NEOC; /* RAJOUTE !! */ + } + j2k->cur_tp_num++; +} + +static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno) { + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[tileno]; + opj_cio_t *cio = j2k->cio; + int numcomps = j2k->image->numcomps; + + cio_write(cio, J2K_MS_RGN, 2); /* RGN */ + cio_write(cio, numcomps <= 256 ? 5 : 6, 2); /* Lrgn */ + cio_write(cio, compno, numcomps <= 256 ? 1 : 2); /* Crgn */ + cio_write(cio, 0, 1); /* Srgn */ + cio_write(cio, tcp->tccps[compno].roishift, 1); /* SPrgn */ +} + +static void j2k_read_rgn(opj_j2k_t *j2k) { + int len, compno, roisty; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_cio_t *cio = j2k->cio; + int numcomps = j2k->image->numcomps; + + len = cio_read(cio, 2); /* Lrgn */ + compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */ + roisty = cio_read(cio, 1); /* Srgn */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* totlen is negative or larger than the bytes left!!! */ + if (compno >= numcomps) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in RGN (%d when there are only %d)\n", + compno, numcomps); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + }; +#endif /* USE_JPWL */ + + tcp->tccps[compno].roishift = cio_read(cio, 1); /* SPrgn */ +} + +static void j2k_write_eoc(opj_j2k_t *j2k) { + opj_cio_t *cio = j2k->cio; + /* opj_event_msg(j2k->cinfo, "%.8x: EOC\n", cio_tell(cio) + j2k->pos_correction); */ + cio_write(cio, J2K_MS_EOC, 2); + +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EOC, cio_tell(cio) - 2, 2); +#endif /* USE_JPWL */ +/* <cp->limit_decoding != DECODE_ALL_BUT_PACKETS) { + opj_tcd_t *tcd = tcd_create(j2k->cinfo); + tcd_malloc_decode(tcd, j2k->image, j2k->cp); + for (i = 0; i < j2k->cp->tileno_size; i++) { + tcd_malloc_decode_tile(tcd, j2k->image, j2k->cp, i, j2k->cstr_info); + tileno = j2k->cp->tileno[i]; + success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info); + opj_free(j2k->tile_data[tileno]); + j2k->tile_data[tileno] = NULL; + tcd_free_decode_tile(tcd, i); + if (success == OPJ_FALSE) { + j2k->state |= J2K_STATE_ERR; + break; + } + } + tcd_free_decode(tcd); + tcd_destroy(tcd); + } + /* if packets should not be decoded */ + else { + for (i = 0; i < j2k->cp->tileno_size; i++) { + tileno = j2k->cp->tileno[i]; + opj_free(j2k->tile_data[tileno]); + j2k->tile_data[tileno] = NULL; + } + } + if (j2k->state & J2K_STATE_ERR) + j2k->state = J2K_STATE_MT + J2K_STATE_ERR; + else + j2k->state = J2K_STATE_MT; +} + +typedef struct opj_dec_mstabent { + /** marker value */ + int id; + /** value of the state when the marker can appear */ + int states; + /** action linked to the marker */ + void (*handler) (opj_j2k_t *j2k); +} opj_dec_mstabent_t; + +opj_dec_mstabent_t j2k_dec_mstab[] = { + {J2K_MS_SOC, J2K_STATE_MHSOC, j2k_read_soc}, + {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, j2k_read_sot}, + {J2K_MS_SOD, J2K_STATE_TPH, j2k_read_sod}, + {J2K_MS_EOC, J2K_STATE_TPHSOT, j2k_read_eoc}, + {J2K_MS_SIZ, J2K_STATE_MHSIZ, j2k_read_siz}, + {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_cod}, + {J2K_MS_COC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_coc}, + {J2K_MS_RGN, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_rgn}, + {J2K_MS_QCD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcd}, + {J2K_MS_QCC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcc}, + {J2K_MS_POC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_poc}, + {J2K_MS_TLM, J2K_STATE_MH, j2k_read_tlm}, + {J2K_MS_PLM, J2K_STATE_MH, j2k_read_plm}, + {J2K_MS_PLT, J2K_STATE_TPH, j2k_read_plt}, + {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm}, + {J2K_MS_PPT, J2K_STATE_TPH, j2k_read_ppt}, + {J2K_MS_SOP, 0, 0}, + {J2K_MS_CRG, J2K_STATE_MH, j2k_read_crg}, + {J2K_MS_COM, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_com}, + +#ifdef USE_JPWL + {J2K_MS_EPC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epc}, + {J2K_MS_EPB, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epb}, + {J2K_MS_ESD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_esd}, + {J2K_MS_RED, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_red}, +#endif /* USE_JPWL */ +#ifdef USE_JPSEC + {J2K_MS_SEC, J2K_STATE_MH, j2k_read_sec}, + {J2K_MS_INSEC, 0, j2k_read_insec}, +#endif /* USE_JPSEC */ + + {0, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_unk} +}; + +static void j2k_read_unk(opj_j2k_t *j2k) { + opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown marker\n"); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + int m = 0, id, i; + int min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + id = cio_read(j2k->cio, 2); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: really don't know this marker %x\n", + id); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- possible synch loss due to uncorrectable codestream errors => giving up\n"); + return; + } + /* OK, activate this at your own risk!!! */ + /* we look for the marker at the minimum hamming distance from this */ + while (j2k_dec_mstab[m].id) { + + /* 1's where they differ */ + tmp_id = j2k_dec_mstab[m].id ^ id; + + /* compute the hamming distance between our id and the current */ + cur_dist = 0; + for (i = 0; i < 16; i++) { + if ((tmp_id >> i) & 0x0001) { + cur_dist++; + } + } + + /* if current distance is smaller, set the minimum */ + if (cur_dist < min_dist) { + min_dist = cur_dist; + min_id = j2k_dec_mstab[m].id; + } + + /* jump to the next marker */ + m++; + } + + /* do we substitute the marker? */ + if (min_dist < JPWL_MAXIMUM_HAMMING) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- marker %x is at distance %d from the read %x\n", + min_id, min_dist, id); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- trying to substitute in place and crossing fingers!\n"); + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + cio_write(j2k->cio, min_id, 2); + + /* rewind */ + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + + } + + }; +#endif /* USE_JPWL */ + +} + +/** +Read the lookup table containing all the marker, status and action +@param id Marker value +*/ +static opj_dec_mstabent_t *j2k_dec_mstab_lookup(int id) { + opj_dec_mstabent_t *e; + for (e = j2k_dec_mstab; e->id != 0; e++) { + if (e->id == id) { + break; + } + } + return e; +} + +/* ----------------------------------------------------------------------- */ +/* J2K / JPT decoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_j2k_t* j2k_create_decompress(opj_common_ptr cinfo) { + opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); + if(!j2k) + return NULL; + + j2k->default_tcp = (opj_tcp_t*) opj_calloc(1, sizeof(opj_tcp_t)); + if(!j2k->default_tcp) { + opj_free(j2k); + return NULL; + } + + j2k->cinfo = cinfo; + j2k->tile_data = NULL; + + return j2k; +} + +void j2k_destroy_decompress(opj_j2k_t *j2k) { + int i = 0; + + if(j2k->tile_len != NULL) { + opj_free(j2k->tile_len); + } + if(j2k->tile_data != NULL) { + opj_free(j2k->tile_data); + } + if(j2k->default_tcp != NULL) { + opj_tcp_t *default_tcp = j2k->default_tcp; + if(default_tcp->ppt_data_first != NULL) { + opj_free(default_tcp->ppt_data_first); + } + if(j2k->default_tcp->tccps != NULL) { + opj_free(j2k->default_tcp->tccps); + } + opj_free(j2k->default_tcp); + } + if(j2k->cp != NULL) { + opj_cp_t *cp = j2k->cp; + if(cp->tcps != NULL) { + for(i = 0; i < cp->tw * cp->th; i++) { + if(cp->tcps[i].ppt_data_first != NULL) { + opj_free(cp->tcps[i].ppt_data_first); + } + if(cp->tcps[i].tccps != NULL) { + opj_free(cp->tcps[i].tccps); + } + } + opj_free(cp->tcps); + } + if(cp->ppm_data_first != NULL) { + opj_free(cp->ppm_data_first); + } + if(cp->tileno != NULL) { + opj_free(cp->tileno); + } + if(cp->comment != NULL) { + opj_free(cp->comment); + } + + opj_free(cp); + } + opj_free(j2k); +} + +void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) { + if(j2k && parameters) { + /* create and initialize the coding parameters structure */ + opj_cp_t *cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); + cp->reduce = parameters->cp_reduce; + cp->layer = parameters->cp_layer; + cp->limit_decoding = parameters->cp_limit_decoding; + +#ifdef USE_JPWL + cp->correct = parameters->jpwl_correct; + cp->exp_comps = parameters->jpwl_exp_comps; + cp->max_tiles = parameters->jpwl_max_tiles; +#endif /* USE_JPWL */ + + + /* keep a link to cp so that we can destroy it later in j2k_destroy_decompress */ + j2k->cp = cp; + } +} + +opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + opj_image_t *image = NULL; + + opj_common_ptr cinfo = j2k->cinfo; + + j2k->cio = cio; + j2k->cstr_info = cstr_info; + if (cstr_info) + memset(cstr_info, 0, sizeof(opj_codestream_info_t)); + + /* create an empty image */ + image = opj_image_create0(); + j2k->image = image; + + j2k->state = J2K_STATE_MHSOC; + + for (;;) { + opj_dec_mstabent_t *e; + int id = cio_read(cio, 2); + +#ifdef USE_JPWL + /* we try to honor JPWL correction power */ + if (j2k->cp->correct) { + + int orig_pos = cio_tell(cio); + opj_bool status; + + /* call the corrector */ + status = jpwl_correct(j2k); + + /* go back to where you were */ + cio_seek(cio, orig_pos - 2); + + /* re-read the marker */ + id = cio_read(cio, 2); + + /* check whether it begins with ff */ + if (id >> 8 != 0xff) { + opj_event_msg(cinfo, EVT_ERROR, + "JPWL: possible bad marker %x at %d\n", + id, cio_tell(cio) - 2); + if (!JPWL_ASSUME) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "JPWL: giving up\n"); + return 0; + } + /* we try to correct */ + id = id | 0xff00; + cio_seek(cio, cio_tell(cio) - 2); + cio_write(cio, id, 2); + opj_event_msg(cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting marker to %x\n", + id); + } + + } +#endif /* USE_JPWL */ + + if (id >> 8 != 0xff) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); + return 0; + } + e = j2k_dec_mstab_lookup(id); + /* Check if the marker is known*/ + if (!(j2k->state & e->states)) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); + return 0; + } + /* Check if the decoding is limited to the main header*/ + if (e->id == J2K_MS_SOT && j2k->cp->limit_decoding == LIMIT_TO_MAIN_HEADER) { + opj_event_msg(cinfo, EVT_INFO, "Main Header decoded.\n"); + return image; + } + + if (e->handler) { + (*e->handler)(j2k); + } + if (j2k->state & J2K_STATE_ERR) + return NULL; + + if (j2k->state == J2K_STATE_MT) { + break; + } + if (j2k->state == J2K_STATE_NEOC) { + break; + } + } + if (j2k->state == J2K_STATE_NEOC) { + j2k_read_eoc(j2k); + } + + if (j2k->state != J2K_STATE_MT) { + opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + } + return image; +} + +/* +* Read a JPT-stream and decode file +* +*/ +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + opj_image_t *image = NULL; + opj_jpt_msg_header_t header; + int position; + opj_common_ptr cinfo = j2k->cinfo; + + OPJ_ARG_NOT_USED(cstr_info); + + j2k->cio = cio; + + /* create an empty image */ + image = opj_image_create0(); + j2k->image = image; + + j2k->state = J2K_STATE_MHSOC; + + /* Initialize the header */ + jpt_init_msg_header(&header); + /* Read the first header of the message */ + jpt_read_msg_header(cinfo, cio, &header); + + position = cio_tell(cio); + if (header.Class_Id != 6) { /* 6 : Main header data-bin message */ + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Main header first [class_Id %d] !\n", header.Class_Id); + return 0; + } + + for (;;) { + opj_dec_mstabent_t *e = NULL; + int id; + + if (!cio_numbytesleft(cio)) { + j2k_read_eoc(j2k); + return image; + } + /* data-bin read -> need to read a new header */ + if ((unsigned int) (cio_tell(cio) - position) == header.Msg_length) { + jpt_read_msg_header(cinfo, cio, &header); + position = cio_tell(cio); + if (header.Class_Id != 4) { /* 4 : Tile data-bin message */ + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Tile info !\n"); + return 0; + } + } + + id = cio_read(cio, 2); + if (id >> 8 != 0xff) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); + return 0; + } + e = j2k_dec_mstab_lookup(id); + if (!(j2k->state & e->states)) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); + return 0; + } + if (e->handler) { + (*e->handler)(j2k); + } + if (j2k->state == J2K_STATE_MT) { + break; + } + if (j2k->state == J2K_STATE_NEOC) { + break; + } + } + if (j2k->state == J2K_STATE_NEOC) { + j2k_read_eoc(j2k); + } + + if (j2k->state != J2K_STATE_MT) { + opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + } + + return image; +} + +/* ----------------------------------------------------------------------- */ +/* J2K encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo) { + opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); + if(j2k) { + j2k->cinfo = cinfo; + } + return j2k; +} + +void j2k_destroy_compress(opj_j2k_t *j2k) { + int tileno; + + if(!j2k) return; + if(j2k->cp != NULL) { + opj_cp_t *cp = j2k->cp; + + if(cp->comment) { + opj_free(cp->comment); + } + if(cp->matrice) { + opj_free(cp->matrice); + } + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_free(cp->tcps[tileno].tccps); + } + opj_free(cp->tcps); + opj_free(cp); + } + + opj_free(j2k); +} + +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image) { + int i, j, tileno, numpocs_tile; + opj_cp_t *cp = NULL; + + if(!j2k || !parameters || ! image) { + return; + } + + /* create and initialize the coding parameters structure */ + cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); + + /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ + j2k->cp = cp; + + /* set default values for cp */ + cp->tw = 1; + cp->th = 1; + + /* + copy user encoding parameters + */ + cp->cinema = parameters->cp_cinema; + cp->max_comp_size = parameters->max_comp_size; + cp->rsiz = parameters->cp_rsiz; + cp->disto_alloc = parameters->cp_disto_alloc; + cp->fixed_alloc = parameters->cp_fixed_alloc; + cp->fixed_quality = parameters->cp_fixed_quality; + + /* mod fixed_quality */ + if(parameters->cp_matrice) { + size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(int); + cp->matrice = (int *) opj_malloc(array_size); + memcpy(cp->matrice, parameters->cp_matrice, array_size); + } + + /* tiles */ + cp->tdx = parameters->cp_tdx; + cp->tdy = parameters->cp_tdy; + + /* tile offset */ + cp->tx0 = parameters->cp_tx0; + cp->ty0 = parameters->cp_ty0; + + /* comment string */ + if(parameters->cp_comment) { + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); + if(cp->comment) { + strcpy(cp->comment, parameters->cp_comment); + } + } + + /* + calculate other encoding parameters + */ + + if (parameters->tile_size_on) { + cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + } else { + cp->tdx = image->x1 - cp->tx0; + cp->tdy = image->y1 - cp->ty0; + } + + if(parameters->tp_on){ + cp->tp_flag = parameters->tp_flag; + cp->tp_on = 1; + } + + cp->img_size = 0; + for(i=0;inumcomps ;i++){ + cp->img_size += (image->comps[i].w *image->comps[i].h * image->comps[i].prec); + } + + +#ifdef USE_JPWL + /* + calculate JPWL encoding parameters + */ + + if (parameters->jpwl_epc_on) { + int i; + + /* set JPWL on */ + cp->epc_on = OPJ_TRUE; + cp->info_on = OPJ_FALSE; /* no informative technique */ + + /* set EPB on */ + if ((parameters->jpwl_hprot_MH > 0) || (parameters->jpwl_hprot_TPH[0] > 0)) { + cp->epb_on = OPJ_TRUE; + + cp->hprot_MH = parameters->jpwl_hprot_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->hprot_TPH_tileno[i] = parameters->jpwl_hprot_TPH_tileno[i]; + cp->hprot_TPH[i] = parameters->jpwl_hprot_TPH[i]; + } + /* if tile specs are not specified, copy MH specs */ + if (cp->hprot_TPH[0] == -1) { + cp->hprot_TPH_tileno[0] = 0; + cp->hprot_TPH[0] = parameters->jpwl_hprot_MH; + } + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + cp->pprot_tileno[i] = parameters->jpwl_pprot_tileno[i]; + cp->pprot_packno[i] = parameters->jpwl_pprot_packno[i]; + cp->pprot[i] = parameters->jpwl_pprot[i]; + } + } + + /* set ESD writing */ + if ((parameters->jpwl_sens_size == 1) || (parameters->jpwl_sens_size == 2)) { + cp->esd_on = OPJ_TRUE; + + cp->sens_size = parameters->jpwl_sens_size; + cp->sens_addr = parameters->jpwl_sens_addr; + cp->sens_range = parameters->jpwl_sens_range; + + cp->sens_MH = parameters->jpwl_sens_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->sens_TPH_tileno[i] = parameters->jpwl_sens_TPH_tileno[i]; + cp->sens_TPH[i] = parameters->jpwl_sens_TPH[i]; + } + } + + /* always set RED writing to false: we are at the encoder */ + cp->red_on = OPJ_FALSE; + + } else { + cp->epc_on = OPJ_FALSE; + } +#endif /* USE_JPWL */ + + + /* initialize the mutiple tiles */ + /* ---------------------------- */ + cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + tcp->numlayers = parameters->tcp_numlayers; + for (j = 0; j < tcp->numlayers; j++) { + if(cp->cinema){ + if (cp->fixed_quality) { + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } + tcp->rates[j] = parameters->tcp_rates[j]; + }else{ + if (cp->fixed_quality) { /* add fixed_quality */ + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } else { + tcp->rates[j] = parameters->tcp_rates[j]; + } + } + } + tcp->csty = parameters->csty; + tcp->prg = parameters->prog_order; + tcp->mct = parameters->tcp_mct; + + numpocs_tile = 0; + tcp->POC = 0; + if (parameters->numpocs) { + /* initialisation of POC */ + tcp->POC = 1; + for (i = 0; i < parameters->numpocs; i++) { + if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { + opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; + tcp_poc->resno0 = parameters->POC[numpocs_tile].resno0; + tcp_poc->compno0 = parameters->POC[numpocs_tile].compno0; + tcp_poc->layno1 = parameters->POC[numpocs_tile].layno1; + tcp_poc->resno1 = parameters->POC[numpocs_tile].resno1; + tcp_poc->compno1 = parameters->POC[numpocs_tile].compno1; + tcp_poc->prg1 = parameters->POC[numpocs_tile].prg1; + tcp_poc->tile = parameters->POC[numpocs_tile].tile; + numpocs_tile++; + } + } + tcp->numpocs = numpocs_tile -1 ; + }else{ + tcp->numpocs = 0; + } + + tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + + for (i = 0; i < image->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->csty = parameters->csty & 0x01; /* 0 => one precinct || 1 => custom precinct */ + tccp->numresolutions = parameters->numresolution; + tccp->cblkw = int_floorlog2(parameters->cblockw_init); + tccp->cblkh = int_floorlog2(parameters->cblockh_init); + tccp->cblksty = parameters->mode; + tccp->qmfbid = parameters->irreversible ? 0 : 1; + tccp->qntsty = parameters->irreversible ? J2K_CCP_QNTSTY_SEQNT : J2K_CCP_QNTSTY_NOQNT; + tccp->numgbits = 2; + if (i == parameters->roi_compno) { + tccp->roishift = parameters->roi_shift; + } else { + tccp->roishift = 0; + } + + if(parameters->cp_cinema) + { + /*Precinct size for lowest frequency subband=128*/ + tccp->prcw[0] = 7; + tccp->prch[0] = 7; + /*Precinct size at all other resolutions = 256*/ + for (j = 1; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 8; + tccp->prch[j] = 8; + } + }else{ + if (parameters->csty & J2K_CCP_CSTY_PRT) { + int p = 0; + for (j = tccp->numresolutions - 1; j >= 0; j--) { + if (p < parameters->res_spec) { + + if (parameters->prcw_init[p] < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(parameters->prcw_init[p]); + } + + if (parameters->prch_init[p] < 1) { + tccp->prch[j] = 1; + }else { + tccp->prch[j] = int_floorlog2(parameters->prch_init[p]); + } + + } else { + int res_spec = parameters->res_spec; + int size_prcw = parameters->prcw_init[res_spec - 1] >> (p - (res_spec - 1)); + int size_prch = parameters->prch_init[res_spec - 1] >> (p - (res_spec - 1)); + + if (size_prcw < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(size_prcw); + } + + if (size_prch < 1) { + tccp->prch[j] = 1; + } else { + tccp->prch[j] = int_floorlog2(size_prch); + } + } + p++; + /*printf("\nsize precinct for level %d : %d,%d\n", j,tccp->prcw[j], tccp->prch[j]); */ + } /*end for*/ + } else { + for (j = 0; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 15; + tccp->prch[j] = 15; + } + } + } + + dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec); + } + } +} + +opj_bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + int tileno, compno; + opj_cp_t *cp = NULL; + + opj_tcd_t *tcd = NULL; /* TCD component */ + + j2k->cio = cio; + j2k->image = image; + + cp = j2k->cp; + + /* INDEX >> */ + j2k->cstr_info = cstr_info; + if (cstr_info) { + int compno; + cstr_info->tile = (opj_tile_info_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tile_info_t)); + cstr_info->image_w = image->x1 - image->x0; + cstr_info->image_h = image->y1 - image->y0; + cstr_info->prog = (&cp->tcps[0])->prg; + cstr_info->tw = cp->tw; + cstr_info->th = cp->th; + cstr_info->tile_x = cp->tdx; /* new version parser */ + cstr_info->tile_y = cp->tdy; /* new version parser */ + cstr_info->tile_Ox = cp->tx0; /* new version parser */ + cstr_info->tile_Oy = cp->ty0; /* new version parser */ + cstr_info->numcomps = image->numcomps; + cstr_info->numlayers = (&cp->tcps[0])->numlayers; + cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); + for (compno=0; compno < image->numcomps; compno++) { + cstr_info->numdecompos[compno] = (&cp->tcps[0])->tccps->numresolutions - 1; + } + cstr_info->D_max = 0.0; /* ADD Marcela */ + cstr_info->main_head_start = cio_tell(cio); /* position of SOC */ + cstr_info->maxmarknum = 100; + cstr_info->marker = (opj_marker_info_t *) opj_malloc(cstr_info->maxmarknum * sizeof(opj_marker_info_t)); + cstr_info->marknum = 0; + } + /* << INDEX */ + + j2k_write_soc(j2k); + j2k_write_siz(j2k); + j2k_write_cod(j2k); + j2k_write_qcd(j2k); + + if(cp->cinema){ + for (compno = 1; compno < image->numcomps; compno++) { + j2k_write_coc(j2k, compno); + j2k_write_qcc(j2k, compno); + } + } + + for (compno = 0; compno < image->numcomps; compno++) { + opj_tcp_t *tcp = &cp->tcps[0]; + if (tcp->tccps[compno].roishift) + j2k_write_rgn(j2k, compno, 0); + } + if (cp->comment != NULL) { + j2k_write_com(j2k); + } + + j2k->totnum_tp = j2k_calculate_tp(cp,image->numcomps,image,j2k); + /* TLM Marker*/ + if(cp->cinema){ + j2k_write_tlm(j2k); + if (cp->cinema == CINEMA4K_24) { + j2k_write_poc(j2k); + } + } + + /* uncomment only for testing JPSEC marker writing */ + /* j2k_write_sec(j2k); */ + + /* INDEX >> */ + if(cstr_info) { + cstr_info->main_head_end = cio_tell(cio) - 1; + } + /* << INDEX */ + /**** Main Header ENDS here ***/ + + /* create the tile encoder */ + tcd = tcd_create(j2k->cinfo); + + /* encode each tile */ + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + int pino; + int tilepartno=0; + /* UniPG>> */ + int acc_pack_num = 0; + /* <tcps[tileno]; + opj_event_msg(j2k->cinfo, EVT_INFO, "tile number %d / %d\n", tileno + 1, cp->tw * cp->th); + + j2k->curtileno = tileno; + j2k->cur_tp_num = 0; + tcd->cur_totnum_tp = j2k->cur_totnum_tp[j2k->curtileno]; + /* initialisation before tile encoding */ + if (tileno == 0) { + tcd_malloc_encode(tcd, image, cp, j2k->curtileno); + } else { + tcd_init_encode(tcd, image, cp, j2k->curtileno); + } + + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[j2k->curtileno].start_pos = cio_tell(cio) + j2k->pos_correction; + cstr_info->tile[j2k->curtileno].maxmarknum = 10; + cstr_info->tile[j2k->curtileno].marker = (opj_marker_info_t *) opj_malloc(cstr_info->tile[j2k->curtileno].maxmarknum * sizeof(opj_marker_info_t)); + cstr_info->tile[j2k->curtileno].marknum = 0; + } + /* << INDEX */ + + for(pino = 0; pino <= tcp->numpocs; pino++) { + int tot_num_tp; + tcd->cur_pino=pino; + + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp(cp,pino,tileno); + tcd->tp_pos = cp->tp_pos; + + for(tilepartno = 0; tilepartno < tot_num_tp ; tilepartno++){ + j2k->tp_num = tilepartno; + /* INDEX >> */ + if(cstr_info) + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pos = + cio_tell(cio) + j2k->pos_correction; + /* << INDEX */ + j2k_write_sot(j2k); + + if(j2k->cur_tp_num == 0 && cp->cinema == 0){ + for (compno = 1; compno < image->numcomps; compno++) { + j2k_write_coc(j2k, compno); + j2k_write_qcc(j2k, compno); + } + if (cp->tcps[tileno].numpocs) { + j2k_write_poc(j2k); + } + } + + /* INDEX >> */ + if(cstr_info) + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = + cio_tell(cio) + j2k->pos_correction + 1; + /* << INDEX */ + + j2k_write_sod(j2k, tcd); + + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_pos = + cio_tell(cio) + j2k->pos_correction - 1; + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pack = + acc_pack_num; + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_numpacks = + cstr_info->packno - acc_pack_num; + acc_pack_num = cstr_info->packno; + } + /* << INDEX */ + + j2k->cur_tp_num++; + } + } + if(cstr_info) { + cstr_info->tile[j2k->curtileno].end_pos = cio_tell(cio) + j2k->pos_correction - 1; + } + + + /* + if (tile->PPT) { // BAD PPT !!! + FILE *PPT_file; + int i; + PPT_file=fopen("PPT","rb"); + fprintf(stderr,"%c%c%c%c",255,97,tile->len_ppt/256,tile->len_ppt%256); + for (i=0;ilen_ppt;i++) { + unsigned char elmt; + fread(&elmt, 1, 1, PPT_file); + fwrite(&elmt,1,1,f); + } + fclose(PPT_file); + unlink("PPT"); + } + */ + + } + + /* destroy the tile encoder */ + tcd_free_encode(tcd); + tcd_destroy(tcd); + + opj_free(j2k->cur_totnum_tp); + + j2k_write_eoc(j2k); + + if(cstr_info) { + cstr_info->codestream_size = cio_tell(cio) + j2k->pos_correction; + /* UniPG>> */ + /* The following adjustment is done to adjust the codestream size */ + /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ + /* the first bunch of bytes is not in the codestream */ + cstr_info->codestream_size -= cstr_info->main_head_start; + /* <epc_on) { + + /* encode according to JPWL */ + jpwl_encode(j2k, cio, image); + + } +#endif /* USE_JPWL */ + + return OPJ_TRUE; +} + +static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) { + + if (!cstr_info) + return; + + /* expand the list? */ + if ((cstr_info->marknum + 1) > cstr_info->maxmarknum) { + cstr_info->maxmarknum = 100 + (int) ((float) cstr_info->maxmarknum * 1.0F); + cstr_info->marker = (opj_marker_info_t*)opj_realloc(cstr_info->marker, cstr_info->maxmarknum); + } + + /* add the marker */ + cstr_info->marker[cstr_info->marknum].type = type; + cstr_info->marker[cstr_info->marknum].pos = pos; + cstr_info->marker[cstr_info->marknum].len = len; + cstr_info->marknum++; + +} + +static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) { + + opj_marker_info_t *marker; + + if (!cstr_info) + return; + + /* expand the list? */ + if ((cstr_info->tile[tileno].marknum + 1) > cstr_info->tile[tileno].maxmarknum) { + cstr_info->tile[tileno].maxmarknum = 100 + (int) ((float) cstr_info->tile[tileno].maxmarknum * 1.0F); + cstr_info->tile[tileno].marker = (opj_marker_info_t*)opj_realloc(cstr_info->tile[tileno].marker, cstr_info->maxmarknum); + } + + marker = &(cstr_info->tile[tileno].marker[cstr_info->tile[tileno].marknum]); + + /* add the marker */ + marker->type = type; + marker->pos = pos; + marker->len = len; + cstr_info->tile[tileno].marknum++; +} diff --git a/openjpeg-dotnet/libopenjpeg/j2k.h b/openjpeg-dotnet/libopenjpeg/j2k.h new file mode 100644 index 0000000..6338c29 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/j2k.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __J2K_H +#define __J2K_H +/** +@file j2k.h +@brief The JPEG-2000 Codestream Reader/Writer (J2K) + +The functions in J2K.C have for goal to read/write the several parts of the codestream: markers and data. +*/ + +/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ +/*@{*/ + +#define J2K_CP_CSTY_PRT 0x01 +#define J2K_CP_CSTY_SOP 0x02 +#define J2K_CP_CSTY_EPH 0x04 +#define J2K_CCP_CSTY_PRT 0x01 +#define J2K_CCP_CBLKSTY_LAZY 0x01 /**< Selective arithmetic coding bypass */ +#define J2K_CCP_CBLKSTY_RESET 0x02 /**< Reset context probabilities on coding pass boundaries */ +#define J2K_CCP_CBLKSTY_TERMALL 0x04 /**< Termination on each coding pass */ +#define J2K_CCP_CBLKSTY_VSC 0x08 /**< Vertically stripe causal context */ +#define J2K_CCP_CBLKSTY_PTERM 0x10 /**< Predictable termination */ +#define J2K_CCP_CBLKSTY_SEGSYM 0x20 /**< Segmentation symbols are used */ +#define J2K_CCP_QNTSTY_NOQNT 0 +#define J2K_CCP_QNTSTY_SIQNT 1 +#define J2K_CCP_QNTSTY_SEQNT 2 + +/* ----------------------------------------------------------------------- */ + +#define J2K_MS_SOC 0xff4f /**< SOC marker value */ +#define J2K_MS_SOT 0xff90 /**< SOT marker value */ +#define J2K_MS_SOD 0xff93 /**< SOD marker value */ +#define J2K_MS_EOC 0xffd9 /**< EOC marker value */ +#define J2K_MS_SIZ 0xff51 /**< SIZ marker value */ +#define J2K_MS_COD 0xff52 /**< COD marker value */ +#define J2K_MS_COC 0xff53 /**< COC marker value */ +#define J2K_MS_RGN 0xff5e /**< RGN marker value */ +#define J2K_MS_QCD 0xff5c /**< QCD marker value */ +#define J2K_MS_QCC 0xff5d /**< QCC marker value */ +#define J2K_MS_POC 0xff5f /**< POC marker value */ +#define J2K_MS_TLM 0xff55 /**< TLM marker value */ +#define J2K_MS_PLM 0xff57 /**< PLM marker value */ +#define J2K_MS_PLT 0xff58 /**< PLT marker value */ +#define J2K_MS_PPM 0xff60 /**< PPM marker value */ +#define J2K_MS_PPT 0xff61 /**< PPT marker value */ +#define J2K_MS_SOP 0xff91 /**< SOP marker value */ +#define J2K_MS_EPH 0xff92 /**< EPH marker value */ +#define J2K_MS_CRG 0xff63 /**< CRG marker value */ +#define J2K_MS_COM 0xff64 /**< COM marker value */ +/* UniPG>> */ +#ifdef USE_JPWL +#define J2K_MS_EPC 0xff68 /**< EPC marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_EPB 0xff66 /**< EPB marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_ESD 0xff67 /**< ESD marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_RED 0xff69 /**< RED marker value (Part 11: JPEG 2000 for Wireless) */ +#endif /* USE_JPWL */ +#ifdef USE_JPSEC +#define J2K_MS_SEC 0xff65 /**< SEC marker value (Part 8: Secure JPEG 2000) */ +#define J2K_MS_INSEC 0xff94 /**< INSEC marker value (Part 8: Secure JPEG 2000) */ +#endif /* USE_JPSEC */ +/* < there was a PPT marker for the present tile */ + int ppt; + /** used in case of multiple marker PPT (number of info already stored) */ + int ppt_store; + /** ppmbug1 */ + int ppt_len; + /** add fixed_quality */ + float distoratio[100]; + /** tile-component coding parameters */ + opj_tccp_t *tccps; +} opj_tcp_t; + +/** +Coding parameters +*/ +typedef struct opj_cp { + /** Digital cinema profile*/ + OPJ_CINEMA_MODE cinema; + /** Maximum rate for each component. If == 0, component size limitation is not considered */ + int max_comp_size; + /** Size of the image in bits*/ + int img_size; + /** Rsiz*/ + OPJ_RSIZ_CAPABILITIES rsiz; + /** Enabling Tile part generation*/ + char tp_on; + /** Flag determining tile part generation*/ + char tp_flag; + /** Position of tile part flag in progression order*/ + int tp_pos; + /** allocation by rate/distortion */ + int disto_alloc; + /** allocation by fixed layer */ + int fixed_alloc; + /** add fixed_quality */ + int fixed_quality; + /** if != 0, then original dimension divided by 2^(reduce); if == 0 or not used, image is decoded to the full resolution */ + int reduce; + /** if != 0, then only the first "layer" layers are decoded; if == 0 or not used, all the quality layers are decoded */ + int layer; + /** if == NO_LIMITATION, decode entire codestream; if == LIMIT_TO_MAIN_HEADER then only decode the main header */ + OPJ_LIMIT_DECODING limit_decoding; + /** XTOsiz */ + int tx0; + /** YTOsiz */ + int ty0; + /** XTsiz */ + int tdx; + /** YTsiz */ + int tdy; + /** comment for coding */ + char *comment; + /** number of tiles in width */ + int tw; + /** number of tiles in heigth */ + int th; + /** ID number of the tiles present in the codestream */ + int *tileno; + /** size of the vector tileno */ + int tileno_size; + /** packet header store there for futur use in t2_decode_packet */ + unsigned char *ppm_data; + /** pointer remaining on the first byte of the first header if ppm is used */ + unsigned char *ppm_data_first; + /** if ppm == 1 --> there was a PPM marker for the present tile */ + int ppm; + /** use in case of multiple marker PPM (number of info already store) */ + int ppm_store; + /** use in case of multiple marker PPM (case on non-finished previous info) */ + int ppm_previous; + /** ppmbug1 */ + int ppm_len; + /** tile coding parameters */ + opj_tcp_t *tcps; + /** fixed layer */ + int *matrice; +/* UniPG>> */ +#ifdef USE_JPWL + /** enables writing of EPC in MH, thus activating JPWL */ + opj_bool epc_on; + /** enables writing of EPB, in case of activated JPWL */ + opj_bool epb_on; + /** enables writing of ESD, in case of activated JPWL */ + opj_bool esd_on; + /** enables writing of informative techniques of ESD, in case of activated JPWL */ + opj_bool info_on; + /** enables writing of RED, in case of activated JPWL */ + opj_bool red_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int hprot_MH; + /** tile number of header protection specification (>=0) */ + int hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0/2/4 bytes) */ + int sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int sens_addr; + /** sensitivity range (0-3) */ + int sens_range; + /** sensitivity method for MH (-1,0-7) */ + int sens_MH; + /** tile number of sensitivity specification (>=0) */ + int sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1,0-7) */ + int sens_TPH[JPWL_MAX_NO_TILESPECS]; + /** enables JPWL correction at the decoder */ + opj_bool correct; + /** expected number of components at the decoder */ + int exp_comps; + /** maximum number of tiles at the decoder */ + int max_tiles; +#endif /* USE_JPWL */ +/* <cp. +@param j2k J2K decompressor handle +@param parameters decompression parameters +*/ +void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 codestream +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Decode an image form a JPT-stream (JPEG 2000, JPIP) +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a J2K compression structure +@param cinfo Codec context info +@return Returns a handle to a J2K compressor if successful, returns NULL otherwise +*/ +opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo); +/** +Destroy a J2K compressor handle +@param j2k J2K compressor handle to destroy +*/ +void j2k_destroy_compress(opj_j2k_t *j2k); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in j2k->cp. +@param j2k J2K compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image); +/** +Converts an enum type progression order to string type +*/ +char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); +/** +Encode an image into a JPEG-2000 codestream +@param j2k J2K compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +opj_bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J2K_H */ diff --git a/openjpeg-dotnet/libopenjpeg/j2k_lib.c b/openjpeg-dotnet/libopenjpeg/j2k_lib.c new file mode 100644 index 0000000..a66e31e --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/j2k_lib.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif /* _WIN32 */ +#include "opj_includes.h" + +double opj_clock(void) { +#ifdef _WIN32 + /* _WIN32: use QueryPerformance (very accurate) */ + LARGE_INTEGER freq , t ; + /* freq is the clock speed of the CPU */ + QueryPerformanceFrequency(&freq) ; + /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ + /* t is the high resolution performance counter (see MSDN) */ + QueryPerformanceCounter ( & t ) ; + return ( t.QuadPart /(double) freq.QuadPart ) ; +#else + /* Unix or Linux: use resource usage */ + struct rusage t; + double procTime; + /* (1) Get the rusage data structure at this moment (man getrusage) */ + getrusage(0,&t); + /* (2) What is the elapsed time ? - CPU time = User time + System time */ + /* (2a) Get the seconds */ + procTime = t.ru_utime.tv_sec + t.ru_stime.tv_sec; + /* (2b) More precisely! Get the microseconds part ! */ + return ( procTime + (t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; +#endif +} + diff --git a/openjpeg-dotnet/libopenjpeg/j2k_lib.h b/openjpeg-dotnet/libopenjpeg/j2k_lib.h new file mode 100644 index 0000000..5f3406e --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/j2k_lib.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __J2K_LIB_H +#define __J2K_LIB_H +/** +@file j2k_lib.h +@brief Internal functions + +The functions in J2K_LIB.C are internal utilities mainly used for timing. +*/ + +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Difference in successive opj_clock() calls tells you the elapsed time +@return Returns time in seconds +*/ +double opj_clock(void); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J2K_LIB_H */ + diff --git a/openjpeg-dotnet/libopenjpeg/jp2.c b/openjpeg-dotnet/libopenjpeg/jp2.c new file mode 100644 index 0000000..5ae114c --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jp2.c @@ -0,0 +1,1210 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#include "opj_includes.h" + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Read box headers +@param cinfo Codec context info +@param cio Input stream +@param box +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box); +/*static void jp2_write_url(opj_cio_t *cio, char *Idx_file);*/ +/** +Read the IHDR box - Image Header box +@param jp2 JP2 handle +@param cio Input buffer stream +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); +static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); +static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); +static opj_bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); +static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Write the FTYP box - File type box +@param jp2 JP2 handle +@param cio Output buffer stream +*/ +static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Read the FTYP box - File type box +@param jp2 JP2 handle +@param cio Input buffer stream +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); +static int jp2_write_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +static opj_bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_codestream_length, unsigned int *j2k_codestream_offset); +static void jp2_write_jp(opj_cio_t *cio); +/** +Read the JP box - JPEG 2000 signature +@param jp2 JP2 handle +@param cio Input buffer stream +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Decode the structure of a JP2 file +@param jp2 JP2 handle +@param cio Input buffer stream +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_struct(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_color_t *color); +/** +Apply collected palette data +@param color Collector for profile, cdef and pclr data +@param image +*/ +static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image, opj_common_ptr cinfo); +/** +Collect palette data +@param jp2 JP2 handle +@param cio Input buffer stream +@param box +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color); +/** +Collect component mapping data +@param jp2 JP2 handle +@param cio Input buffer stream +@param box +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color); +/** +Collect colour specification data +@param jp2 JP2 handle +@param cio Input buffer stream +@param box +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static opj_bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color); +/** +Write file Index (superbox) +@param[in] offset_jp2c offset of jp2c box +@param[in] length_jp2c length of jp2c box +@param[in] offset_idx offset of cidx box +@param[in] length_idx length of cidx box +@param[in] cio file output handle +@return length of fidx box +*/ +static int write_fidx( int offset_jp2c, int length_jp2c, int offset_idx, int length_idx, opj_cio_t *cio); +/** +Write index Finder box +@param[in] offset offset of fidx box +@param[in] length length of fidx box +@param[in] cio file output handle +*/ +static void write_iptr( int offset, int length, opj_cio_t *cio); +/** +Write proxy box +@param[in] offset_jp2c offset of jp2c box +@param[in] length_jp2c length of jp2c box +@param[in] offset_idx offset of cidx box +@param[in] length_idx length of cidx box +@param[in] cio file output handle +*/ +static void write_prxy( int offset_jp2c, int length_jp2c, int offset_idx, int length_idx, opj_cio_t *cio); +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +static opj_bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box) { + box->init_pos = cio_tell(cio); + box->length = cio_read(cio, 4); + box->type = cio_read(cio, 4); + if (box->length == 1) { + if (cio_read(cio, 4) != 0) { + opj_event_msg(cinfo, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return OPJ_FALSE; + } + box->length = cio_read(cio, 4); + if (box->length == 0) + box->length = cio_numbytesleft(cio) + 12; + } + else if (box->length == 0) { + box->length = cio_numbytesleft(cio) + 8; + } + + return OPJ_TRUE; +} + +#if 0 +static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_URL, 4); /* DBTL */ + cio_write(cio, 0, 1); /* VERS */ + cio_write(cio, 0, 3); /* FLAG */ + + if(Idx_file) { + for (i = 0; i < strlen(Idx_file); i++) { + cio_write(cio, Idx_file[i], 1); + } + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} +#endif + +static opj_bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + if (JP2_IHDR != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected IHDR Marker\n"); + return OPJ_FALSE; + } + + jp2->h = cio_read(cio, 4); /* HEIGHT */ + jp2->w = cio_read(cio, 4); /* WIDTH */ + jp2->numcomps = cio_read(cio, 2); /* NC */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + + jp2->bpc = cio_read(cio, 1); /* BPC */ + + jp2->C = cio_read(cio, 1); /* C */ + jp2->UnkC = cio_read(cio, 1); /* UnkC */ + jp2->IPR = cio_read(cio, 1); /* IPR */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with IHDR Box\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_IHDR, 4); /* IHDR */ + + cio_write(cio, jp2->h, 4); /* HEIGHT */ + cio_write(cio, jp2->w, 4); /* WIDTH */ + cio_write(cio, jp2->numcomps, 2); /* NC */ + + cio_write(cio, jp2->bpc, 1); /* BPC */ + + cio_write(cio, jp2->C, 1); /* C : Always 7 */ + cio_write(cio, jp2->UnkC, 1); /* UnkC, colorspace unknown */ + cio_write(cio, jp2->IPR, 1); /* IPR, no intellectual property */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_BPCC, 4); /* BPCC */ + + for (i = 0; i < jp2->numcomps; i++) { + cio_write(cio, jp2->comps[i].bpcc, 1); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + + +static opj_bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { + unsigned int i; + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + if (JP2_BPCC != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected BPCC Marker\n"); + return OPJ_FALSE; + } + + for (i = 0; i < jp2->numcomps; i++) { + jp2->comps[i].bpcc = cio_read(cio, 1); + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with BPCC Box\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_COLR, 4); /* COLR */ + + cio_write(cio, jp2->meth, 1); /* METH */ + cio_write(cio, jp2->precedence, 1); /* PRECEDENCE */ + cio_write(cio, jp2->approx, 1); /* APPROX */ + + if(jp2->meth == 2) + jp2->enumcs = 0; + + cio_write(cio, jp2->enumcs, 4); /* EnumCS */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static void jp2_free_pclr(opj_jp2_color_t *color) +{ + opj_free(color->jp2_pclr->channel_sign); + opj_free(color->jp2_pclr->channel_size); + opj_free(color->jp2_pclr->entries); + + if(color->jp2_pclr->cmap) opj_free(color->jp2_pclr->cmap); + + opj_free(color->jp2_pclr); color->jp2_pclr = NULL; +} + +static void free_color_data(opj_jp2_color_t *color) +{ + if(color->jp2_pclr) + { + jp2_free_pclr(color); + } + if(color->jp2_cdef) + { + if(color->jp2_cdef->info) opj_free(color->jp2_cdef->info); + opj_free(color->jp2_cdef); + } + if(color->icc_profile_buf) opj_free(color->icc_profile_buf); +} + +static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image, opj_common_ptr cinfo) +{ + opj_image_comp_t *old_comps, *new_comps; + unsigned char *channel_size, *channel_sign; + unsigned int *entries; + opj_jp2_cmap_comp_t *cmap; + int *src, *dst; + unsigned int j, max; + unsigned short i, nr_channels, cmp, pcol; + int k, top_k; + + channel_size = color->jp2_pclr->channel_size; + channel_sign = color->jp2_pclr->channel_sign; + entries = color->jp2_pclr->entries; + cmap = color->jp2_pclr->cmap; + nr_channels = color->jp2_pclr->nr_channels; + + old_comps = image->comps; + new_comps = (opj_image_comp_t*) + opj_malloc(nr_channels * sizeof(opj_image_comp_t)); + + for(i = 0; i < nr_channels; ++i) + { + pcol = cmap[i].pcol; cmp = cmap[i].cmp; + + if( pcol < nr_channels ) + new_comps[pcol] = old_comps[cmp]; + else + { + opj_event_msg(cinfo, EVT_ERROR, "Error with pcol value %d (max: %d). skipping\n", pcol, nr_channels); + continue; + } + + if(cmap[i].mtyp == 0) /* Direct use */ + { + old_comps[cmp].data = NULL; continue; + } +/* Palette mapping: */ + new_comps[pcol].data = (int*) + opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(int)); + new_comps[pcol].prec = channel_size[i]; + new_comps[pcol].sgnd = channel_sign[i]; + } + top_k = color->jp2_pclr->nr_entries - 1; + + for(i = 0; i < nr_channels; ++i) + { +/* Direct use: */ + if(cmap[i].mtyp == 0) continue; + +/* Palette mapping: */ + cmp = cmap[i].cmp; pcol = cmap[i].pcol; + src = old_comps[cmp].data; + dst = new_comps[pcol].data; + max = new_comps[pcol].w * new_comps[pcol].h; + + for(j = 0; j < max; ++j) + { +/* The index */ + if((k = src[j]) < 0) k = 0; else if(k > top_k) k = top_k; +/* The colour */ + dst[j] = entries[k * nr_channels + pcol]; + } + } + max = image->numcomps; + for(i = 0; i < max; ++i) + { + if(old_comps[i].data) opj_free(old_comps[i].data); + } + opj_free(old_comps); + image->comps = new_comps; + image->numcomps = nr_channels; + + jp2_free_pclr(color); + +}/* apply_pclr() */ + +static opj_bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + opj_jp2_pclr_t *jp2_pclr; + unsigned char *channel_size, *channel_sign; + unsigned int *entries; + unsigned short nr_entries, nr_channels; + unsigned short i, j; + unsigned char uc; + + OPJ_ARG_NOT_USED(box); + OPJ_ARG_NOT_USED(jp2); + +/* Part 1, I.5.3.4: 'There shall be at most one Palette box inside + * a JP2 Header box' : +*/ + if(color->jp2_pclr) return OPJ_FALSE; + + nr_entries = (unsigned short)cio_read(cio, 2); /* NE */ + nr_channels = (unsigned short)cio_read(cio, 1);/* NPC */ + + entries = (unsigned int*) + opj_malloc(nr_channels * nr_entries * sizeof(unsigned int)); + channel_size = (unsigned char*)opj_malloc(nr_channels); + channel_sign = (unsigned char*)opj_malloc(nr_channels); + + jp2_pclr = (opj_jp2_pclr_t*)opj_malloc(sizeof(opj_jp2_pclr_t)); + jp2_pclr->channel_sign = channel_sign; + jp2_pclr->channel_size = channel_size; + jp2_pclr->entries = entries; + jp2_pclr->nr_entries = nr_entries; + jp2_pclr->nr_channels = nr_channels; + jp2_pclr->cmap = NULL; + + color->jp2_pclr = jp2_pclr; + + for(i = 0; i < nr_channels; ++i) + { + uc = cio_read(cio, 1); /* Bi */ + channel_size[i] = (uc & 0x7f) + 1; + channel_sign[i] = (uc & 0x80)?1:0; + } + + for(j = 0; j < nr_entries; ++j) + { + for(i = 0; i < nr_channels; ++i) + { +/* Cji */ + *entries++ = cio_read(cio, channel_size[i]>>3); + } + } + + return OPJ_TRUE; +}/* jp2_read_pclr() */ + +static opj_bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + opj_jp2_cmap_comp_t *cmap; + unsigned short i, nr_channels; + + OPJ_ARG_NOT_USED(box); + OPJ_ARG_NOT_USED(jp2); + +/* Need nr_channels: */ + if(color->jp2_pclr == NULL) return OPJ_FALSE; + +/* Part 1, I.5.3.5: 'There shall be at most one Component Mapping box + * inside a JP2 Header box' : +*/ + if(color->jp2_pclr->cmap) return OPJ_FALSE; + + nr_channels = color->jp2_pclr->nr_channels; + cmap = (opj_jp2_cmap_comp_t*) + opj_malloc(nr_channels * sizeof(opj_jp2_cmap_comp_t)); + + for(i = 0; i < nr_channels; ++i) + { + cmap[i].cmp = (unsigned short)cio_read(cio, 2); + cmap[i].mtyp = cio_read(cio, 1); + cmap[i].pcol = cio_read(cio, 1); + + } + color->jp2_pclr->cmap = cmap; + + return OPJ_TRUE; +}/* jp2_read_cmap() */ + +static void jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color) +{ + opj_jp2_cdef_info_t *info; + int color_space; + unsigned short i, n, cn, typ, asoc, acn; + + color_space = image->color_space; + info = color->jp2_cdef->info; + n = color->jp2_cdef->n; + + for(i = 0; i < n; ++i) + { +/* WATCH: acn = asoc - 1 ! */ + if((asoc = info[i].asoc) == 0) continue; + + cn = info[i].cn; typ = info[i].typ; acn = asoc - 1; + + if(cn != acn) + { + opj_image_comp_t saved; + + memcpy(&saved, &image->comps[cn], sizeof(opj_image_comp_t)); + memcpy(&image->comps[cn], &image->comps[acn], sizeof(opj_image_comp_t)); + memcpy(&image->comps[acn], &saved, sizeof(opj_image_comp_t)); + + info[i].asoc = cn + 1; + info[acn].asoc = info[acn].cn + 1; + } + } + if(color->jp2_cdef->info) opj_free(color->jp2_cdef->info); + + opj_free(color->jp2_cdef); color->jp2_cdef = NULL; + +}/* jp2_apply_cdef() */ + +static opj_bool jp2_read_cdef(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + opj_jp2_cdef_info_t *info; + unsigned short i, n; + + OPJ_ARG_NOT_USED(box); + OPJ_ARG_NOT_USED(jp2); + +/* Part 1, I.5.3.6: 'The shall be at most one Channel Definition box + * inside a JP2 Header box.' +*/ + if(color->jp2_cdef) return OPJ_FALSE; + + if((n = (unsigned short)cio_read(cio, 2)) == 0) return OPJ_FALSE; /* szukw000: FIXME */ + + info = (opj_jp2_cdef_info_t*) + opj_malloc(n * sizeof(opj_jp2_cdef_info_t)); + + color->jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); + color->jp2_cdef->info = info; + color->jp2_cdef->n = n; + + for(i = 0; i < n; ++i) + { + info[i].cn = (unsigned short)cio_read(cio, 2); + info[i].typ = (unsigned short)cio_read(cio, 2); + info[i].asoc = (unsigned short)cio_read(cio, 2); + + } + return OPJ_TRUE; +}/* jp2_read_cdef() */ + +static opj_bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + int skip_len; + opj_common_ptr cinfo; + +/* Part 1, I.5.3.3 : 'A conforming JP2 reader shall ignore all Colour + * Specification boxes after the first.' +*/ + if(color->jp2_has_colr) return OPJ_FALSE; + + cinfo = jp2->cinfo; + + jp2->meth = cio_read(cio, 1); /* METH */ + jp2->precedence = cio_read(cio, 1); /* PRECEDENCE */ + jp2->approx = cio_read(cio, 1); /* APPROX */ + + if (jp2->meth == 1) + { + jp2->enumcs = cio_read(cio, 4); /* EnumCS */ + } + else + if (jp2->meth == 2) + { +/* skip PROFILE */ + skip_len = box->init_pos + box->length - cio_tell(cio); + if (skip_len < 0) + { + opj_event_msg(cinfo, EVT_ERROR, "Error with COLR box size\n"); + return OPJ_FALSE; + } + if(skip_len > 0) + { + unsigned char *start; + + start = cio_getbp(cio); + color->icc_profile_buf = (unsigned char*)opj_malloc(skip_len); + color->icc_profile_len = skip_len; + + cio_skip(cio, box->init_pos + box->length - cio_tell(cio)); + + memcpy(color->icc_profile_buf, start, skip_len); + } + } + + if (cio_tell(cio) - box->init_pos != box->length) + { + opj_event_msg(cinfo, EVT_ERROR, "Error with COLR Box\n"); + return OPJ_FALSE; + } + color->jp2_has_colr = 1; + + return OPJ_TRUE; +}/* jp2_read_colr() */ + +opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color) +{ + opj_jp2_box_t box; + int jp2h_end; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + do + { + if (JP2_JP2H != box.type) + { + if (box.type == JP2_JP2C) + { + opj_event_msg(cinfo, EVT_ERROR, "Expected JP2H Marker\n"); + return OPJ_FALSE; + } + cio_skip(cio, box.length - 8); + + if(cio->bp >= cio->end) return OPJ_FALSE; + + jp2_read_boxhdr(cinfo, cio, &box); + } + } while(JP2_JP2H != box.type); + + if (!jp2_read_ihdr(jp2, cio)) + return OPJ_FALSE; + jp2h_end = box.init_pos + box.length; + + if (jp2->bpc == 255) + { + if (!jp2_read_bpcc(jp2, cio)) + return OPJ_FALSE; + } + jp2_read_boxhdr(cinfo, cio, &box); + + while(cio_tell(cio) < jp2h_end) + { + if(box.type == JP2_COLR) + { + if( !jp2_read_colr(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + if(box.type == JP2_CDEF && !jp2->ignore_pclr_cmap_cdef) + { + if( !jp2_read_cdef(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + if(box.type == JP2_PCLR && !jp2->ignore_pclr_cmap_cdef) + { + if( !jp2_read_pclr(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + if(box.type == JP2_CMAP && !jp2->ignore_pclr_cmap_cdef) + { + if( !jp2_read_cmap(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + jp2_read_boxhdr(cinfo, cio, &box); + + }/* while(cio_tell(cio) < box_end) */ + + cio_seek(cio, jp2h_end); + +/* Part 1, I.5.3.3 : 'must contain at least one' */ + return (color->jp2_has_colr == 1); + +}/* jp2_read_jp2h() */ + +opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, + opj_codestream_info_t *cstr_info) +{ + opj_common_ptr cinfo; + opj_image_t *image = NULL; + opj_jp2_color_t color; + + if(!jp2 || !cio) + { + return NULL; + } + memset(&color, 0, sizeof(opj_jp2_color_t)); + cinfo = jp2->cinfo; + +/* JP2 decoding */ + if(!jp2_read_struct(jp2, cio, &color)) + { + free_color_data(&color); + opj_event_msg(cinfo, EVT_ERROR, "Failed to decode jp2 structure\n"); + return NULL; + } + +/* J2K decoding */ + image = j2k_decode(jp2->j2k, cio, cstr_info); + + if(!image) + { + free_color_data(&color); + opj_event_msg(cinfo, EVT_ERROR, "Failed to decode J2K image\n"); + return NULL; + } + + if (!jp2->ignore_pclr_cmap_cdef){ + + /* Set Image Color Space */ + if (jp2->enumcs == 16) + image->color_space = CLRSPC_SRGB; + else if (jp2->enumcs == 17) + image->color_space = CLRSPC_GRAY; + else if (jp2->enumcs == 18) + image->color_space = CLRSPC_SYCC; + else + image->color_space = CLRSPC_UNKNOWN; + + if(color.jp2_cdef) + { + jp2_apply_cdef(image, &color); + } + if(color.jp2_pclr) + { +/* Part 1, I.5.3.4: Either both or none : */ + if( !color.jp2_pclr->cmap) + jp2_free_pclr(&color); + else + jp2_apply_pclr(&color, image, cinfo); + } + if(color.icc_profile_buf) + { + image->icc_profile_buf = color.icc_profile_buf; + color.icc_profile_buf = NULL; + image->icc_profile_len = color.icc_profile_len; + } + } + + return image; + +}/* opj_jp2_decode() */ + + +void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_JP2H, 4); /* JP2H */ + + jp2_write_ihdr(jp2, cio); + + if (jp2->bpc == 255) { + jp2_write_bpcc(jp2, cio); + } + jp2_write_colr(jp2, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_FTYP, 4); /* FTYP */ + + cio_write(cio, jp2->brand, 4); /* BR */ + cio_write(cio, jp2->minversion, 4); /* MinV */ + + for (i = 0; i < jp2->numcl; i++) { + cio_write(cio, jp2->cl[i], 4); /* CL */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { + int i; + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + + if (JP2_FTYP != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected FTYP Marker\n"); + return OPJ_FALSE; + } + + jp2->brand = cio_read(cio, 4); /* BR */ + jp2->minversion = cio_read(cio, 4); /* MinV */ + jp2->numcl = (box.length - 16) / 4; + jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int)); + + for (i = 0; i < (int)jp2->numcl; i++) { + jp2->cl[i] = cio_read(cio, 4); /* CLi */ + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with FTYP Box\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +static int jp2_write_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + unsigned int j2k_codestream_offset, j2k_codestream_length; + opj_jp2_box_t box; + + opj_j2k_t *j2k = jp2->j2k; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_JP2C, 4); /* JP2C */ + + /* J2K encoding */ + j2k_codestream_offset = cio_tell(cio); + if(!j2k_encode(j2k, cio, image, cstr_info)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Failed to encode image\n"); + return 0; + } + j2k_codestream_length = cio_tell(cio) - j2k_codestream_offset; + + jp2->j2k_codestream_offset = j2k_codestream_offset; + jp2->j2k_codestream_length = j2k_codestream_length; + + box.length = 8 + jp2->j2k_codestream_length; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); + + return box.length; +} + +static opj_bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_codestream_length, unsigned int *j2k_codestream_offset) { + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + do { + if(JP2_JP2C != box.type) { + cio_skip(cio, box.length - 8); + jp2_read_boxhdr(cinfo, cio, &box); + } + } while(JP2_JP2C != box.type); + + *j2k_codestream_offset = cio_tell(cio); + *j2k_codestream_length = box.length - 8; + + return OPJ_TRUE; +} + +static void jp2_write_jp(opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_JP, 4); /* JP2 signature */ + cio_write(cio, 0x0d0a870a, 4); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static opj_bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + if (JP2_JP != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected JP Marker\n"); + return OPJ_FALSE; + } + if (0x0d0a870a != cio_read(cio, 4)) { + opj_event_msg(cinfo, EVT_ERROR, "Error with JP Marker\n"); + return OPJ_FALSE; + } + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with JP Box size\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +static opj_bool jp2_read_struct(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_color_t *color) { + if (!jp2_read_jp(jp2, cio)) + return OPJ_FALSE; + if (!jp2_read_ftyp(jp2, cio)) + return OPJ_FALSE; + if (!jp2_read_jp2h(jp2, cio, color)) + return OPJ_FALSE; + if (!jp2_read_jp2c(jp2, cio, &jp2->j2k_codestream_length, &jp2->j2k_codestream_offset)) + return OPJ_FALSE; + + return OPJ_TRUE; +} + + +static int write_fidx( int offset_jp2c, int length_jp2c, int offset_idx, int length_idx, opj_cio_t *cio) +{ + int len, lenp; + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_FIDX, 4); /* IPTR */ + + write_prxy( offset_jp2c, length_jp2c, offset_idx, length_idx, cio); + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); + + return len; +} + +static void write_prxy( int offset_jp2c, int length_jp2c, int offset_idx, int length_idx, opj_cio_t *cio) +{ + int len, lenp; + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_PRXY, 4); /* IPTR */ + + cio_write( cio, offset_jp2c, 8); /* OOFF */ + cio_write( cio, length_jp2c, 4); /* OBH part 1 */ + cio_write( cio, JP2_JP2C, 4); /* OBH part 2 */ + + cio_write( cio, 1,1); /* NI */ + + cio_write( cio, offset_idx, 8); /* IOFF */ + cio_write( cio, length_idx, 4); /* IBH part 1 */ + cio_write( cio, JPIP_CIDX, 4); /* IBH part 2 */ + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); +} + +static void write_iptr( int offset, int length, opj_cio_t *cio) +{ + int len, lenp; + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_IPTR, 4); /* IPTR */ + + cio_write( cio, offset, 8); + cio_write( cio, length, 8); + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); +} + + +/* ----------------------------------------------------------------------- */ +/* JP2 decoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_jp2_t* jp2_create_decompress(opj_common_ptr cinfo) { + opj_jp2_t *jp2 = (opj_jp2_t*) opj_calloc(1, sizeof(opj_jp2_t)); + if(jp2) { + jp2->cinfo = cinfo; + /* create the J2K codec */ + jp2->j2k = j2k_create_decompress(cinfo); + if(jp2->j2k == NULL) { + jp2_destroy_decompress(jp2); + return NULL; + } + } + return jp2; +} + +void jp2_destroy_decompress(opj_jp2_t *jp2) { + if(jp2) { + /* destroy the J2K codec */ + j2k_destroy_decompress(jp2->j2k); + + if(jp2->comps) { + opj_free(jp2->comps); + } + if(jp2->cl) { + opj_free(jp2->cl); + } + opj_free(jp2); + } +} + +void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) { + /* setup the J2K codec */ + j2k_setup_decoder(jp2->j2k, parameters); + /* further JP2 initializations go here */ + jp2->ignore_pclr_cmap_cdef = parameters->flags & OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; +} + +/* ----------------------------------------------------------------------- */ +/* JP2 encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo) { + opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t)); + if(jp2) { + jp2->cinfo = cinfo; + /* create the J2K codec */ + jp2->j2k = j2k_create_compress(cinfo); + if(jp2->j2k == NULL) { + jp2_destroy_compress(jp2); + return NULL; + } + } + return jp2; +} + +void jp2_destroy_compress(opj_jp2_t *jp2) { + if(jp2) { + /* destroy the J2K codec */ + j2k_destroy_compress(jp2->j2k); + + if(jp2->comps) { + opj_free(jp2->comps); + } + if(jp2->cl) { + opj_free(jp2->cl); + } + opj_free(jp2); + } +} + +void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image) { + int i; + int depth_0, sign; + + if(!jp2 || !parameters || !image) + return; + + /* setup the J2K codec */ + /* ------------------- */ + + /* Check if number of components respects standard */ + if (image->numcomps < 1 || image->numcomps > 16384) { + opj_event_msg(jp2->cinfo, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); + return; + } + + j2k_setup_encoder(jp2->j2k, parameters, image); + + /* setup the JP2 codec */ + /* ------------------- */ + + /* Profile box */ + + jp2->brand = JP2_JP2; /* BR */ + jp2->minversion = 0; /* MinV */ + jp2->numcl = 1; + jp2->cl = (unsigned int*) opj_malloc(jp2->numcl * sizeof(unsigned int)); + jp2->cl[0] = JP2_JP2; /* CL0 : JP2 */ + + /* Image Header box */ + + jp2->numcomps = image->numcomps; /* NC */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + jp2->h = image->y1 - image->y0; /* HEIGHT */ + jp2->w = image->x1 - image->x0; /* WIDTH */ + /* BPC */ + depth_0 = image->comps[0].prec - 1; + sign = image->comps[0].sgnd; + jp2->bpc = depth_0 + (sign << 7); + for (i = 1; i < image->numcomps; i++) { + int depth = image->comps[i].prec - 1; + sign = image->comps[i].sgnd; + if (depth_0 != depth) + jp2->bpc = 255; + } + jp2->C = 7; /* C : Always 7 */ + jp2->UnkC = 0; /* UnkC, colorspace specified in colr box */ + jp2->IPR = 0; /* IPR, no intellectual property */ + + /* BitsPerComponent box */ + + for (i = 0; i < image->numcomps; i++) { + jp2->comps[i].bpcc = image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); + } + jp2->meth = 1; + if (image->color_space == 1) + jp2->enumcs = 16; /* sRGB as defined by IEC 61966-2.1 */ + else if (image->color_space == 2) + jp2->enumcs = 17; /* greyscale */ + else if (image->color_space == 3) + jp2->enumcs = 18; /* YUV */ + jp2->precedence = 0; /* PRECEDENCE */ + jp2->approx = 0; /* APPROX */ + + jp2->jpip_on = parameters->jpip_on; +} + +opj_bool opj_jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + + int pos_iptr, pos_cidx, pos_jp2c, len_jp2c, len_cidx, end_pos, pos_fidx, len_fidx; + pos_jp2c = pos_iptr = -1; /* remove a warning */ + + /* JP2 encoding */ + + /* JPEG 2000 Signature box */ + jp2_write_jp(cio); + /* File Type box */ + jp2_write_ftyp(jp2, cio); + /* JP2 Header box */ + jp2_write_jp2h(jp2, cio); + + if( jp2->jpip_on){ + pos_iptr = cio_tell( cio); + cio_skip( cio, 24); /* IPTR further ! */ + + pos_jp2c = cio_tell( cio); + } + + /* J2K encoding */ + if(!(len_jp2c = jp2_write_jp2c( jp2, cio, image, cstr_info))){ + opj_event_msg(jp2->cinfo, EVT_ERROR, "Failed to encode image\n"); + return OPJ_FALSE; + } + + if( jp2->jpip_on){ + pos_cidx = cio_tell( cio); + + len_cidx = write_cidx( pos_jp2c+8, cio, image, *cstr_info, len_jp2c-8); + + pos_fidx = cio_tell( cio); + len_fidx = write_fidx( pos_jp2c, len_jp2c, pos_cidx, len_cidx, cio); + + end_pos = cio_tell( cio); + + cio_seek( cio, pos_iptr); + write_iptr( pos_fidx, len_fidx, cio); + + cio_seek( cio, end_pos); + } + + return OPJ_TRUE; +} diff --git a/openjpeg-dotnet/libopenjpeg/jp2.h b/openjpeg-dotnet/libopenjpeg/jp2.h new file mode 100644 index 0000000..acb643c --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jp2.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __JP2_H +#define __JP2_H +/** +@file jp2.h +@brief The JPEG-2000 file format Reader/Writer (JP2) + +*/ + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +#define JPIP_JPIP 0x6a706970 + +#define JP2_JP 0x6a502020 /**< JPEG 2000 signature box */ +#define JP2_FTYP 0x66747970 /**< File type box */ +#define JP2_JP2H 0x6a703268 /**< JP2 header box */ +#define JP2_IHDR 0x69686472 /**< Image header box */ +#define JP2_COLR 0x636f6c72 /**< Colour specification box */ +#define JP2_JP2C 0x6a703263 /**< Contiguous codestream box */ +#define JP2_URL 0x75726c20 /**< URL box */ +#define JP2_DTBL 0x6474626c /**< Data Reference box */ +#define JP2_BPCC 0x62706363 /**< Bits per component box */ +#define JP2_JP2 0x6a703220 /**< File type fields */ +#define JP2_PCLR 0x70636c72 /**< Palette box */ +#define JP2_CMAP 0x636d6170 /**< Component Mapping box */ +#define JP2_CDEF 0x63646566 /**< Channel Definition box */ + +/* ----------------------------------------------------------------------- */ +/** +Channel description: channel index, type, assocation +*/ +typedef struct opj_jp2_cdef_info +{ + unsigned short cn, typ, asoc; +} opj_jp2_cdef_info_t; + +/** +Channel descriptions and number of descriptions +*/ +typedef struct opj_jp2_cdef +{ + opj_jp2_cdef_info_t *info; + unsigned short n; +} opj_jp2_cdef_t; + +/** +Component mappings: channel index, mapping type, palette index +*/ +typedef struct opj_jp2_cmap_comp +{ + unsigned short cmp; + unsigned char mtyp, pcol; +} opj_jp2_cmap_comp_t; + +/** +Palette data: table entries, palette columns +*/ +typedef struct opj_jp2_pclr +{ + unsigned int *entries; + unsigned char *channel_sign; + unsigned char *channel_size; + opj_jp2_cmap_comp_t *cmap; + unsigned short nr_entries, nr_channels; +} opj_jp2_pclr_t; + +/** +Collector for ICC profile, palette, component mapping, channel description +*/ +typedef struct opj_jp2_color +{ + unsigned char *icc_profile_buf; + int icc_profile_len; + + opj_jp2_cdef_t *jp2_cdef; + opj_jp2_pclr_t *jp2_pclr; + unsigned char jp2_has_colr; +} opj_jp2_color_t; + +/** +JP2 component +*/ +typedef struct opj_jp2_comps { + int depth; + int sgnd; + int bpcc; +} opj_jp2_comps_t; + +/** +JPEG-2000 file format reader/writer +*/ +typedef struct opj_jp2 { + /** codec context */ + opj_common_ptr cinfo; + /** handle to the J2K codec */ + opj_j2k_t *j2k; + unsigned int w; + unsigned int h; + unsigned int numcomps; + unsigned int bpc; + unsigned int C; + unsigned int UnkC; + unsigned int IPR; + unsigned int meth; + unsigned int approx; + unsigned int enumcs; + unsigned int precedence; + unsigned int brand; + unsigned int minversion; + unsigned int numcl; + unsigned int *cl; + opj_jp2_comps_t *comps; + unsigned int j2k_codestream_offset; + unsigned int j2k_codestream_length; + opj_bool jpip_on; + opj_bool ignore_pclr_cmap_cdef; +} opj_jp2_t; + +/** +JP2 Box +*/ +typedef struct opj_jp2_box { + int length; + int type; + int init_pos; +} opj_jp2_box_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write the JP2H box - JP2 Header box (used in MJ2) +@param jp2 JP2 handle +@param cio Output buffer stream +*/ +void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Read the JP2H box - JP2 Header box (used in MJ2) +@param jp2 JP2 handle +@param cio Input buffer stream +@param ext Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color); +/** +Creates a JP2 decompression structure +@param cinfo Codec context info +@return Returns a handle to a JP2 decompressor if successful, returns NULL otherwise +*/ +opj_jp2_t* jp2_create_decompress(opj_common_ptr cinfo); +/** +Destroy a JP2 decompressor handle +@param jp2 JP2 decompressor handle to destroy +*/ +void jp2_destroy_decompress(opj_jp2_t *jp2); +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 decompressor handle +@param parameters decompression parameters +*/ +void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 file stream +@param jp2 JP2 decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a JP2 compression structure +@param cinfo Codec context info +@return Returns a handle to a JP2 compressor if successful, returns NULL otherwise +*/ +opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo); +/** +Destroy a JP2 compressor handle +@param jp2 JP2 compressor handle to destroy +*/ +void jp2_destroy_compress(opj_jp2_t *jp2); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image); +/** +Encode an image into a JPEG-2000 file stream +@param jp2 JP2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +opj_bool opj_jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __JP2_H */ + diff --git a/openjpeg-dotnet/libopenjpeg/jpt.c b/openjpeg-dotnet/libopenjpeg/jpt.c new file mode 100644 index 0000000..a2566ea --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpt.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/* + * Read the information contains in VBAS [JPP/JPT stream message header] + * Store information (7 bits) in value + * + */ +unsigned int jpt_read_VBAS_info(opj_cio_t *cio, unsigned int value) { + unsigned char elmt; + + elmt = cio_read(cio, 1); + while ((elmt >> 7) == 1) { + value = (value << 7); + value |= (elmt & 0x7f); + elmt = cio_read(cio, 1); + } + value = (value << 7); + value |= (elmt & 0x7f); + + return value; +} + +/* + * Initialize the value of the message header structure + * + */ +void jpt_init_msg_header(opj_jpt_msg_header_t * header) { + header->Id = 0; /* In-class Identifier */ + header->last_byte = 0; /* Last byte information */ + header->Class_Id = 0; /* Class Identifier */ + header->CSn_Id = 0; /* CSn : index identifier */ + header->Msg_offset = 0; /* Message offset */ + header->Msg_length = 0; /* Message length */ + header->Layer_nb = 0; /* Auxiliary for JPP case */ +} + +/* + * Re-initialize the value of the message header structure + * + * Only parameters always present in message header + * + */ +void jpt_reinit_msg_header(opj_jpt_msg_header_t * header) { + header->Id = 0; /* In-class Identifier */ + header->last_byte = 0; /* Last byte information */ + header->Msg_offset = 0; /* Message offset */ + header->Msg_length = 0; /* Message length */ +} + +/* + * Read the message header for a JPP/JPT - stream + * + */ +void jpt_read_msg_header(opj_common_ptr cinfo, opj_cio_t *cio, opj_jpt_msg_header_t *header) { + unsigned char elmt, Class = 0, CSn = 0; + jpt_reinit_msg_header(header); + + /* ------------- */ + /* VBAS : Bin-ID */ + /* ------------- */ + elmt = cio_read(cio, 1); + + /* See for Class and CSn */ + switch ((elmt >> 5) & 0x03) { + case 0: + opj_event_msg(cinfo, EVT_ERROR, "Forbidden value encounter in message header !!\n"); + break; + case 1: + Class = 0; + CSn = 0; + break; + case 2: + Class = 1; + CSn = 0; + break; + case 3: + Class = 1; + CSn = 1; + break; + default: + break; + } + + /* see information on bits 'c' [p 10 : A.2.1 general, ISO/IEC FCD 15444-9] */ + if (((elmt >> 4) & 0x01) == 1) + header->last_byte = 1; + + /* In-class identifier */ + header->Id |= (elmt & 0x0f); + if ((elmt >> 7) == 1) + header->Id = jpt_read_VBAS_info(cio, header->Id); + + /* ------------ */ + /* VBAS : Class */ + /* ------------ */ + if (Class == 1) { + header->Class_Id = 0; + header->Class_Id = jpt_read_VBAS_info(cio, header->Class_Id); + } + + /* ---------- */ + /* VBAS : CSn */ + /* ---------- */ + if (CSn == 1) { + header->CSn_Id = 0; + header->CSn_Id = jpt_read_VBAS_info(cio, header->CSn_Id); + } + + /* ----------------- */ + /* VBAS : Msg_offset */ + /* ----------------- */ + header->Msg_offset = jpt_read_VBAS_info(cio, header->Msg_offset); + + /* ----------------- */ + /* VBAS : Msg_length */ + /* ----------------- */ + header->Msg_length = jpt_read_VBAS_info(cio, header->Msg_length); + + /* ---------- */ + /* VBAS : Aux */ + /* ---------- */ + if ((header->Class_Id & 0x01) == 1) { + header->Layer_nb = 0; + header->Layer_nb = jpt_read_VBAS_info(cio, header->Layer_nb); + } +} diff --git a/openjpeg-dotnet/libopenjpeg/jpt.h b/openjpeg-dotnet/libopenjpeg/jpt.h new file mode 100644 index 0000000..eb01f98 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpt.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __JPT_H +#define __JPT_H +/** +@file jpt.h +@brief JPT-stream reader (JPEG 2000, JPIP) + +JPT-stream functions are implemented in J2K.C. +*/ + +/** +Message Header JPT stream structure +*/ +typedef struct opj_jpt_msg_header { + /** In-class Identifier */ + unsigned int Id; + /** Last byte information */ + unsigned int last_byte; + /** Class Identifier */ + unsigned int Class_Id; + /** CSn : index identifier */ + unsigned int CSn_Id; + /** Message offset */ + unsigned int Msg_offset; + /** Message length */ + unsigned int Msg_length; + /** Auxiliary for JPP case */ + unsigned int Layer_nb; +} opj_jpt_msg_header_t; + +/* ----------------------------------------------------------------------- */ + +/** +Initialize the value of the message header structure +@param header Message header structure +*/ +void jpt_init_msg_header(opj_jpt_msg_header_t * header); + +/** +Read the message header for a JPP/JPT - stream +@param cinfo Codec context info +@param cio CIO handle +@param header Message header structure +*/ +void jpt_read_msg_header(opj_common_ptr cinfo, opj_cio_t *cio, opj_jpt_msg_header_t *header); + +#endif diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/CMakeLists.txt b/openjpeg-dotnet/libopenjpeg/jpwl/CMakeLists.txt new file mode 100644 index 0000000..6fcfc95 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/CMakeLists.txt @@ -0,0 +1,32 @@ +# Makefile for the main JPWL OpenJPEG codecs: JPWL_ j2k_to_image and JPWL_image_to_j2k + +ADD_DEFINITIONS(-DUSE_JPWL) + +SET(JPWL_SRCS crc.c jpwl.c jpwl_lib.c rs.c) +IF(APPLE) + SET_SOURCE_FILES_PROPERTIES( + rs.c + PROPERTIES + COMPILE_FLAGS -fno-common) +ENDIF(APPLE) + +INCLUDE_DIRECTORIES( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ) + +# Build the library +IF(WIN32) + IF(BUILD_SHARED_LIBS) + ADD_DEFINITIONS(-DOPJ_EXPORTS) + ELSE(BUILD_SHARED_LIBS) + ADD_DEFINITIONS(-DOPJ_STATIC) + ENDIF(BUILD_SHARED_LIBS) +ENDIF(WIN32) +ADD_LIBRARY(${OPENJPEG_LIBRARY_NAME}_JPWL ${JPWL_SRCS} ${OPENJPEG_SRCS}) +SET_TARGET_PROPERTIES(${OPENJPEG_LIBRARY_NAME}_JPWL + PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) + +# Install library +INSTALL(TARGETS ${OPENJPEG_LIBRARY_NAME}_JPWL + DESTINATION ${OPENJPEG_INSTALL_LIB_DIR} COMPONENT Libraries +) diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/Makefile b/openjpeg-dotnet/libopenjpeg/jpwl/Makefile new file mode 100644 index 0000000..5e39177 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/Makefile @@ -0,0 +1,908 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# libopenjpeg/jpwl/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + + +pkgdatadir = $(datadir)/openjpeg +pkgincludedir = $(includedir)/openjpeg +pkglibdir = $(libdir)/openjpeg +pkglibexecdir = $(libexecdir)/openjpeg +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-unknown-linux-gnu +host_triplet = x86_64-unknown-linux-gnu +target_triplet = x86_64-unknown-linux-gnu +subdir = libopenjpeg/jpwl +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/opj_check_lib.m4 \ + $(top_srcdir)/m4/opj_compiler_flag.m4 \ + $(top_srcdir)/m4/opj_doxygen.m4 $(top_srcdir)/m4/pkg.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/opj_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libopenjpeg_JPWL_la_DEPENDENCIES = +am__objects_1 = libopenjpeg_JPWL_la-bio.lo libopenjpeg_JPWL_la-cio.lo \ + libopenjpeg_JPWL_la-dwt.lo libopenjpeg_JPWL_la-event.lo \ + libopenjpeg_JPWL_la-image.lo libopenjpeg_JPWL_la-j2k.lo \ + libopenjpeg_JPWL_la-j2k_lib.lo libopenjpeg_JPWL_la-jp2.lo \ + libopenjpeg_JPWL_la-jpt.lo libopenjpeg_JPWL_la-mct.lo \ + libopenjpeg_JPWL_la-mqc.lo libopenjpeg_JPWL_la-openjpeg.lo \ + libopenjpeg_JPWL_la-pi.lo libopenjpeg_JPWL_la-raw.lo \ + libopenjpeg_JPWL_la-t1.lo \ + libopenjpeg_JPWL_la-t1_generate_luts.lo \ + libopenjpeg_JPWL_la-t2.lo libopenjpeg_JPWL_la-tcd.lo \ + libopenjpeg_JPWL_la-tgt.lo libopenjpeg_JPWL_la-cidx_manager.lo \ + libopenjpeg_JPWL_la-phix_manager.lo \ + libopenjpeg_JPWL_la-ppix_manager.lo \ + libopenjpeg_JPWL_la-thix_manager.lo \ + libopenjpeg_JPWL_la-tpix_manager.lo +am_libopenjpeg_JPWL_la_OBJECTS = $(am__objects_1) \ + libopenjpeg_JPWL_la-crc.lo libopenjpeg_JPWL_la-jpwl.lo \ + libopenjpeg_JPWL_la-jpwl_lib.lo libopenjpeg_JPWL_la-rs.lo +libopenjpeg_JPWL_la_OBJECTS = $(am_libopenjpeg_JPWL_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libopenjpeg_JPWL_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) \ + $(libopenjpeg_JPWL_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libopenjpeg_JPWL_la_SOURCES) +DIST_SOURCES = $(libopenjpeg_JPWL_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/missing --run aclocal-1.11 +AMTAR = ${SHELL} /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/missing --run tar +AM_DEFAULT_VERBOSITY = 0 +AR = ar +AS = as +AUTOCONF = ${SHELL} /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/missing --run autoconf +AUTOHEADER = ${SHELL} /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/missing --run autoheader +AUTOMAKE = ${SHELL} /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/missing --run automake-1.11 +AWK = mawk +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 -Wno-unused-result -O3 +CPP = gcc -E +CPPFLAGS = +CYGPATH_W = echo +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = dlltool +DSYMUTIL = +DUMPBIN = +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +EXEEXT = +FCGI_CFLAGS = +FCGI_LIBS = +FGREP = /bin/grep -F +GREP = /bin/grep +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +LCMS1_CFLAGS = +LCMS1_LIBS = +LCMS2_CFLAGS = +LCMS2_LIBS = +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LIBCURL_CFLAGS = +LIBCURL_LIBS = +LIBOBJS = +LIBS = +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +MAJOR_NR = 1 +MAKEINFO = ${SHELL} /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/missing --run makeinfo +MICRO_NR = 0 +MINOR_NR = 5 +MKDIR_P = /bin/mkdir -p +NM = /usr/bin/nm -B +NMEDIT = +OBJDUMP = objdump +OBJEXT = o +OTOOL = +OTOOL64 = +PACKAGE = openjpeg +PACKAGE_BUGREPORT = openjpeg@googlegroups.com +PACKAGE_NAME = OpenJPEG +PACKAGE_STRING = OpenJPEG 1.5.0 +PACKAGE_TARNAME = openjpeg +PACKAGE_URL = http://www.openjpeg.org +PACKAGE_VERSION = 1.5.0 +PATH_SEPARATOR = : +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PNG_CFLAGS = -I/usr/include/libpng12 +PNG_LIBS = -lpng12 -lz +RANLIB = ranlib +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THREAD_CFLAGS = +THREAD_LIBS = +TIFF_CFLAGS = -I/usr/include +TIFF_LIBS = -L/usr/lib -ltiff +VERSION = 1.5.0 +Z_CFLAGS = +Z_LIBS = +abs_builddir = /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/libopenjpeg/jpwl +abs_srcdir = /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/libopenjpeg/jpwl +abs_top_builddir = /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0 +abs_top_srcdir = /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0 +ac_ct_CC = gcc +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = ${AMTAR} chof - "$$tardir" +am__untar = ${AMTAR} xf - +bindir = ${exec_prefix}/bin +build = x86_64-unknown-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = unknown +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +host = x86_64-unknown-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = unknown +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/justincc/jc/it/g/graphics/jpeg/jpeg2000/openjpeg/src/openjpeg-1.5.0/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +lt_ECHO = echo +lt_version = 6:0:5 +mandir = ${datarootdir}/man +mkdir_p = /bin/mkdir -p +oldincludedir = /usr/include +opj_doxygen = doxygen +opj_have_doxygen = no +pdfdir = ${docdir} +pkgconfig_requires_private = Requires.private +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +requirements = +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +sysconfdir = ${prefix}/etc +target = x86_64-unknown-linux-gnu +target_alias = +target_cpu = x86_64 +target_os = linux-gnu +target_vendor = unknown +top_build_prefix = ../../ +top_builddir = ../.. +top_srcdir = ../.. +MAINTAINERCLEANFILES = Makefile.in +lib_LTLIBRARIES = libopenjpeg_JPWL.la +OPJ_SRC = \ +../bio.c \ +../cio.c \ +../dwt.c \ +../event.c \ +../image.c \ +../j2k.c \ +../j2k_lib.c \ +../jp2.c \ +../jpt.c \ +../mct.c \ +../mqc.c \ +../openjpeg.c \ +../pi.c \ +../raw.c \ +../t1.c \ +../t1_generate_luts.c \ +../t2.c \ +../tcd.c \ +../tgt.c \ +../cidx_manager.c \ +../phix_manager.c \ +../ppix_manager.c \ +../thix_manager.c \ +../tpix_manager.c + +libopenjpeg_JPWL_la_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/libopenjpeg \ +-I$(top_builddir)/libopenjpeg \ +-I$(top_srcdir)/libopenjpeg/jpwl \ +-I$(top_builddir)/libopenjpeg/jpwl \ +-DUSE_JPWL + +libopenjpeg_JPWL_la_CFLAGS = +libopenjpeg_JPWL_la_LIBADD = -lm +libopenjpeg_JPWL_la_LDFLAGS = -no-undefined -version-info 6:0:5 +libopenjpeg_JPWL_la_SOURCES = \ +$(OPJ_SRC) \ +crc.c \ +jpwl.c \ +jpwl_lib.c \ +rs.c \ +crc.h \ +jpwl.h \ +rs.h + +solist = $(foreach f, $(dll) $(so), echo -e ' $(SO_PREFIX)\t$(base)/$(f)' ;) +get_tok = $(shell grep -E "^$(1)=" $(lib_LTLIBRARIES) | cut -d "'" -f 2) +base = $(call get_tok,libdir) +so = $(call get_tok,library_names) +a = $(call get_tok,old_library) +SO_PREFIX = (SO) +#SO_PREFIX = (DY) +#SO_PREFIX = (DLL) +dll = +#dll = +#dll = $(call get_tok,dlname) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libopenjpeg/jpwl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign libopenjpeg/jpwl/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libopenjpeg_JPWL.la: $(libopenjpeg_JPWL_la_OBJECTS) $(libopenjpeg_JPWL_la_DEPENDENCIES) + $(AM_V_CCLD)$(libopenjpeg_JPWL_la_LINK) -rpath $(libdir) $(libopenjpeg_JPWL_la_OBJECTS) $(libopenjpeg_JPWL_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +include ./$(DEPDIR)/libopenjpeg_JPWL_la-bio.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-cio.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-crc.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-dwt.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-event.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-image.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-j2k.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-jp2.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-jpt.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-mct.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-mqc.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-pi.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-raw.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-rs.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-t1.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-t2.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-tcd.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-tgt.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Plo +include ./$(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Plo + +.c.o: + $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +# $(AM_V_CC) \ +# source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(COMPILE) -c $< + +.c.obj: + $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` + $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +# $(AM_V_CC) \ +# source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +# $(AM_V_CC) \ +# source='$<' object='$@' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LTCOMPILE) -c -o $@ $< + +libopenjpeg_JPWL_la-bio.lo: ../bio.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-bio.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-bio.Tpo -c -o libopenjpeg_JPWL_la-bio.lo `test -f '../bio.c' || echo '$(srcdir)/'`../bio.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-bio.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-bio.Plo +# $(AM_V_CC) \ +# source='../bio.c' object='libopenjpeg_JPWL_la-bio.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-bio.lo `test -f '../bio.c' || echo '$(srcdir)/'`../bio.c + +libopenjpeg_JPWL_la-cio.lo: ../cio.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-cio.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-cio.Tpo -c -o libopenjpeg_JPWL_la-cio.lo `test -f '../cio.c' || echo '$(srcdir)/'`../cio.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-cio.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-cio.Plo +# $(AM_V_CC) \ +# source='../cio.c' object='libopenjpeg_JPWL_la-cio.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-cio.lo `test -f '../cio.c' || echo '$(srcdir)/'`../cio.c + +libopenjpeg_JPWL_la-dwt.lo: ../dwt.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-dwt.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-dwt.Tpo -c -o libopenjpeg_JPWL_la-dwt.lo `test -f '../dwt.c' || echo '$(srcdir)/'`../dwt.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-dwt.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-dwt.Plo +# $(AM_V_CC) \ +# source='../dwt.c' object='libopenjpeg_JPWL_la-dwt.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-dwt.lo `test -f '../dwt.c' || echo '$(srcdir)/'`../dwt.c + +libopenjpeg_JPWL_la-event.lo: ../event.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-event.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-event.Tpo -c -o libopenjpeg_JPWL_la-event.lo `test -f '../event.c' || echo '$(srcdir)/'`../event.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-event.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-event.Plo +# $(AM_V_CC) \ +# source='../event.c' object='libopenjpeg_JPWL_la-event.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-event.lo `test -f '../event.c' || echo '$(srcdir)/'`../event.c + +libopenjpeg_JPWL_la-image.lo: ../image.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-image.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-image.Tpo -c -o libopenjpeg_JPWL_la-image.lo `test -f '../image.c' || echo '$(srcdir)/'`../image.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-image.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-image.Plo +# $(AM_V_CC) \ +# source='../image.c' object='libopenjpeg_JPWL_la-image.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-image.lo `test -f '../image.c' || echo '$(srcdir)/'`../image.c + +libopenjpeg_JPWL_la-j2k.lo: ../j2k.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-j2k.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-j2k.Tpo -c -o libopenjpeg_JPWL_la-j2k.lo `test -f '../j2k.c' || echo '$(srcdir)/'`../j2k.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-j2k.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-j2k.Plo +# $(AM_V_CC) \ +# source='../j2k.c' object='libopenjpeg_JPWL_la-j2k.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-j2k.lo `test -f '../j2k.c' || echo '$(srcdir)/'`../j2k.c + +libopenjpeg_JPWL_la-j2k_lib.lo: ../j2k_lib.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-j2k_lib.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Tpo -c -o libopenjpeg_JPWL_la-j2k_lib.lo `test -f '../j2k_lib.c' || echo '$(srcdir)/'`../j2k_lib.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Plo +# $(AM_V_CC) \ +# source='../j2k_lib.c' object='libopenjpeg_JPWL_la-j2k_lib.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-j2k_lib.lo `test -f '../j2k_lib.c' || echo '$(srcdir)/'`../j2k_lib.c + +libopenjpeg_JPWL_la-jp2.lo: ../jp2.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jp2.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jp2.Tpo -c -o libopenjpeg_JPWL_la-jp2.lo `test -f '../jp2.c' || echo '$(srcdir)/'`../jp2.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jp2.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jp2.Plo +# $(AM_V_CC) \ +# source='../jp2.c' object='libopenjpeg_JPWL_la-jp2.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jp2.lo `test -f '../jp2.c' || echo '$(srcdir)/'`../jp2.c + +libopenjpeg_JPWL_la-jpt.lo: ../jpt.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jpt.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jpt.Tpo -c -o libopenjpeg_JPWL_la-jpt.lo `test -f '../jpt.c' || echo '$(srcdir)/'`../jpt.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jpt.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jpt.Plo +# $(AM_V_CC) \ +# source='../jpt.c' object='libopenjpeg_JPWL_la-jpt.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jpt.lo `test -f '../jpt.c' || echo '$(srcdir)/'`../jpt.c + +libopenjpeg_JPWL_la-mct.lo: ../mct.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-mct.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-mct.Tpo -c -o libopenjpeg_JPWL_la-mct.lo `test -f '../mct.c' || echo '$(srcdir)/'`../mct.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-mct.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-mct.Plo +# $(AM_V_CC) \ +# source='../mct.c' object='libopenjpeg_JPWL_la-mct.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-mct.lo `test -f '../mct.c' || echo '$(srcdir)/'`../mct.c + +libopenjpeg_JPWL_la-mqc.lo: ../mqc.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-mqc.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-mqc.Tpo -c -o libopenjpeg_JPWL_la-mqc.lo `test -f '../mqc.c' || echo '$(srcdir)/'`../mqc.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-mqc.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-mqc.Plo +# $(AM_V_CC) \ +# source='../mqc.c' object='libopenjpeg_JPWL_la-mqc.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-mqc.lo `test -f '../mqc.c' || echo '$(srcdir)/'`../mqc.c + +libopenjpeg_JPWL_la-openjpeg.lo: ../openjpeg.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-openjpeg.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Tpo -c -o libopenjpeg_JPWL_la-openjpeg.lo `test -f '../openjpeg.c' || echo '$(srcdir)/'`../openjpeg.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Plo +# $(AM_V_CC) \ +# source='../openjpeg.c' object='libopenjpeg_JPWL_la-openjpeg.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-openjpeg.lo `test -f '../openjpeg.c' || echo '$(srcdir)/'`../openjpeg.c + +libopenjpeg_JPWL_la-pi.lo: ../pi.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-pi.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-pi.Tpo -c -o libopenjpeg_JPWL_la-pi.lo `test -f '../pi.c' || echo '$(srcdir)/'`../pi.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-pi.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-pi.Plo +# $(AM_V_CC) \ +# source='../pi.c' object='libopenjpeg_JPWL_la-pi.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-pi.lo `test -f '../pi.c' || echo '$(srcdir)/'`../pi.c + +libopenjpeg_JPWL_la-raw.lo: ../raw.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-raw.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-raw.Tpo -c -o libopenjpeg_JPWL_la-raw.lo `test -f '../raw.c' || echo '$(srcdir)/'`../raw.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-raw.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-raw.Plo +# $(AM_V_CC) \ +# source='../raw.c' object='libopenjpeg_JPWL_la-raw.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-raw.lo `test -f '../raw.c' || echo '$(srcdir)/'`../raw.c + +libopenjpeg_JPWL_la-t1.lo: ../t1.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-t1.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-t1.Tpo -c -o libopenjpeg_JPWL_la-t1.lo `test -f '../t1.c' || echo '$(srcdir)/'`../t1.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-t1.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-t1.Plo +# $(AM_V_CC) \ +# source='../t1.c' object='libopenjpeg_JPWL_la-t1.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-t1.lo `test -f '../t1.c' || echo '$(srcdir)/'`../t1.c + +libopenjpeg_JPWL_la-t1_generate_luts.lo: ../t1_generate_luts.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-t1_generate_luts.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Tpo -c -o libopenjpeg_JPWL_la-t1_generate_luts.lo `test -f '../t1_generate_luts.c' || echo '$(srcdir)/'`../t1_generate_luts.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Plo +# $(AM_V_CC) \ +# source='../t1_generate_luts.c' object='libopenjpeg_JPWL_la-t1_generate_luts.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-t1_generate_luts.lo `test -f '../t1_generate_luts.c' || echo '$(srcdir)/'`../t1_generate_luts.c + +libopenjpeg_JPWL_la-t2.lo: ../t2.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-t2.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-t2.Tpo -c -o libopenjpeg_JPWL_la-t2.lo `test -f '../t2.c' || echo '$(srcdir)/'`../t2.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-t2.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-t2.Plo +# $(AM_V_CC) \ +# source='../t2.c' object='libopenjpeg_JPWL_la-t2.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-t2.lo `test -f '../t2.c' || echo '$(srcdir)/'`../t2.c + +libopenjpeg_JPWL_la-tcd.lo: ../tcd.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-tcd.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-tcd.Tpo -c -o libopenjpeg_JPWL_la-tcd.lo `test -f '../tcd.c' || echo '$(srcdir)/'`../tcd.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-tcd.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-tcd.Plo +# $(AM_V_CC) \ +# source='../tcd.c' object='libopenjpeg_JPWL_la-tcd.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-tcd.lo `test -f '../tcd.c' || echo '$(srcdir)/'`../tcd.c + +libopenjpeg_JPWL_la-tgt.lo: ../tgt.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-tgt.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-tgt.Tpo -c -o libopenjpeg_JPWL_la-tgt.lo `test -f '../tgt.c' || echo '$(srcdir)/'`../tgt.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-tgt.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-tgt.Plo +# $(AM_V_CC) \ +# source='../tgt.c' object='libopenjpeg_JPWL_la-tgt.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-tgt.lo `test -f '../tgt.c' || echo '$(srcdir)/'`../tgt.c + +libopenjpeg_JPWL_la-cidx_manager.lo: ../cidx_manager.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-cidx_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Tpo -c -o libopenjpeg_JPWL_la-cidx_manager.lo `test -f '../cidx_manager.c' || echo '$(srcdir)/'`../cidx_manager.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Plo +# $(AM_V_CC) \ +# source='../cidx_manager.c' object='libopenjpeg_JPWL_la-cidx_manager.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-cidx_manager.lo `test -f '../cidx_manager.c' || echo '$(srcdir)/'`../cidx_manager.c + +libopenjpeg_JPWL_la-phix_manager.lo: ../phix_manager.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-phix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Tpo -c -o libopenjpeg_JPWL_la-phix_manager.lo `test -f '../phix_manager.c' || echo '$(srcdir)/'`../phix_manager.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Plo +# $(AM_V_CC) \ +# source='../phix_manager.c' object='libopenjpeg_JPWL_la-phix_manager.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-phix_manager.lo `test -f '../phix_manager.c' || echo '$(srcdir)/'`../phix_manager.c + +libopenjpeg_JPWL_la-ppix_manager.lo: ../ppix_manager.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-ppix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Tpo -c -o libopenjpeg_JPWL_la-ppix_manager.lo `test -f '../ppix_manager.c' || echo '$(srcdir)/'`../ppix_manager.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Plo +# $(AM_V_CC) \ +# source='../ppix_manager.c' object='libopenjpeg_JPWL_la-ppix_manager.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-ppix_manager.lo `test -f '../ppix_manager.c' || echo '$(srcdir)/'`../ppix_manager.c + +libopenjpeg_JPWL_la-thix_manager.lo: ../thix_manager.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-thix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Tpo -c -o libopenjpeg_JPWL_la-thix_manager.lo `test -f '../thix_manager.c' || echo '$(srcdir)/'`../thix_manager.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Plo +# $(AM_V_CC) \ +# source='../thix_manager.c' object='libopenjpeg_JPWL_la-thix_manager.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-thix_manager.lo `test -f '../thix_manager.c' || echo '$(srcdir)/'`../thix_manager.c + +libopenjpeg_JPWL_la-tpix_manager.lo: ../tpix_manager.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-tpix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Tpo -c -o libopenjpeg_JPWL_la-tpix_manager.lo `test -f '../tpix_manager.c' || echo '$(srcdir)/'`../tpix_manager.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Plo +# $(AM_V_CC) \ +# source='../tpix_manager.c' object='libopenjpeg_JPWL_la-tpix_manager.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-tpix_manager.lo `test -f '../tpix_manager.c' || echo '$(srcdir)/'`../tpix_manager.c + +libopenjpeg_JPWL_la-crc.lo: crc.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-crc.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-crc.Tpo -c -o libopenjpeg_JPWL_la-crc.lo `test -f 'crc.c' || echo '$(srcdir)/'`crc.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-crc.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-crc.Plo +# $(AM_V_CC) \ +# source='crc.c' object='libopenjpeg_JPWL_la-crc.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-crc.lo `test -f 'crc.c' || echo '$(srcdir)/'`crc.c + +libopenjpeg_JPWL_la-jpwl.lo: jpwl.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jpwl.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Tpo -c -o libopenjpeg_JPWL_la-jpwl.lo `test -f 'jpwl.c' || echo '$(srcdir)/'`jpwl.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Plo +# $(AM_V_CC) \ +# source='jpwl.c' object='libopenjpeg_JPWL_la-jpwl.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jpwl.lo `test -f 'jpwl.c' || echo '$(srcdir)/'`jpwl.c + +libopenjpeg_JPWL_la-jpwl_lib.lo: jpwl_lib.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jpwl_lib.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Tpo -c -o libopenjpeg_JPWL_la-jpwl_lib.lo `test -f 'jpwl_lib.c' || echo '$(srcdir)/'`jpwl_lib.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Plo +# $(AM_V_CC) \ +# source='jpwl_lib.c' object='libopenjpeg_JPWL_la-jpwl_lib.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jpwl_lib.lo `test -f 'jpwl_lib.c' || echo '$(srcdir)/'`jpwl_lib.c + +libopenjpeg_JPWL_la-rs.lo: rs.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-rs.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-rs.Tpo -c -o libopenjpeg_JPWL_la-rs.lo `test -f 'rs.c' || echo '$(srcdir)/'`rs.c + $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-rs.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-rs.Plo +# $(AM_V_CC) \ +# source='rs.c' object='libopenjpeg_JPWL_la-rs.lo' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-rs.lo `test -f 'rs.c' || echo '$(srcdir)/'`rs.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-data-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-data-hook install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +install-data-hook: + @echo -e " (LA)\t$(libdir)/libopenjpeg_JPWL.la" >> $(top_builddir)/report.txt + @( $(call solist) ) >> $(top_builddir)/report.txt + @echo -e " (A)\t$(base)/$(a)" >> $(top_builddir)/report.txt + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/Makefile.am b/openjpeg-dotnet/libopenjpeg/jpwl/Makefile.am new file mode 100644 index 0000000..f1eda31 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/Makefile.am @@ -0,0 +1,77 @@ +MAINTAINERCLEANFILES = Makefile.in + +lib_LTLIBRARIES = libopenjpeg_JPWL.la + +OPJ_SRC = \ +../bio.c \ +../cio.c \ +../dwt.c \ +../event.c \ +../image.c \ +../j2k.c \ +../j2k_lib.c \ +../jp2.c \ +../jpt.c \ +../mct.c \ +../mqc.c \ +../openjpeg.c \ +../pi.c \ +../raw.c \ +../t1.c \ +../t1_generate_luts.c \ +../t2.c \ +../tcd.c \ +../tgt.c \ +../cidx_manager.c \ +../phix_manager.c \ +../ppix_manager.c \ +../thix_manager.c \ +../tpix_manager.c + +libopenjpeg_JPWL_la_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/libopenjpeg \ +-I$(top_builddir)/libopenjpeg \ +-I$(top_srcdir)/libopenjpeg/jpwl \ +-I$(top_builddir)/libopenjpeg/jpwl \ +-DUSE_JPWL +libopenjpeg_JPWL_la_CFLAGS = +libopenjpeg_JPWL_la_LIBADD = -lm +libopenjpeg_JPWL_la_LDFLAGS = -no-undefined -version-info @lt_version@ +libopenjpeg_JPWL_la_SOURCES = \ +$(OPJ_SRC) \ +crc.c \ +jpwl.c \ +jpwl_lib.c \ +rs.c \ +crc.h \ +jpwl.h \ +rs.h + +install-data-hook: + @echo -e " (LA)\t$(libdir)/libopenjpeg_JPWL.la" >> $(top_builddir)/report.txt +if BUILD_SHARED + @( $(call solist) ) >> $(top_builddir)/report.txt +endif +if BUILD_STATIC + @echo -e " (A)\t$(base)/$(a)" >> $(top_builddir)/report.txt +endif + +solist = $(foreach f, $(dll) $(so), echo -e ' $(SO_PREFIX)\t$(base)/$(f)' ;) +get_tok = $(shell grep -E "^$(1)=" $(lib_LTLIBRARIES) | cut -d "'" -f 2) +base = $(call get_tok,libdir) +so = $(call get_tok,library_names) +a = $(call get_tok,old_library) + +if HAVE_WIN32 +SO_PREFIX = (DLL) +dll = $(call get_tok,dlname) +else +if HAVE_DARWIN +SO_PREFIX = (DY) +dll = +else +SO_PREFIX = (SO) +dll = +endif +endif diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/Makefile.in b/openjpeg-dotnet/libopenjpeg/jpwl/Makefile.in new file mode 100644 index 0000000..ace2887 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/Makefile.in @@ -0,0 +1,908 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = libopenjpeg/jpwl +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/opj_check_lib.m4 \ + $(top_srcdir)/m4/opj_compiler_flag.m4 \ + $(top_srcdir)/m4/opj_doxygen.m4 $(top_srcdir)/m4/pkg.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/opj_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libopenjpeg_JPWL_la_DEPENDENCIES = +am__objects_1 = libopenjpeg_JPWL_la-bio.lo libopenjpeg_JPWL_la-cio.lo \ + libopenjpeg_JPWL_la-dwt.lo libopenjpeg_JPWL_la-event.lo \ + libopenjpeg_JPWL_la-image.lo libopenjpeg_JPWL_la-j2k.lo \ + libopenjpeg_JPWL_la-j2k_lib.lo libopenjpeg_JPWL_la-jp2.lo \ + libopenjpeg_JPWL_la-jpt.lo libopenjpeg_JPWL_la-mct.lo \ + libopenjpeg_JPWL_la-mqc.lo libopenjpeg_JPWL_la-openjpeg.lo \ + libopenjpeg_JPWL_la-pi.lo libopenjpeg_JPWL_la-raw.lo \ + libopenjpeg_JPWL_la-t1.lo \ + libopenjpeg_JPWL_la-t1_generate_luts.lo \ + libopenjpeg_JPWL_la-t2.lo libopenjpeg_JPWL_la-tcd.lo \ + libopenjpeg_JPWL_la-tgt.lo libopenjpeg_JPWL_la-cidx_manager.lo \ + libopenjpeg_JPWL_la-phix_manager.lo \ + libopenjpeg_JPWL_la-ppix_manager.lo \ + libopenjpeg_JPWL_la-thix_manager.lo \ + libopenjpeg_JPWL_la-tpix_manager.lo +am_libopenjpeg_JPWL_la_OBJECTS = $(am__objects_1) \ + libopenjpeg_JPWL_la-crc.lo libopenjpeg_JPWL_la-jpwl.lo \ + libopenjpeg_JPWL_la-jpwl_lib.lo libopenjpeg_JPWL_la-rs.lo +libopenjpeg_JPWL_la_OBJECTS = $(am_libopenjpeg_JPWL_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libopenjpeg_JPWL_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) \ + $(libopenjpeg_JPWL_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libopenjpeg_JPWL_la_SOURCES) +DIST_SOURCES = $(libopenjpeg_JPWL_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FCGI_CFLAGS = @FCGI_CFLAGS@ +FCGI_LIBS = @FCGI_LIBS@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCMS1_CFLAGS = @LCMS1_CFLAGS@ +LCMS1_LIBS = @LCMS1_LIBS@ +LCMS2_CFLAGS = @LCMS2_CFLAGS@ +LCMS2_LIBS = @LCMS2_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL_CFLAGS = @LIBCURL_CFLAGS@ +LIBCURL_LIBS = @LIBCURL_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAJOR_NR = @MAJOR_NR@ +MAKEINFO = @MAKEINFO@ +MICRO_NR = @MICRO_NR@ +MINOR_NR = @MINOR_NR@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PNG_CFLAGS = @PNG_CFLAGS@ +PNG_LIBS = @PNG_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THREAD_CFLAGS = @THREAD_CFLAGS@ +THREAD_LIBS = @THREAD_LIBS@ +TIFF_CFLAGS = @TIFF_CFLAGS@ +TIFF_LIBS = @TIFF_LIBS@ +VERSION = @VERSION@ +Z_CFLAGS = @Z_CFLAGS@ +Z_LIBS = @Z_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_version = @lt_version@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +opj_doxygen = @opj_doxygen@ +opj_have_doxygen = @opj_have_doxygen@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +requirements = @requirements@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +lib_LTLIBRARIES = libopenjpeg_JPWL.la +OPJ_SRC = \ +../bio.c \ +../cio.c \ +../dwt.c \ +../event.c \ +../image.c \ +../j2k.c \ +../j2k_lib.c \ +../jp2.c \ +../jpt.c \ +../mct.c \ +../mqc.c \ +../openjpeg.c \ +../pi.c \ +../raw.c \ +../t1.c \ +../t1_generate_luts.c \ +../t2.c \ +../tcd.c \ +../tgt.c \ +../cidx_manager.c \ +../phix_manager.c \ +../ppix_manager.c \ +../thix_manager.c \ +../tpix_manager.c + +libopenjpeg_JPWL_la_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/libopenjpeg \ +-I$(top_builddir)/libopenjpeg \ +-I$(top_srcdir)/libopenjpeg/jpwl \ +-I$(top_builddir)/libopenjpeg/jpwl \ +-DUSE_JPWL + +libopenjpeg_JPWL_la_CFLAGS = +libopenjpeg_JPWL_la_LIBADD = -lm +libopenjpeg_JPWL_la_LDFLAGS = -no-undefined -version-info @lt_version@ +libopenjpeg_JPWL_la_SOURCES = \ +$(OPJ_SRC) \ +crc.c \ +jpwl.c \ +jpwl_lib.c \ +rs.c \ +crc.h \ +jpwl.h \ +rs.h + +solist = $(foreach f, $(dll) $(so), echo -e ' $(SO_PREFIX)\t$(base)/$(f)' ;) +get_tok = $(shell grep -E "^$(1)=" $(lib_LTLIBRARIES) | cut -d "'" -f 2) +base = $(call get_tok,libdir) +so = $(call get_tok,library_names) +a = $(call get_tok,old_library) +@HAVE_DARWIN_FALSE@@HAVE_WIN32_FALSE@SO_PREFIX = (SO) +@HAVE_DARWIN_TRUE@@HAVE_WIN32_FALSE@SO_PREFIX = (DY) +@HAVE_WIN32_TRUE@SO_PREFIX = (DLL) +@HAVE_DARWIN_FALSE@@HAVE_WIN32_FALSE@dll = +@HAVE_DARWIN_TRUE@@HAVE_WIN32_FALSE@dll = +@HAVE_WIN32_TRUE@dll = $(call get_tok,dlname) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libopenjpeg/jpwl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign libopenjpeg/jpwl/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libopenjpeg_JPWL.la: $(libopenjpeg_JPWL_la_OBJECTS) $(libopenjpeg_JPWL_la_DEPENDENCIES) + $(AM_V_CCLD)$(libopenjpeg_JPWL_la_LINK) -rpath $(libdir) $(libopenjpeg_JPWL_la_OBJECTS) $(libopenjpeg_JPWL_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-bio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-cio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-crc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-dwt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-event.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-image.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-j2k.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-jp2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-jpt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-mct.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-mqc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-pi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-raw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-rs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-t1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-t2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-tcd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-tgt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libopenjpeg_JPWL_la-bio.lo: ../bio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-bio.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-bio.Tpo -c -o libopenjpeg_JPWL_la-bio.lo `test -f '../bio.c' || echo '$(srcdir)/'`../bio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-bio.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-bio.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../bio.c' object='libopenjpeg_JPWL_la-bio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-bio.lo `test -f '../bio.c' || echo '$(srcdir)/'`../bio.c + +libopenjpeg_JPWL_la-cio.lo: ../cio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-cio.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-cio.Tpo -c -o libopenjpeg_JPWL_la-cio.lo `test -f '../cio.c' || echo '$(srcdir)/'`../cio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-cio.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-cio.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../cio.c' object='libopenjpeg_JPWL_la-cio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-cio.lo `test -f '../cio.c' || echo '$(srcdir)/'`../cio.c + +libopenjpeg_JPWL_la-dwt.lo: ../dwt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-dwt.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-dwt.Tpo -c -o libopenjpeg_JPWL_la-dwt.lo `test -f '../dwt.c' || echo '$(srcdir)/'`../dwt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-dwt.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-dwt.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../dwt.c' object='libopenjpeg_JPWL_la-dwt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-dwt.lo `test -f '../dwt.c' || echo '$(srcdir)/'`../dwt.c + +libopenjpeg_JPWL_la-event.lo: ../event.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-event.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-event.Tpo -c -o libopenjpeg_JPWL_la-event.lo `test -f '../event.c' || echo '$(srcdir)/'`../event.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-event.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-event.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../event.c' object='libopenjpeg_JPWL_la-event.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-event.lo `test -f '../event.c' || echo '$(srcdir)/'`../event.c + +libopenjpeg_JPWL_la-image.lo: ../image.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-image.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-image.Tpo -c -o libopenjpeg_JPWL_la-image.lo `test -f '../image.c' || echo '$(srcdir)/'`../image.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-image.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-image.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../image.c' object='libopenjpeg_JPWL_la-image.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-image.lo `test -f '../image.c' || echo '$(srcdir)/'`../image.c + +libopenjpeg_JPWL_la-j2k.lo: ../j2k.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-j2k.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-j2k.Tpo -c -o libopenjpeg_JPWL_la-j2k.lo `test -f '../j2k.c' || echo '$(srcdir)/'`../j2k.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-j2k.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-j2k.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../j2k.c' object='libopenjpeg_JPWL_la-j2k.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-j2k.lo `test -f '../j2k.c' || echo '$(srcdir)/'`../j2k.c + +libopenjpeg_JPWL_la-j2k_lib.lo: ../j2k_lib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-j2k_lib.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Tpo -c -o libopenjpeg_JPWL_la-j2k_lib.lo `test -f '../j2k_lib.c' || echo '$(srcdir)/'`../j2k_lib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-j2k_lib.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../j2k_lib.c' object='libopenjpeg_JPWL_la-j2k_lib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-j2k_lib.lo `test -f '../j2k_lib.c' || echo '$(srcdir)/'`../j2k_lib.c + +libopenjpeg_JPWL_la-jp2.lo: ../jp2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jp2.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jp2.Tpo -c -o libopenjpeg_JPWL_la-jp2.lo `test -f '../jp2.c' || echo '$(srcdir)/'`../jp2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jp2.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jp2.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../jp2.c' object='libopenjpeg_JPWL_la-jp2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jp2.lo `test -f '../jp2.c' || echo '$(srcdir)/'`../jp2.c + +libopenjpeg_JPWL_la-jpt.lo: ../jpt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jpt.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jpt.Tpo -c -o libopenjpeg_JPWL_la-jpt.lo `test -f '../jpt.c' || echo '$(srcdir)/'`../jpt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jpt.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jpt.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../jpt.c' object='libopenjpeg_JPWL_la-jpt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jpt.lo `test -f '../jpt.c' || echo '$(srcdir)/'`../jpt.c + +libopenjpeg_JPWL_la-mct.lo: ../mct.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-mct.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-mct.Tpo -c -o libopenjpeg_JPWL_la-mct.lo `test -f '../mct.c' || echo '$(srcdir)/'`../mct.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-mct.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-mct.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../mct.c' object='libopenjpeg_JPWL_la-mct.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-mct.lo `test -f '../mct.c' || echo '$(srcdir)/'`../mct.c + +libopenjpeg_JPWL_la-mqc.lo: ../mqc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-mqc.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-mqc.Tpo -c -o libopenjpeg_JPWL_la-mqc.lo `test -f '../mqc.c' || echo '$(srcdir)/'`../mqc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-mqc.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-mqc.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../mqc.c' object='libopenjpeg_JPWL_la-mqc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-mqc.lo `test -f '../mqc.c' || echo '$(srcdir)/'`../mqc.c + +libopenjpeg_JPWL_la-openjpeg.lo: ../openjpeg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-openjpeg.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Tpo -c -o libopenjpeg_JPWL_la-openjpeg.lo `test -f '../openjpeg.c' || echo '$(srcdir)/'`../openjpeg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-openjpeg.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../openjpeg.c' object='libopenjpeg_JPWL_la-openjpeg.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-openjpeg.lo `test -f '../openjpeg.c' || echo '$(srcdir)/'`../openjpeg.c + +libopenjpeg_JPWL_la-pi.lo: ../pi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-pi.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-pi.Tpo -c -o libopenjpeg_JPWL_la-pi.lo `test -f '../pi.c' || echo '$(srcdir)/'`../pi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-pi.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-pi.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../pi.c' object='libopenjpeg_JPWL_la-pi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-pi.lo `test -f '../pi.c' || echo '$(srcdir)/'`../pi.c + +libopenjpeg_JPWL_la-raw.lo: ../raw.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-raw.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-raw.Tpo -c -o libopenjpeg_JPWL_la-raw.lo `test -f '../raw.c' || echo '$(srcdir)/'`../raw.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-raw.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-raw.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../raw.c' object='libopenjpeg_JPWL_la-raw.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-raw.lo `test -f '../raw.c' || echo '$(srcdir)/'`../raw.c + +libopenjpeg_JPWL_la-t1.lo: ../t1.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-t1.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-t1.Tpo -c -o libopenjpeg_JPWL_la-t1.lo `test -f '../t1.c' || echo '$(srcdir)/'`../t1.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-t1.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-t1.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../t1.c' object='libopenjpeg_JPWL_la-t1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-t1.lo `test -f '../t1.c' || echo '$(srcdir)/'`../t1.c + +libopenjpeg_JPWL_la-t1_generate_luts.lo: ../t1_generate_luts.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-t1_generate_luts.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Tpo -c -o libopenjpeg_JPWL_la-t1_generate_luts.lo `test -f '../t1_generate_luts.c' || echo '$(srcdir)/'`../t1_generate_luts.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-t1_generate_luts.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../t1_generate_luts.c' object='libopenjpeg_JPWL_la-t1_generate_luts.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-t1_generate_luts.lo `test -f '../t1_generate_luts.c' || echo '$(srcdir)/'`../t1_generate_luts.c + +libopenjpeg_JPWL_la-t2.lo: ../t2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-t2.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-t2.Tpo -c -o libopenjpeg_JPWL_la-t2.lo `test -f '../t2.c' || echo '$(srcdir)/'`../t2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-t2.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-t2.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../t2.c' object='libopenjpeg_JPWL_la-t2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-t2.lo `test -f '../t2.c' || echo '$(srcdir)/'`../t2.c + +libopenjpeg_JPWL_la-tcd.lo: ../tcd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-tcd.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-tcd.Tpo -c -o libopenjpeg_JPWL_la-tcd.lo `test -f '../tcd.c' || echo '$(srcdir)/'`../tcd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-tcd.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-tcd.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../tcd.c' object='libopenjpeg_JPWL_la-tcd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-tcd.lo `test -f '../tcd.c' || echo '$(srcdir)/'`../tcd.c + +libopenjpeg_JPWL_la-tgt.lo: ../tgt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-tgt.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-tgt.Tpo -c -o libopenjpeg_JPWL_la-tgt.lo `test -f '../tgt.c' || echo '$(srcdir)/'`../tgt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-tgt.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-tgt.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../tgt.c' object='libopenjpeg_JPWL_la-tgt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-tgt.lo `test -f '../tgt.c' || echo '$(srcdir)/'`../tgt.c + +libopenjpeg_JPWL_la-cidx_manager.lo: ../cidx_manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-cidx_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Tpo -c -o libopenjpeg_JPWL_la-cidx_manager.lo `test -f '../cidx_manager.c' || echo '$(srcdir)/'`../cidx_manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-cidx_manager.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../cidx_manager.c' object='libopenjpeg_JPWL_la-cidx_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-cidx_manager.lo `test -f '../cidx_manager.c' || echo '$(srcdir)/'`../cidx_manager.c + +libopenjpeg_JPWL_la-phix_manager.lo: ../phix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-phix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Tpo -c -o libopenjpeg_JPWL_la-phix_manager.lo `test -f '../phix_manager.c' || echo '$(srcdir)/'`../phix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-phix_manager.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../phix_manager.c' object='libopenjpeg_JPWL_la-phix_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-phix_manager.lo `test -f '../phix_manager.c' || echo '$(srcdir)/'`../phix_manager.c + +libopenjpeg_JPWL_la-ppix_manager.lo: ../ppix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-ppix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Tpo -c -o libopenjpeg_JPWL_la-ppix_manager.lo `test -f '../ppix_manager.c' || echo '$(srcdir)/'`../ppix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-ppix_manager.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ppix_manager.c' object='libopenjpeg_JPWL_la-ppix_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-ppix_manager.lo `test -f '../ppix_manager.c' || echo '$(srcdir)/'`../ppix_manager.c + +libopenjpeg_JPWL_la-thix_manager.lo: ../thix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-thix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Tpo -c -o libopenjpeg_JPWL_la-thix_manager.lo `test -f '../thix_manager.c' || echo '$(srcdir)/'`../thix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-thix_manager.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../thix_manager.c' object='libopenjpeg_JPWL_la-thix_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-thix_manager.lo `test -f '../thix_manager.c' || echo '$(srcdir)/'`../thix_manager.c + +libopenjpeg_JPWL_la-tpix_manager.lo: ../tpix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-tpix_manager.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Tpo -c -o libopenjpeg_JPWL_la-tpix_manager.lo `test -f '../tpix_manager.c' || echo '$(srcdir)/'`../tpix_manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-tpix_manager.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../tpix_manager.c' object='libopenjpeg_JPWL_la-tpix_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-tpix_manager.lo `test -f '../tpix_manager.c' || echo '$(srcdir)/'`../tpix_manager.c + +libopenjpeg_JPWL_la-crc.lo: crc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-crc.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-crc.Tpo -c -o libopenjpeg_JPWL_la-crc.lo `test -f 'crc.c' || echo '$(srcdir)/'`crc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-crc.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-crc.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crc.c' object='libopenjpeg_JPWL_la-crc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-crc.lo `test -f 'crc.c' || echo '$(srcdir)/'`crc.c + +libopenjpeg_JPWL_la-jpwl.lo: jpwl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jpwl.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Tpo -c -o libopenjpeg_JPWL_la-jpwl.lo `test -f 'jpwl.c' || echo '$(srcdir)/'`jpwl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jpwl.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='jpwl.c' object='libopenjpeg_JPWL_la-jpwl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jpwl.lo `test -f 'jpwl.c' || echo '$(srcdir)/'`jpwl.c + +libopenjpeg_JPWL_la-jpwl_lib.lo: jpwl_lib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-jpwl_lib.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Tpo -c -o libopenjpeg_JPWL_la-jpwl_lib.lo `test -f 'jpwl_lib.c' || echo '$(srcdir)/'`jpwl_lib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-jpwl_lib.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='jpwl_lib.c' object='libopenjpeg_JPWL_la-jpwl_lib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-jpwl_lib.lo `test -f 'jpwl_lib.c' || echo '$(srcdir)/'`jpwl_lib.c + +libopenjpeg_JPWL_la-rs.lo: rs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -MT libopenjpeg_JPWL_la-rs.lo -MD -MP -MF $(DEPDIR)/libopenjpeg_JPWL_la-rs.Tpo -c -o libopenjpeg_JPWL_la-rs.lo `test -f 'rs.c' || echo '$(srcdir)/'`rs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenjpeg_JPWL_la-rs.Tpo $(DEPDIR)/libopenjpeg_JPWL_la-rs.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='rs.c' object='libopenjpeg_JPWL_la-rs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenjpeg_JPWL_la_CPPFLAGS) $(CPPFLAGS) $(libopenjpeg_JPWL_la_CFLAGS) $(CFLAGS) -c -o libopenjpeg_JPWL_la-rs.lo `test -f 'rs.c' || echo '$(srcdir)/'`rs.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-data-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-data-hook install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +install-data-hook: + @echo -e " (LA)\t$(libdir)/libopenjpeg_JPWL.la" >> $(top_builddir)/report.txt +@BUILD_SHARED_TRUE@ @( $(call solist) ) >> $(top_builddir)/report.txt +@BUILD_STATIC_TRUE@ @echo -e " (A)\t$(base)/$(a)" >> $(top_builddir)/report.txt + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/README.txt b/openjpeg-dotnet/libopenjpeg/jpwl/README.txt new file mode 100644 index 0000000..66e9d5b --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/README.txt @@ -0,0 +1,136 @@ +=============================================================================== + JPEG2000 Part 11 (ISO/IEC 15444-11 JPWL) Software + + + + Version 20061213 +=============================================================================== + + + + + +1. Scope +============= + +This document describes the installation and use of the JPWL module in the framework of OpenJPEG library. + +This implementation has been developed from OpenJPEG implementation of JPEG2000 standard, and for this reason it is written in C language. + +If you find some bugs or if you have problems using the encoder/decoder, please send an e-mail to jpwl@diei.unipg.it + + +2. Installing the code +========================== + +The JPWL code is integrated with the standard OpenJPEG library and codecs: it is activated by setting the macro USE_JPWL to defined in the preprocessor configuration options of your preferred C compiler. + +2.1. Compiling the source code in Windows +------------------------------------------- + +The "jpwl" directory is already populated with a couple of Visual C++ 6.0 workspaces + + * JPWL_image_to_j2k.dsw - Creates the encoder with JPWL functionalities + * JPWL_j2k_to_image.dsw - Creates the decoder with JPWL functionalities + +2.2. Compiling the source code in Unix-like systems +----------------------------------------------------- + +Under linux, enter the jpwl directory and type "make clean" and "make". + + +3. Running the JPWL software +========================= + +The options available at the command line are exactly the same of the base OpenJPEG codecs. In addition, there is a "-W" switch that activates JPWL functionalities. + +3.1. JPWL Encoder +------------------- + +-W : adoption of JPWL (Part 11) capabilities (-W params) + The parameters can be written and repeated in any order: + [h<=type>,s<=method>,a=,z=,g=,... + ...,p<=type>] + + h selects the header error protection (EPB): 'type' can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if 'tile' is absent, it applies to main and tile headers + if 'tile' is present, it applies from that tile + onwards, up to the next h spec, or to the last tile + in the codestream (max. 16 specs) + + p selects the packet error protection (EEP/UEP with EPBs) + to be applied to raw data: 'type' can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if 'tile:pack' is absent, it starts from tile 0, packet 0 + if 'tile:pack' is present, it applies from that tile + and that packet onwards, up to the next packet spec + or to the last packet in the last tile in the codestream + (max. 16 specs) + + s enables sensitivity data insertion (ESD): 'method' can be + [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR + 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED] + if 'tile' is absent, it applies to main header only + if 'tile' is present, it applies from that tile + onwards, up to the next s spec, or to the last tile + in the codestream (max. 16 specs) + + g determines the addressing mode: can be + [0=PACKET 1=BYTE RANGE 2=PACKET RANGE] + + a determines the size of data addressing: can be + 2/4 bytes (small/large codestreams). If not set, auto-mode + + z determines the size of sensitivity values: can be + 1/2 bytes, for the transformed pseudo-floating point value + + ex.: + h,h0=64,h3=16,h5=32,p0=78,p0:24=56,p1,p3:0=0,p3:20=32,s=0,s0=6,s3=-1,a=0,g=1,z=1 + means + predefined EPB in MH, rs(64,32) from TPH 0 to TPH 2, + CRC-16 in TPH 3 and TPH 4, CRC-32 in remaining TPHs, + UEP rs(78,32) for packets 0 to 23 of tile 0, + UEP rs(56,32) for packets 24 to the last of tile 0, + UEP rs default for packets of tile 1, + no UEP for packets 0 to 19 of tile 3, + UEP CRC-32 for packets 20 of tile 3 to last tile, + relative sensitivity ESD for MH, + TSE ESD from TPH 0 to TPH 2, byte range with automatic + size of addresses and 1 byte for each sensitivity value + + ex.: + h,s,p + means + default protection to headers (MH and TPHs) as well as + data packets, one ESD in MH + + N.B.: use the following recommendations when specifying + the JPWL parameters list + - when you use UEP, always pair the 'p' option with 'h' + +3.2. JPWL Decoder +------------------- + + -W + Activates the JPWL correction capability, if the codestream complies. + Options can be a comma separated list of tokens: + c, c=numcomps + numcomps is the number of expected components in the codestream + (search of first EPB rely upon this, default is 3) + + +4. Known bugs and limitations +=============================== + +4.1. Bugs +----------- + +* It is not possible to save a JPWL encoded codestream using the wrapped file format (i.e. JP2): only raw file format (i.e. J2K) is working + +4.2. Limitations +------------------ + +* When specifying an UEP protection, you need to activate even TPH protection for those tiles where there is a protection of the packets +* RED insertion is not currently implemented at the decoder +* JPWL at entropy coding level is not implemented diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/crc.c b/openjpeg-dotnet/libopenjpeg/jpwl/crc.c new file mode 100644 index 0000000..f65e4e1 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/crc.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef USE_JPWL + +#include "crc.h" + +/** +@file crc.c +@brief Functions used to compute the 16- and 32-bit CRC of byte arrays + +*/ + +/** file: CRC16.CPP + * + * CRC - Cyclic Redundancy Check (16-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC16 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +const unsigned short CRC16_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void updateCRC16(unsigned short *crc, unsigned char data) { + *crc = CRC16_table[(*crc >> 8) & 0xFF] ^ (*crc << 8) ^ data; +}; + + +/** file: CRC32.CPP + * + * CRC - Cyclic Redundancy Check (32-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned long), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC32 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +const unsigned long CRC32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +void updateCRC32(unsigned long *crc, unsigned char data) { + *crc = CRC32_table[(unsigned char) *crc ^ data] ^ ((*crc >> 8) & 0x00FFFFFF); +}; + +#endif /* USE_JPWL */ diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/crc.h b/openjpeg-dotnet/libopenjpeg/jpwl/crc.h new file mode 100644 index 0000000..4ea2c4c --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/crc.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef USE_JPWL + +/** +@file crc.h +@brief Functions used to compute the 16- and 32-bit CRC of byte arrays + +*/ + +#ifndef __CRC16_HEADER__ +#define __CRC16_HEADER__ + +/** file: CRC16.HPP + * + * CRC - Cyclic Redundancy Check (16-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC16 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +void updateCRC16(unsigned short *, unsigned char); + +#endif /* __CRC16_HEADER__ */ + + +#ifndef __CRC32_HEADER__ +#define __CRC32_HEADER__ + +/** file: CRC32.HPP + * + * CRC - Cyclic Redundancy Check (32-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC32 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +void updateCRC32(unsigned long *, unsigned char); + +#endif /* __CRC32_HEADER__ */ + + +#endif /* USE_JPWL */ diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/jpwl.c b/openjpeg-dotnet/libopenjpeg/jpwl/jpwl.c new file mode 100644 index 0000000..4247f75 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/jpwl.c @@ -0,0 +1,1358 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +#ifdef USE_JPWL + +/** @defgroup JPWL JPWL - JPEG-2000 Part11 (JPWL) codestream manager */ +/*@{*/ + +/** @name Local static variables */ +/*@{*/ + +/** number of JPWL prepared markers */ +static int jwmarker_num; +/** properties of JPWL markers to insert */ +static jpwl_marker_t jwmarker[JPWL_MAX_NO_MARKERS]; + +/*@}*/ + +/*@}*/ + +/** @name Local static functions */ +/*@{*/ + +/** create an EPC marker segment +@param j2k J2K compressor handle +@param esd_on true if ESD is activated +@param red_on true if RED is activated +@param epb_on true if EPB is activated +@param info_on true if informative techniques are activated +@return returns the freshly created EPC +*/ +jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, opj_bool esd_on, opj_bool red_on, opj_bool epb_on, opj_bool info_on); + +/*@}*/ + +/** create an EPC marker segment +@param j2k J2K compressor handle +@param comps considered component (-1=average, 0/1/2/...=component no.) +@param addrm addressing mode (0=packet, 1=byte range, 2=packet range, 3=reserved) +@param ad_size size of addresses (2/4 bytes) +@param senst sensitivity type +@param se_size sensitivity values size (1/2 bytes) +@param tileno tile where this ESD lies (-1 means MH) +@param svalnum number of sensitivity values (if 0, they will be automatically filled) +@param sensval pointer to an array of sensitivity values (if NULL, they will be automatically filled) +@return returns the freshly created ESD +*/ +jpwl_esd_ms_t *jpwl_esd_create(opj_j2k_t *j2k, int comps, + unsigned char addrm, unsigned char ad_size, + unsigned char senst, int se_size, int tileno, + unsigned long int svalnum, void *sensval); + +/** this function is used to compare two JPWL markers based on +their relevant wishlist position +@param arg1 pointer to first marker +@param arg2 pointer to second marker +@return 1 if arg1>arg2, 0 if arg1=arg2, -1 if arg1pos_correction = 0; + +} + +void j2k_add_marker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) { + + if (!cstr_info) + return; + + /* expand the list? */ + if ((cstr_info->marknum + 1) > cstr_info->maxmarknum) { + cstr_info->maxmarknum += 100; + cstr_info->marker = (opj_marker_info_t*)opj_realloc(cstr_info->marker, cstr_info->maxmarknum * sizeof(opj_marker_info_t)); + } + + /* add the marker */ + cstr_info->marker[cstr_info->marknum].type = type; + cstr_info->marker[cstr_info->marknum].pos = pos; + cstr_info->marker[cstr_info->marknum].len = len; + cstr_info->marknum++; + +} + +void jpwl_prepare_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image) { + + unsigned short int socsiz_len = 0; + int ciopos = cio_tell(cio), soc_pos = j2k->cstr_info->main_head_start; + unsigned char *socp = NULL; + + int tileno, acc_tpno, tpno, tilespec, hprot, sens, pprot, packspec, lastileno, packno; + + jpwl_epb_ms_t *epb_mark; + jpwl_epc_ms_t *epc_mark; + jpwl_esd_ms_t *esd_mark; + + /* find (SOC + SIZ) length */ + /* I assume SIZ is always the first marker after SOC */ + cio_seek(cio, soc_pos + 4); + socsiz_len = (unsigned short int) cio_read(cio, 2) + 4; /* add the 2 marks length itself */ + cio_seek(cio, soc_pos + 0); + socp = cio_getbp(cio); /* pointer to SOC */ + + /* + EPC MS for Main Header: if we are here it's required + */ + /* create the EPC */ + if ((epc_mark = jpwl_epc_create( + j2k, + j2k->cp->esd_on, /* is ESD present? */ + j2k->cp->red_on, /* is RED present? */ + j2k->cp->epb_on, /* is EPB present? */ + OPJ_FALSE /* are informative techniques present? */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (epc_mark) { + jwmarker[jwmarker_num].id = J2K_MS_EPC; /* its type */ + jwmarker[jwmarker_num].m.epcmark = epc_mark; /* the EPC */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.1; /* not so first */ + jwmarker[jwmarker_num].len = epc_mark->Lepc; /* its length */ + jwmarker[jwmarker_num].len_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].pos_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].parms_ready = OPJ_FALSE; /* not ready */ + jwmarker[jwmarker_num].data_ready = OPJ_TRUE; /* ready */ + jwmarker_num++; + }; + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH EPC : setting %s%s%s\n", + j2k->cp->esd_on ? "ESD, " : "", + j2k->cp->red_on ? "RED, " : "", + j2k->cp->epb_on ? "EPB, " : "" + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH EPC\n"); + }; + + /* + ESD MS for Main Header + */ + /* first of all, must MH have an ESD MS? */ + if (j2k->cp->esd_on && (j2k->cp->sens_MH >= 0)) { + + /* Create the ESD */ + if ((esd_mark = jpwl_esd_create( + j2k, /* this encoder handle */ + -1, /* we are averaging over all components */ + (unsigned char) j2k->cp->sens_range, /* range method */ + (unsigned char) j2k->cp->sens_addr, /* sensitivity addressing */ + (unsigned char) j2k->cp->sens_MH, /* sensitivity method */ + j2k->cp->sens_size, /* sensitivity size */ + -1, /* this ESD is in main header */ + 0 /*j2k->cstr_info->num*/, /* number of packets in codestream */ + NULL /*sensval*/ /* pointer to sensitivity data of packets */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_ESD; /* its type */ + jwmarker[jwmarker_num].m.esdmark = esd_mark; /* the EPB */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* we choose to place it after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.2; /* not first at all! */ + jwmarker[jwmarker_num].len = esd_mark->Lesd; /* its length */ + jwmarker[jwmarker_num].len_ready = OPJ_TRUE; /* not ready, yet */ + jwmarker[jwmarker_num].pos_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].parms_ready = OPJ_TRUE; /* not ready */ + jwmarker[jwmarker_num].data_ready = OPJ_FALSE; /* not ready */ + jwmarker_num++; + } + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH ESDs: method %d\n", + j2k->cp->sens_MH + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH ESD\n"); + }; + + } + + /* + ESD MSs for Tile Part Headers + */ + /* cycle through tiles */ + sens = -1; /* default spec: no ESD */ + tilespec = 0; /* first tile spec */ + acc_tpno = 0; + for (tileno = 0; tileno < j2k->cstr_info->tw * j2k->cstr_info->th; tileno++) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + "Tile %d has %d tile part(s)\n", + tileno, j2k->cstr_info->tile[tileno].num_tps + ); + + /* for every tile part in the tile */ + for (tpno = 0; tpno < j2k->cstr_info->tile[tileno].num_tps; tpno++, acc_tpno++) { + + int sot_len, Psot, Psotp, mm; + unsigned long sot_pos, post_sod_pos; + + unsigned long int left_THmarks_len; + + /******* sot_pos = j2k->cstr_info->tile[tileno].start_pos; */ + sot_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos; + cio_seek(cio, sot_pos + 2); + sot_len = cio_read(cio, 2); /* SOT Len */ + cio_skip(cio, 2); + Psotp = cio_tell(cio); + Psot = cio_read(cio, 4); /* tile length */ + + /******* post_sod_pos = j2k->cstr_info->tile[tileno].end_header + 1; */ + post_sod_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_end_header + 1; + left_THmarks_len = post_sod_pos - sot_pos; + + /* add all the lengths of the markers which are len-ready and stay within SOT and SOD */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >= sot_pos) && (jwmarker[mm].pos < post_sod_pos)) { + if (jwmarker[mm].len_ready) + left_THmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up TH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /******* if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->sens_TPH_tileno[tilespec] == tileno)) */ + if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->sens_TPH_tileno[tilespec] == acc_tpno)) + /* we got a specification from this tile onwards */ + sens = j2k->cp->sens_TPH[tilespec++]; + + /* must this TPH have an ESD MS? */ + if (j2k->cp->esd_on && (sens >= 0)) { + + /* Create the ESD */ + if ((esd_mark = jpwl_esd_create( + j2k, /* this encoder handle */ + -1, /* we are averaging over all components */ + (unsigned char) j2k->cp->sens_range, /* range method */ + (unsigned char) j2k->cp->sens_addr, /* sensitivity addressing size */ + (unsigned char) sens, /* sensitivity method */ + j2k->cp->sens_size, /* sensitivity value size */ + tileno, /* this ESD is in a tile */ + 0, /* number of packets in codestream */ + NULL /* pointer to sensitivity data of packets */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_ESD; /* its type */ + jwmarker[jwmarker_num].m.esdmark = esd_mark; /* the EPB */ + /****** jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].start_pos + sot_len + 2; */ /* after SOT */ + jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2; /* after SOT */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.2; /* not first at all! */ + jwmarker[jwmarker_num].len = esd_mark->Lesd; /* its length */ + jwmarker[jwmarker_num].len_ready = OPJ_TRUE; /* ready, yet */ + jwmarker[jwmarker_num].pos_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].parms_ready = OPJ_TRUE; /* not ready */ + jwmarker[jwmarker_num].data_ready = OPJ_FALSE; /* ready */ + jwmarker_num++; + } + + /* update Psot of the tile */ + cio_seek(cio, Psotp); + cio_write(cio, Psot + esd_mark->Lesd + 2, 4); + + opj_event_msg(j2k->cinfo, EVT_INFO, + /******* "TPH ESDs: tile %02d, method %d\n", */ + "TPH ESDs: tile %02d, part %02d, method %d\n", + /******* tileno, */ + tileno, tpno, + sens + ); + + } else { + /* ooops, problems */ + /***** opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH ESD #%d\n", tileno); */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH ESD #%d,%d\n", tileno, tpno); + }; + + } + + } + + }; + + /* + EPB MS for Main Header + */ + /* first of all, must MH have an EPB MS? */ + if (j2k->cp->epb_on && (j2k->cp->hprot_MH > 0)) { + + int mm; + + /* position of SOT */ + unsigned int sot_pos = j2k->cstr_info->main_head_end + 1; + + /* how much space is there between end of SIZ and beginning of SOT? */ + int left_MHmarks_len = sot_pos - socsiz_len; + + /* add all the lengths of the markers which are len-ready and stay within SOC and SOT */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >=0) && (jwmarker[mm].pos < sot_pos)) { + if (jwmarker[mm].len_ready) + left_MHmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up MH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /* Create the EPB */ + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + OPJ_TRUE, /* is it the latest? */ + OPJ_TRUE, /* is it packed? not for now */ + -1, /* we are in main header */ + 0, /* its index is 0 (first) */ + j2k->cp->hprot_MH, /* protection type parameters of data */ + socsiz_len, /* pre-data: only SOC+SIZ */ + left_MHmarks_len /* post-data: from SOC to SOT, and all JPWL markers within */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos; /* first first first! */ + jwmarker[jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[jwmarker_num].len_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].pos_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].parms_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].data_ready = OPJ_FALSE; /* not ready */ + jwmarker_num++; + } + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH EPB : prot. %d\n", + j2k->cp->hprot_MH + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH EPB\n"); + }; + } + + /* + EPB MSs for Tile Parts + */ + /* cycle through TPHs */ + hprot = j2k->cp->hprot_MH; /* default spec */ + tilespec = 0; /* first tile spec */ + lastileno = 0; + packspec = 0; + pprot = -1; + acc_tpno = 0; + for (tileno = 0; tileno < j2k->cstr_info->tw * j2k->cstr_info->th; tileno++) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + "Tile %d has %d tile part(s)\n", + tileno, j2k->cstr_info->tile[tileno].num_tps + ); + + /* for every tile part in the tile */ + for (tpno = 0; tpno < j2k->cstr_info->tile[tileno].num_tps; tpno++, acc_tpno++) { + + int sot_len, Psot, Psotp, mm, epb_index = 0, prot_len = 0; + unsigned long sot_pos, post_sod_pos; + unsigned long int left_THmarks_len/*, epbs_len = 0*/; + int startpack = 0, stoppack = j2k->cstr_info->packno; + int first_tp_pack, last_tp_pack; + jpwl_epb_ms_t *tph_epb = NULL; + + /****** sot_pos = j2k->cstr_info->tile[tileno].start_pos; */ + sot_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos; + cio_seek(cio, sot_pos + 2); + sot_len = cio_read(cio, 2); /* SOT Len */ + cio_skip(cio, 2); + Psotp = cio_tell(cio); + Psot = cio_read(cio, 4); /* tile length */ + + /* a-priori length of the data dwelling between SOT and SOD */ + /****** post_sod_pos = j2k->cstr_info->tile[tileno].end_header + 1; */ + post_sod_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_end_header + 1; + left_THmarks_len = post_sod_pos - (sot_pos + sot_len + 2); + + /* add all the lengths of the JPWL markers which are len-ready and stay within SOT and SOD */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >= sot_pos) && (jwmarker[mm].pos < post_sod_pos)) { + if (jwmarker[mm].len_ready) + left_THmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up TH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /****** if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->hprot_TPH_tileno[tilespec] == tileno)) */ + if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->hprot_TPH_tileno[tilespec] == acc_tpno)) + /* we got a specification from this tile part onwards */ + hprot = j2k->cp->hprot_TPH[tilespec++]; + + /* must this TPH have an EPB MS? */ + if (j2k->cp->epb_on && (hprot > 0)) { + + /* Create the EPB */ + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + OPJ_FALSE, /* is it the latest? in TPH, no for now (if huge data size in TPH, we'd need more) */ + OPJ_TRUE, /* is it packed? yes for now */ + tileno, /* we are in TPH */ + epb_index++, /* its index is 0 (first) */ + hprot, /* protection type parameters of following data */ + sot_len + 2, /* pre-data length: only SOT */ + left_THmarks_len /* post-data length: from SOT end to SOD inclusive */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + /****** jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].start_pos + sot_len + 2; */ /* after SOT */ + jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2; /* after SOT */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos; /* first first first! */ + jwmarker[jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[jwmarker_num].len_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].pos_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].parms_ready = OPJ_TRUE; /* ready */ + jwmarker[jwmarker_num].data_ready = OPJ_FALSE; /* not ready */ + jwmarker_num++; + } + + /* update Psot of the tile */ + Psot += epb_mark->Lepb + 2; + + opj_event_msg(j2k->cinfo, EVT_INFO, + /***** "TPH EPB : tile %02d, prot. %d\n", */ + "TPH EPB : tile %02d, part %02d, prot. %d\n", + /***** tileno, */ + tileno, tpno, + hprot + ); + + /* save this TPH EPB address */ + tph_epb = epb_mark; + + } else { + /* ooops, problems */ + /****** opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB #%d\n", tileno); */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB in #%d,d\n", tileno, tpno); + }; + + } + + startpack = 0; + /* EPB MSs for UEP packet data protection in Tile Parts */ + /****** for (packno = 0; packno < j2k->cstr_info->num; packno++) { */ + /*first_tp_pack = (tpno > 0) ? (first_tp_pack + j2k->cstr_info->tile[tileno].tp[tpno - 1].tp_numpacks) : 0;*/ + first_tp_pack = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pack; + last_tp_pack = first_tp_pack + j2k->cstr_info->tile[tileno].tp[tpno].tp_numpacks - 1; + for (packno = 0; packno < j2k->cstr_info->tile[tileno].tp[tpno].tp_numpacks; packno++) { + + /******** if ((packspec < JPWL_MAX_NO_PACKSPECS) && + (j2k->cp->pprot_tileno[packspec] == tileno) && (j2k->cp->pprot_packno[packspec] == packno)) { */ + if ((packspec < JPWL_MAX_NO_PACKSPECS) && + (j2k->cp->pprot_tileno[packspec] == acc_tpno) && (j2k->cp->pprot_packno[packspec] == packno)) { + + /* we got a specification from this tile and packet onwards */ + /* print the previous spec */ + if (packno > 0) { + stoppack = packno - 1; + opj_event_msg(j2k->cinfo, EVT_INFO, + /***** "UEP EPBs: tile %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", */ + "UEP EPBs: tile %02d, part %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", + /***** tileno, */ + tileno, tpno, + startpack, + stoppack, + /***** j2k->cstr_info->tile[tileno].packet[startpack].start_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos, + /***** j2k->cstr_info->tile[tileno].packet[stoppack].end_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos, + pprot); + + /***** prot_len = j2k->cstr_info->tile[tileno].packet[stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[startpack].start_pos; */ + prot_len = j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos; + + /* + particular case: if this is the last header and the last packet, + then it is better to protect even the EOC marker + */ + /****** if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (stoppack == (j2k->cstr_info->num - 1))) */ + if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (tpno == (j2k->cstr_info->tile[tileno].num_tps - 1)) && + (stoppack == last_tp_pack)) + /* add the EOC len */ + prot_len += 2; + + /* let's add the EPBs */ + Psot += jpwl_epbs_add( + j2k, /* J2K handle */ + jwmarker, /* pointer to JPWL markers list */ + &jwmarker_num, /* pointer to the number of current markers */ + OPJ_FALSE, /* latest */ + OPJ_TRUE, /* packed */ + OPJ_FALSE, /* inside MH */ + &epb_index, /* pointer to EPB index */ + pprot, /* protection type */ + /****** (double) (j2k->cstr_info->tile[tileno].start_pos + sot_len + 2) + 0.0001, */ /* position */ + (double) (j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2) + 0.0001, /* position */ + tileno, /* number of tile */ + 0, /* length of pre-data */ + prot_len /*4000*/ /* length of post-data */ + ); + } + + startpack = packno; + pprot = j2k->cp->pprot[packspec++]; + } + + //printf("Tile %02d, pack %02d ==> %d\n", tileno, packno, pprot); + + } + + /* we are at the end: print the remaining spec */ + stoppack = packno - 1; + if (pprot >= 0) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + /**** "UEP EPBs: tile %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", */ + "UEP EPBs: tile %02d, part %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", + /**** tileno, */ + tileno, tpno, + startpack, + stoppack, + /***** j2k->image_info->tile[tileno].packet[startpack].start_pos, + j2k->image_info->tile[tileno].packet[stoppack].end_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos, + j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos, + pprot); + + /***** prot_len = j2k->cstr_info->tile[tileno].packet[stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[startpack].start_pos; */ + prot_len = j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos; + + /* + particular case: if this is the last header and the last packet, + then it is better to protect even the EOC marker + */ + /***** if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (stoppack == (j2k->cstr_info->num - 1))) */ + if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (tpno == (j2k->cstr_info->tile[tileno].num_tps - 1)) && + (stoppack == last_tp_pack)) + /* add the EOC len */ + prot_len += 2; + + /* let's add the EPBs */ + Psot += jpwl_epbs_add( + j2k, /* J2K handle */ + jwmarker, /* pointer to JPWL markers list */ + &jwmarker_num, /* pointer to the number of current markers */ + OPJ_TRUE, /* latest */ + OPJ_TRUE, /* packed */ + OPJ_FALSE, /* inside MH */ + &epb_index, /* pointer to EPB index */ + pprot, /* protection type */ + /***** (double) (j2k->cstr_info->tile[tileno].start_pos + sot_len + 2) + 0.0001,*/ /* position */ + (double) (j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2) + 0.0001, /* position */ + tileno, /* number of tile */ + 0, /* length of pre-data */ + prot_len /*4000*/ /* length of post-data */ + ); + } + + /* we can now check if the TPH EPB was really the last one */ + if (tph_epb && (epb_index == 1)) { + /* set the TPH EPB to be the last one in current header */ + tph_epb->Depb |= (unsigned char) ((OPJ_TRUE & 0x0001) << 6); + tph_epb = NULL; + } + + /* write back Psot */ + cio_seek(cio, Psotp); + cio_write(cio, Psot, 4); + + } + + }; + + /* reset the position */ + cio_seek(cio, ciopos); + +} + +void jpwl_dump_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image) { + + int mm; + unsigned long int old_size = j2k->cstr_info->codestream_size; + unsigned long int new_size = old_size; + int /*ciopos = cio_tell(cio),*/ soc_pos = j2k->cstr_info->main_head_start; + unsigned char *jpwl_buf, *orig_buf; + unsigned long int orig_pos; + double epbcoding_time = 0.0, esdcoding_time = 0.0; + + /* Order JPWL markers according to their wishlist position */ + qsort((void *) jwmarker, (size_t) jwmarker_num, sizeof (jpwl_marker_t), jpwl_markcomp); + + /* compute markers total size */ + for (mm = 0; mm < jwmarker_num; mm++) { + /*printf("%x, %d, %.10f, %d long\n", jwmarker[mm].id, jwmarker[mm].pos, + jwmarker[mm].dpos, jwmarker[mm].len);*/ + new_size += jwmarker[mm].len + 2; + } + + /* allocate a new buffer of proper size */ + if (!(jpwl_buf = (unsigned char *) opj_malloc((size_t) (new_size + soc_pos) * sizeof(unsigned char)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for JPWL codestream buffer\n"); + exit(1); + }; + + /* copy the jp2 part, if any */ + orig_buf = jpwl_buf; + memcpy(jpwl_buf, cio->buffer, soc_pos); + jpwl_buf += soc_pos; + + /* cycle through markers */ + orig_pos = soc_pos + 0; /* start from the beginning */ + cio_seek(cio, soc_pos + 0); /* rewind the original */ + for (mm = 0; mm < jwmarker_num; mm++) { + + /* + need to copy a piece of the original codestream + if there is such + */ + memcpy(jpwl_buf, cio_getbp(cio), jwmarker[mm].pos - orig_pos); + jpwl_buf += jwmarker[mm].pos - orig_pos; + orig_pos = jwmarker[mm].pos; + cio_seek(cio, orig_pos); + + /* + then write down the marker + */ + switch (jwmarker[mm].id) { + + case J2K_MS_EPB: + jpwl_epb_write(j2k, jwmarker[mm].m.epbmark, jpwl_buf); + break; + + case J2K_MS_EPC: + jpwl_epc_write(j2k, jwmarker[mm].m.epcmark, jpwl_buf); + break; + + case J2K_MS_ESD: + jpwl_esd_write(j2k, jwmarker[mm].m.esdmark, jpwl_buf); + break; + + case J2K_MS_RED: + memset(jpwl_buf, 0, jwmarker[mm].len + 2); /* placeholder */ + break; + + default: + break; + }; + + /* we update the markers struct */ + if (j2k->cstr_info) + j2k->cstr_info->marker[j2k->cstr_info->marknum - 1].pos = (jpwl_buf - orig_buf); + + /* we set the marker dpos to the new position in the JPWL codestream */ + jwmarker[mm].dpos = (double) (jpwl_buf - orig_buf); + + /* advance JPWL buffer position */ + jpwl_buf += jwmarker[mm].len + 2; + + } + + /* finish remaining original codestream */ + memcpy(jpwl_buf, cio_getbp(cio), old_size - (orig_pos - soc_pos)); + jpwl_buf += old_size - (orig_pos - soc_pos); + cio_seek(cio, soc_pos + old_size); + + /* + update info file based on added markers + */ + if (!jpwl_update_info(j2k, jwmarker, jwmarker_num)) + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not update OPJ cstr_info structure\n"); + + /* now we need to repass some markers and fill their data fields */ + + /* first of all, DL and Pcrc in EPCs */ + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the EPCs */ + if (jwmarker[mm].id == J2K_MS_EPC) { + + int epc_pos = (int) jwmarker[mm].dpos, pp; + unsigned short int mycrc = 0x0000; + + /* fix and fill the DL field */ + jwmarker[mm].m.epcmark->DL = new_size; + orig_buf[epc_pos + 6] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 24); + orig_buf[epc_pos + 7] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 16); + orig_buf[epc_pos + 8] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 8); + orig_buf[epc_pos + 9] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 0); + + /* compute the CRC field (excluding itself) */ + for (pp = 0; pp < 4; pp++) + jpwl_updateCRC16(&mycrc, orig_buf[epc_pos + pp]); + for (pp = 6; pp < (jwmarker[mm].len + 2); pp++) + jpwl_updateCRC16(&mycrc, orig_buf[epc_pos + pp]); + + /* fix and fill the CRC */ + jwmarker[mm].m.epcmark->Pcrc = mycrc; + orig_buf[epc_pos + 4] = (unsigned char) (jwmarker[mm].m.epcmark->Pcrc >> 8); + orig_buf[epc_pos + 5] = (unsigned char) (jwmarker[mm].m.epcmark->Pcrc >> 0); + + } + } + + /* then, sensitivity data in ESDs */ + esdcoding_time = opj_clock(); + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the ESDs */ + if (jwmarker[mm].id == J2K_MS_ESD) { + + /* remember that they are now in a new position (dpos) */ + int esd_pos = (int) jwmarker[mm].dpos; + + jpwl_esd_fill(j2k, jwmarker[mm].m.esdmark, &orig_buf[esd_pos]); + + } + + } + esdcoding_time = opj_clock() - esdcoding_time; + if (j2k->cp->esd_on) + opj_event_msg(j2k->cinfo, EVT_INFO, "ESDs sensitivities computed in %f s\n", esdcoding_time); + + /* finally, RS or CRC parity in EPBs */ + epbcoding_time = opj_clock(); + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the EPBs */ + if (jwmarker[mm].id == J2K_MS_EPB) { + + /* remember that they are now in a new position (dpos) */ + int nn, accum_len; + + /* let's see how many EPBs are following this one, included itself */ + /* for this to work, we suppose that the markers are correctly ordered */ + /* and, overall, that they are in packed mode inside headers */ + accum_len = 0; + for (nn = mm; (nn < jwmarker_num) && (jwmarker[nn].id == J2K_MS_EPB) && + (jwmarker[nn].pos == jwmarker[mm].pos); nn++) + accum_len += jwmarker[nn].m.epbmark->Lepb + 2; + + /* fill the current (first) EPB with post-data starting from the computed position */ + jpwl_epb_fill(j2k, jwmarker[mm].m.epbmark, &orig_buf[(int) jwmarker[mm].dpos], + &orig_buf[(int) jwmarker[mm].dpos + accum_len]); + + /* fill the remaining EPBs in the header with post-data starting from the last position */ + for (nn = mm + 1; (nn < jwmarker_num) && (jwmarker[nn].id == J2K_MS_EPB) && + (jwmarker[nn].pos == jwmarker[mm].pos); nn++) + jpwl_epb_fill(j2k, jwmarker[nn].m.epbmark, &orig_buf[(int) jwmarker[nn].dpos], NULL); + + /* skip all the processed EPBs */ + mm = nn - 1; + } + + } + epbcoding_time = opj_clock() - epbcoding_time; + if (j2k->cp->epb_on) + opj_event_msg(j2k->cinfo, EVT_INFO, "EPBs redundancy computed in %f s\n", epbcoding_time); + + /* free original cio buffer and set it to the JPWL one */ + opj_free(cio->buffer); + cio->cinfo = cio->cinfo; /* no change */ + cio->openmode = cio->openmode; /* no change */ + cio->buffer = orig_buf; + cio->length = new_size + soc_pos; + cio->start = cio->buffer; + cio->end = cio->buffer + cio->length; + cio->bp = cio->buffer; + cio_seek(cio, soc_pos + new_size); + +} + + +void j2k_read_epc(opj_j2k_t *j2k) { + unsigned long int DL, Lepcp, Pcrcp, l; + unsigned short int Lepc, Pcrc = 0x0000; + unsigned char Pepc; + opj_cio_t *cio = j2k->cio; + const char *ans1; + + /* Simply read the EPC parameters */ + Lepcp = cio_tell(cio); + Lepc = cio_read(cio, 2); + Pcrcp = cio_tell(cio); + cio_skip(cio, 2); /* Pcrc */ + DL = cio_read(cio, 4); + Pepc = cio_read(cio, 1); + + /* compute Pcrc */ + cio_seek(cio, Lepcp - 2); + + /* Marker */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* Length */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* skip Pcrc */ + cio_skip(cio, 2); + + /* read all remaining */ + for (l = 4; l < Lepc; l++) + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* check Pcrc with the result */ + cio_seek(cio, Pcrcp); + ans1 = (Pcrc == (unsigned short int) cio_read(cio, 2)) ? "crc-ok" : "crc-ko"; + + /* now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPC(%u,%d): %s, DL=%d%s %s %s\n", + Lepcp - 2, + Lepc, + ans1, + DL, /* data length this EPC is referring to */ + (Pepc & 0x10) ? ", esd" : "", /* ESD is present */ + (Pepc & 0x20) ? ", red" : "", /* RED is present */ + (Pepc & 0x40) ? ", epb" : ""); /* EPB is present */ + + cio_seek(cio, Lepcp + Lepc); +} + +void j2k_write_epc(opj_j2k_t *j2k) { + + unsigned long int DL, Lepcp, Pcrcp, l; + unsigned short int Lepc, Pcrc; + unsigned char Pepc; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_EPC, 2); /* EPC */ + Lepcp = cio_tell(cio); + cio_skip(cio, 2); + + /* CRC-16 word of the EPC */ + Pcrc = 0x0000; /* initialize */ + Pcrcp = cio_tell(cio); + cio_write(cio, Pcrc, 2); /* Pcrc placeholder*/ + + /* data length of the EPC protection domain */ + DL = 0x00000000; /* we leave this set to 0, as if the information is not available */ + cio_write(cio, DL, 4); /* DL */ + + /* jpwl capabilities */ + Pepc = 0x00; + cio_write(cio, Pepc, 1); /* Pepc */ + + /* ID section */ + /* no ID's, as of now */ + + Lepc = (unsigned short) (cio_tell(cio) - Lepcp); + cio_seek(cio, Lepcp); + cio_write(cio, Lepc, 2); /* Lepc */ + + /* compute Pcrc */ + cio_seek(cio, Lepcp - 2); + + /* Marker */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* Length */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* skip Pcrc */ + cio_skip(cio, 2); + + /* read all remaining */ + for (l = 4; l < Lepc; l++) + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* fill Pcrc with the result */ + cio_seek(cio, Pcrcp); + cio_write(cio, Pcrc, 2); + + cio_seek(cio, Lepcp + Lepc); + + /* marker struct update */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPC, Lepcp - 2, Lepc + 2); + +} + +void j2k_read_epb(opj_j2k_t *j2k) { + unsigned long int LDPepb, Pepb; + unsigned short int Lepb; + unsigned char Depb; + char str1[25] = ""; + opj_bool status; + static opj_bool first_in_tph = OPJ_TRUE; + int type, pre_len, post_len; + static unsigned char *redund = NULL; + + opj_cio_t *cio = j2k->cio; + + /* B/W = 45, RGB = 51 */ + /* SIZ SIZ_FIELDS SIZ_COMPS FOLLOWING_MARKER */ + int skipnum = 2 + 38 + 3 * j2k->cp->exp_comps + 2; + + if (j2k->cp->correct) { + + /* go back to EPB marker value */ + cio_seek(cio, cio_tell(cio) - 2); + + /* we need to understand where we are */ + if (j2k->state == J2K_STATE_MH) { + /* we are in MH */ + type = 0; /* MH */ + pre_len = skipnum; /* SOC+SIZ */ + post_len = -1; /* auto */ + + } else if ((j2k->state == J2K_STATE_TPH) && first_in_tph) { + /* we are in TPH */ + type = 1; /* TPH */ + pre_len = 12; /* SOC+SIZ */ + first_in_tph = OPJ_FALSE; + post_len = -1; /* auto */ + + } else { + /* we are elsewhere */ + type = 2; /* other */ + pre_len = 0; /* nada */ + post_len = -1; /* auto */ + + } + + /* call EPB corrector */ + /*printf("before %x, ", redund);*/ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + type, /* EPB type: MH */ + pre_len, /* length of pre-data */ + post_len, /* length of post-data: -1 means auto */ + NULL, /* do everything auto */ + &redund + ); + /*printf("after %x\n", redund);*/ + + /* Read the (possibly corrected) EPB parameters */ + cio_skip(cio, 2); + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + if (!status) { + + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL correction could not be performed\n"); + + /* advance to EPB endpoint */ + cio_skip(cio, Lepb + 2); + + return; + } + + /* last in current header? */ + if (Depb & 0x40) { + redund = NULL; /* reset the pointer to L4 buffer */ + first_in_tph = OPJ_TRUE; + } + + /* advance to EPB endpoint */ + cio_skip(cio, Lepb - 11); + + } else { + + /* Simply read the EPB parameters */ + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + /* What does Pepb tells us about the protection method? */ + if (((Pepb & 0xF0000000) >> 28) == 0) + sprintf(str1, "pred"); /* predefined */ + else if (((Pepb & 0xF0000000) >> 28) == 1) + sprintf(str1, "crc-%lu", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */ + else if (((Pepb & 0xF0000000) >> 28) == 2) + sprintf(str1, "rs(%lu,32)", (Pepb & 0x0000FF00) >> 8); /* RS mode */ + else if (Pepb == 0xFFFFFFFF) + sprintf(str1, "nometh"); /* RS mode */ + else + sprintf(str1, "unknown"); /* unknown */ + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPB(%d): (%sl, %sp, %u), %lu, %s\n", + cio_tell(cio) - 13, + (Depb & 0x40) ? "" : "n", /* latest EPB or not? */ + (Depb & 0x80) ? "" : "n", /* packed or unpacked EPB? */ + (Depb & 0x3F), /* EPB index value */ + LDPepb, /*length of the data protected by the EPB */ + str1); /* protection method */ + + cio_skip(cio, Lepb - 11); + } +} + +void j2k_write_epb(opj_j2k_t *j2k) { + unsigned long int LDPepb, Pepb, Lepbp; + unsigned short int Lepb; + unsigned char Depb; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_EPB, 2); /* EPB */ + Lepbp = cio_tell(cio); + cio_skip(cio, 2); + + /* EPB style */ + Depb = 0x00; /* test */ + cio_write(cio, Depb, 1); /* Depb */ + + /* length of the data to be protected by this EPB */ + LDPepb = 0x00000000; /* test */ + cio_write(cio, LDPepb, 4); /* LDPepb */ + + /* next error correction tool */ + Pepb = 0x00000000; /* test */ + cio_write(cio, Pepb, 4); /* Pepb */ + + /* EPB data */ + /* no data, as of now */ + + Lepb = (unsigned short) (cio_tell(cio) - Lepbp); + cio_seek(cio, Lepbp); + cio_write(cio, Lepb, 2); /* Lepb */ + + cio_seek(cio, Lepbp + Lepb); + + /* marker struct update */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPB, Lepbp - 2, Lepb + 2); +} + +void j2k_read_esd(opj_j2k_t *j2k) { + unsigned short int Lesd, Cesd; + unsigned char Pesd; + + int cesdsize = (j2k->image->numcomps >= 257) ? 2 : 1; + + char str1[4][4] = {"p", "br", "pr", "res"}; + char str2[8][8] = {"res", "mse", "mse-r", "psnr", "psnr-i", "maxerr", "tse", "res"}; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the ESD parameters */ + Lesd = cio_read(cio, 2); + Cesd = cio_read(cio, cesdsize); + Pesd = cio_read(cio, 1); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "ESD(%d): c%d, %s, %s, %s, %s, %s\n", + cio_tell(cio) - (5 + cesdsize), + Cesd, /* component number for this ESD */ + str1[(Pesd & (unsigned char) 0xC0) >> 6], /* addressing mode */ + str2[(Pesd & (unsigned char) 0x38) >> 3], /* sensitivity type */ + ((Pesd & (unsigned char) 0x04) >> 2) ? "2Bs" : "1Bs", + ((Pesd & (unsigned char) 0x02) >> 1) ? "4Ba" : "2Ba", + (Pesd & (unsigned char) 0x01) ? "avgc" : ""); + + cio_skip(cio, Lesd - (3 + cesdsize)); +} + +void j2k_read_red(opj_j2k_t *j2k) { + unsigned short int Lred; + unsigned char Pred; + char str1[4][4] = {"p", "br", "pr", "res"}; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the RED parameters */ + Lred = cio_read(cio, 2); + Pred = cio_read(cio, 1); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "RED(%d): %s, %dc, %s, %s\n", + cio_tell(cio) - 5, + str1[(Pred & (unsigned char) 0xC0) >> 6], /* addressing mode */ + (Pred & (unsigned char) 0x38) >> 3, /* corruption level */ + ((Pred & (unsigned char) 0x02) >> 1) ? "4Ba" : "2Ba", /* address range */ + (Pred & (unsigned char) 0x01) ? "errs" : "free"); /* error free? */ + + cio_skip(cio, Lred - 3); +} + +opj_bool jpwl_check_tile(opj_j2k_t *j2k, opj_tcd_t *tcd, int tileno) { + +#ifdef oerhgierhgvhreit4u + /* + we navigate through the tile and find possible invalid parameters: + this saves a lot of crashes!!!!! + */ + int compno, resno, precno, /*layno,*/ bandno, blockno; + int numprecincts, numblocks; + + /* this is the selected tile */ + opj_tcd_tile_t *tile = &(tcd->tcd_image->tiles[tileno]); + + /* will keep the component */ + opj_tcd_tilecomp_t *comp = NULL; + + /* will keep the resolution */ + opj_tcd_resolution_t *res; + + /* will keep the subband */ + opj_tcd_band_t *band; + + /* will keep the precinct */ + opj_tcd_precinct_t *prec; + + /* will keep the codeblock */ + opj_tcd_cblk_t *block; + + /* check all tile components */ + for (compno = 0; compno < tile->numcomps; compno++) { + comp = &(tile->comps[compno]); + + /* check all component resolutions */ + for (resno = 0; resno < comp->numresolutions; resno++) { + res = &(comp->resolutions[resno]); + numprecincts = res->pw * res->ph; + + /* check all the subbands */ + for (bandno = 0; bandno < res->numbands; bandno++) { + band = &(res->bands[bandno]); + + /* check all the precincts */ + for (precno = 0; precno < numprecincts; precno++) { + prec = &(band->precincts[precno]); + numblocks = prec->ch * prec->cw; + + /* check all the codeblocks */ + for (blockno = 0; blockno < numblocks; blockno++) { + block = &(prec->cblks[blockno]); + + /* x-origin is invalid */ + if ((block->x0 < prec->x0) || (block->x0 > prec->x1)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: wrong x-cord of block origin %d => x-prec is (%d, %d)\n", + block->x0, prec->x0, prec->x1); + if (!JPWL_ASSUME || JPWL_ASSUME) + return OPJ_FALSE; + }; + } + } + } + } + } + +#endif + + return OPJ_TRUE; +} + +/*@}*/ + +#endif /* USE_JPWL */ + + +#ifdef USE_JPSEC + +/** @defgroup JPSEC JPSEC - JPEG-2000 Part 8 (JPSEC) codestream manager */ +/*@{*/ + + +/** @name Local static functions */ +/*@{*/ + +void j2k_read_sec(opj_j2k_t *j2k) { + unsigned short int Lsec; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the SEC length */ + Lsec = cio_read(cio, 2); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "SEC(%d)\n", + cio_tell(cio) - 2 + ); + + cio_skip(cio, Lsec - 2); +} + +void j2k_write_sec(opj_j2k_t *j2k) { + unsigned short int Lsec = 24; + int i; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_SEC, 2); /* SEC */ + cio_write(cio, Lsec, 2); + + /* write dummy data */ + for (i = 0; i < Lsec - 2; i++) + cio_write(cio, 0, 1); +} + +void j2k_read_insec(opj_j2k_t *j2k) { + unsigned short int Linsec; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the INSEC length */ + Linsec = cio_read(cio, 2); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "INSEC(%d)\n", + cio_tell(cio) - 2 + ); + + cio_skip(cio, Linsec - 2); +} + + +/*@}*/ + +/*@}*/ + +#endif /* USE_JPSEC */ + diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/jpwl.h b/openjpeg-dotnet/libopenjpeg/jpwl/jpwl.h new file mode 100644 index 0000000..b77afdd --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/jpwl.h @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __JPWL_H +#define __JPWL_H + +#ifdef USE_JPWL + +#include "crc.h" +#include "rs.h" + +/** +@file jpwl.h +@brief The JPEG-2000 Part11 (JPWL) marker segments manager + +The functions in JPWL.C have for goal to read/write the markers added by JPWL. +*/ + +/** @defgroup JPWL JPWL - JPEG-2000 Part11 (JPWL) codestream manager */ +/*@{*/ + +/** +Assume a basic codestream structure, so you can resort better from uncorrected errors +*/ +#define JPWL_ASSUME OPJ_TRUE + +/** +EPB (Error Protection Block) Marker segment +*/ +typedef struct jpwl_epb_ms { + /**@name Private fields set by epb_create */ + /*@{*/ + /** is the latest in header? */ + opj_bool latest; + /** is it in packed mode? */ + opj_bool packed; + /** TH where this marker has been placed (-1 means MH) */ + int tileno; + /** index in current header (0-63) */ + unsigned char index; + /** error protection method [-1=absent 0=none 1=predefined 16=CRC-16 32=CRC-32 37-128=RS] */ + int hprot; + /** message word length of pre-data */ + int k_pre; + /** code word length of pre-data */ + int n_pre; + /** length of pre-data */ + int pre_len; + /** message word length of post-data */ + int k_post; + /** code word length of post-data */ + int n_post; + /** length of post-data */ + int post_len; + /*@}*/ + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of EPB MS, exluding the marker itself (11 to 65535 bytes) */ + unsigned short int Lepb; + /** single byte for the style */ + unsigned char Depb; + /** four bytes, from 0 to 2^31-1 */ + unsigned long int LDPepb; + /** four bytes, next error management method */ + unsigned long int Pepb; + /** EPB data, variable size */ + unsigned char *data; + /*@}*/ +} jpwl_epb_ms_t; + +/** +EPC (Error Protection Capability) Marker segment +*/ +typedef struct jpwl_epc_ms { + /** is ESD active? */ + opj_bool esd_on; + /** is RED active? */ + opj_bool red_on; + /** is EPB active? */ + opj_bool epb_on; + /** are informative techniques active? */ + opj_bool info_on; + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of EPC MS, exluding the marker itself (9 to 65535 bytes) */ + unsigned short int Lepc; + /** two bytes, CRC for the EPC, excluding Pcrc itself */ + unsigned short int Pcrc; + /** four bytes, the codestream length from SOC to EOC */ + unsigned long int DL; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pepc; + /** EPC data, variable length */ + unsigned char *data; + /*@}*/ +} jpwl_epc_ms_t; + +/** +ESD (Error Sensitivity Descriptor) Marker segment +*/ +typedef struct jpwl_esd_ms { + /** codestream addressing mode [0=packet, 1=byte range, 2=packet range, 3=reserved] */ + unsigned char addrm; + /** size of codestream addresses [2/4 bytes] */ + unsigned char ad_size; + /** type of sensitivity + [0=relative error, 1=MSE, 2=MSE reduction, 3=PSNR, 4=PSNR increment, + 5=MAXERR (absolute peak error), 6=TSE (total squared error), 7=reserved */ + unsigned char senst; + /** size of sensitivity data (1/2 bytes) */ + unsigned char se_size; + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of ESD MS, exluding the marker itself (4 to 65535 bytes) */ + unsigned short int Lesd; + /** two bytes, component of error sensitivity */ + unsigned short int Cesd; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pesd; + /** ESD data, variable length */ + unsigned char *data; + /*@}*/ + /**@name Fields set by esd_create (only internal use) */ + /*@{*/ + /** number of components in the image */ + int numcomps; + /** tile where this marker has been placed (-1 means MH) */ + int tileno; + /** number of sensitivity values */ + unsigned long int svalnum; + /** size of a single sensitivity pair (address+value) */ + size_t sensval_size; + /*@}*/ +} jpwl_esd_ms_t; + +/** +RED (Residual Error Descriptor) Marker segment +*/ +typedef struct jpwl_red_ms { + /** two bytes for the length of RED MS, exluding the marker itself (3 to 65535 bytes) */ + unsigned short int Lred; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pred; + /** RED data, variable length */ + unsigned char *data; +} jpwl_red_ms_t; + +/** +Structure used to store JPWL markers temporary position and readyness +*/ +typedef struct jpwl_marker { + /** marker value (J2K_MS_EPC, etc.) */ + int id; + /** union keeping the pointer to the real marker struct */ + union jpwl_marks { + /** pointer to EPB marker */ + jpwl_epb_ms_t *epbmark; + /** pointer to EPC marker */ + jpwl_epc_ms_t *epcmark; + /** pointer to ESD marker */ + jpwl_esd_ms_t *esdmark; + /** pointer to RED marker */ + jpwl_red_ms_t *redmark; + } m; + /** position where the marker should go, in the pre-JPWL codestream */ + unsigned long int pos; + /** same as before, only written as a double, so we can sort it better */ + double dpos; + /** length of the marker segment (marker excluded) */ + unsigned short int len; + /** the marker length is ready or not? */ + opj_bool len_ready; + /** the marker position is ready or not? */ + opj_bool pos_ready; + /** the marker parameters are ready or not? */ + opj_bool parms_ready; + /** are the written data ready or not */ + opj_bool data_ready; +} jpwl_marker_t; + +/** +Encode according to JPWL specs +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Prepare the list of JPWL markers, after the Part 1 codestream +has been finalized (index struct is full) +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_prepare_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Dump the list of JPWL markers, after it has been prepared +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_dump_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Read the EPC marker (Error Protection Capability) +@param j2k J2K handle +*/ +void j2k_read_epc(opj_j2k_t *j2k); + +/** +Write the EPC marker (Error Protection Capability), BUT the DL field is always set to 0 +(this simplifies the management of EPBs and it is openly stated in the standard +as a possible value, mening that the information is not available) and the informative techniques +are not yet implemented +@param j2k J2K handle +*/ +void j2k_write_epc(opj_j2k_t *j2k); + +/** +Read the EPB marker (Error Protection Block) +@param j2k J2K handle +*/ +void j2k_read_epb(opj_j2k_t *j2k); + +/** +Write the EPB marker (Error Protection Block) +@param j2k J2K handle +*/ +void j2k_write_epb(opj_j2k_t *j2k); + +/** +Read the ESD marker (Error Sensitivity Descriptor) +@param j2k J2K handle +*/ +void j2k_read_esd(opj_j2k_t *j2k); + +/** +Read the RED marker (Residual Error Descriptor) +@param j2k J2K handle +*/ +void j2k_read_red(opj_j2k_t *j2k); + +/** create an EPB marker segment +@param j2k J2K compressor handle +@param latest it is the latest EPB in the header +@param packed EPB is in packed style +@param tileno tile number where the marker has been placed (-1 means MH) +@param idx current EPB running index +@param hprot applied protection type (-1/0,1,16,32,37-128) +@param pre_len length of pre-protected data +@param post_len length of post-protected data +@return returns the freshly created EPB +*/ +jpwl_epb_ms_t *jpwl_epb_create(opj_j2k_t *j2k, opj_bool latest, opj_bool packed, int tileno, int idx, int hprot, + unsigned long int pre_len, unsigned long int post_len); + +/** add a number of EPB marker segments +@param j2k J2K compressor handle +@param jwmarker pointer to the JPWL markers list +@param jwmarker_num pointer to the number of JPWL markers (gets updated) +@param latest it is the latest group of EPBs in the header +@param packed EPBs are in packed style +@param insideMH it is in the MH +@param idx pointer to the starting EPB running index (gets updated) +@param hprot applied protection type (-1/0,1,16,32,37-128) +@param place_pos place in original codestream where EPBs should go +@param tileno tile number of these EPBs +@param pre_len length of pre-protected data +@param post_len length of post-protected data +@return returns the length of all added markers +*/ +int jpwl_epbs_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + opj_bool latest, opj_bool packed, opj_bool insideMH, int *idx, int hprot, + double place_pos, int tileno, + unsigned long int pre_len, unsigned long int post_len); + +/** add a number of ESD marker segments +@param j2k J2K compressor handle +@param jwmarker pointer to the JPWL markers list +@param jwmarker_num pointer to the number of JPWL markers (gets updated) +@param comps considered component (-1=average, 0/1/2/...=component no.) +@param addrm addressing mode (0=packet, 1=byte range, 2=packet range, 3=reserved) +@param ad_size size of addresses (2/4 bytes) +@param senst sensitivity type +@param se_size sensitivity values size (1/2 bytes) +@param place_pos place in original codestream where EPBs should go +@param tileno tile number of these EPBs +@return returns the length of all added markers +*/ +int jpwl_esds_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, + double place_pos, int tileno); + +/** updates the information structure by modifying the positions and lengths +@param j2k J2K compressor handle +@param jwmarker pointer to JPWL markers list +@param jwmarker_num number of JPWL markers +@return returns true in case of success +*/ +opj_bool jpwl_update_info(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int jwmarker_num); + + +opj_bool jpwl_esd_fill(opj_j2k_t *j2k, jpwl_esd_ms_t *esdmark, unsigned char *buf); + +opj_bool jpwl_epb_fill(opj_j2k_t *j2k, jpwl_epb_ms_t *epbmark, unsigned char *buf, unsigned char *post_buf); + +void j2k_add_marker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len); + +/** corrects the data in the JPWL codestream +@param j2k J2K compressor handle +@return true if correction is performed correctly +*/ +opj_bool jpwl_correct(opj_j2k_t *j2k); + +/** corrects the data protected by an EPB +@param j2k J2K compressor handle +@param buffer pointer to the EPB position +@param type type of EPB: 0=MH, 1=TPH, 2=other, 3=auto +@param pre_len length of pre-data +@param post_len length of post_data +@param conn is a pointer to the length of all connected (packed) EPBs +@param L4_bufp is a pointer to the buffer pointer of redundancy data +@return returns true if correction could be succesfully performed +*/ +opj_bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn, + unsigned char **L4_bufp); + +/** check that a tile and its children have valid data +@param j2k J2K decompressor handle +@param tcd Tile decompressor handle +@param tileno number of the tile to check +*/ +opj_bool jpwl_check_tile(opj_j2k_t *j2k, opj_tcd_t *tcd, int tileno); + +/** Macro functions for CRC computation */ + +/** +Computes the CRC-16, as stated in JPWL specs +@param CRC two bytes containing the CRC value (must be initialized with 0x0000) +@param DATA byte for which the CRC is computed; call this on every byte of the sequence +and get the CRC at the end +*/ +#define jpwl_updateCRC16(CRC, DATA) updateCRC16(CRC, DATA) + +/** +Computes the CRC-32, as stated in JPWL specs +@param CRC four bytes containing the CRC value (must be initialized with 0x00000000) +@param DATA byte for which the CRC is computed; call this on every byte of the sequence +and get the CRC at the end +*/ +#define jpwl_updateCRC32(CRC, DATA) updateCRC32(CRC, DATA) + +/** +Computes the minimum between two integers +@param a first integer to compare +@param b second integer to compare +@return returns the minimum integer between a and b +*/ +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif /* min */ + +/*@}*/ + +#endif /* USE_JPWL */ + +#ifdef USE_JPSEC + +/** @defgroup JPSEC JPSEC - JPEG-2000 Part 8 (JPSEC) codestream manager */ +/*@{*/ + +/** +Read the SEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_read_sec(opj_j2k_t *j2k); + +/** +Write the SEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_write_sec(opj_j2k_t *j2k); + +/** +Read the INSEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_read_insec(opj_j2k_t *j2k); + +/*@}*/ + +#endif /* USE_JPSEC */ + +#endif /* __JPWL_H */ + diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/jpwl_lib.c b/openjpeg-dotnet/libopenjpeg/jpwl/jpwl_lib.c new file mode 100644 index 0000000..90a71ce --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/jpwl_lib.c @@ -0,0 +1,1797 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef USE_JPWL + +#include "opj_includes.h" +#include + +/** Minimum and maximum values for the double->pfp conversion */ +#define MIN_V1 0.0 +#define MAX_V1 17293822569102704640.0 +#define MIN_V2 0.000030517578125 +#define MAX_V2 131040.0 + +/** conversion between a double precision floating point +number and the corresponding pseudo-floating point used +to represent sensitivity values +@param V the double precision value +@param bytes the number of bytes of the representation +@return the pseudo-floating point value (cast accordingly) +*/ +unsigned short int jpwl_double_to_pfp(double V, int bytes); + +/** conversion between a pseudo-floating point used +to represent sensitivity values and the corresponding +double precision floating point number +@param em the pseudo-floating point value (cast accordingly) +@param bytes the number of bytes of the representation +@return the double precision value +*/ +double jpwl_pfp_to_double(unsigned short int em, int bytes); + + /*-------------------------------------------------------------*/ + +int jpwl_markcomp(const void *arg1, const void *arg2) +{ + /* Compare the two markers' positions */ + double diff = (((jpwl_marker_t *) arg1)->dpos - ((jpwl_marker_t *) arg2)->dpos); + + if (diff == 0.0) + return (0); + else if (diff < 0) + return (-1); + else + return (+1); +} + +int jpwl_epbs_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + opj_bool latest, opj_bool packed, opj_bool insideMH, int *idx, int hprot, + double place_pos, int tileno, + unsigned long int pre_len, unsigned long int post_len) { + + jpwl_epb_ms_t *epb_mark = NULL; + + int k_pre, k_post, n_pre, n_post; + + unsigned long int L1, L2, dL4, max_postlen, epbs_len = 0; + + /* We find RS(n,k) for EPB parms and pre-data, if any */ + if (insideMH && (*idx == 0)) { + /* First EPB in MH */ + k_pre = 64; + n_pre = 160; + } else if (!insideMH && (*idx == 0)) { + /* First EPB in TH */ + k_pre = 25; + n_pre = 80; + } else { + /* Following EPBs in MH or TH */ + k_pre = 13; + n_pre = 40; + }; + + /* Find lengths, Figs. B3 and B4 */ + /* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */ + L1 = pre_len + 13; + + /* size of pre-data redundancy */ + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L2 = (n_pre - k_pre) * (unsigned long int) ceil((double) L1 / (double) k_pre); + + /* Find protection type for post data and its associated redundancy field length*/ + if ((hprot == 16) || (hprot == 32)) { + /* there is a CRC for post-data */ + k_post = post_len; + n_post = post_len + (hprot >> 3); + /*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */ + + } else if ((hprot >= 37) && (hprot <= 128)) { + /* there is a RS for post-data */ + k_post = 32; + n_post = hprot; + + } else { + /* Use predefined codes */ + n_post = n_pre; + k_post = k_pre; + }; + + /* Create the EPB(s) */ + while (post_len > 0) { + + /* maximum postlen in order to respect EPB size + (we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms)*/ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post)); + + /* maximum postlen in order to respect EPB size */ + if (*idx == 0) + /* (we use (JPWL_MAXIMUM_EPB_ROOM - L2) instead of 65535 for keeping room for EPB parms + pre-data) */ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) (JPWL_MAXIMUM_EPB_ROOM - L2) / (double) (n_post - k_post)); + + else + /* (we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms) */ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post)); + + /* null protection case */ + /* the max post length can be as large as the LDPepb field can host */ + if (hprot == 0) + max_postlen = INT_MAX; + + /* length to use */ + dL4 = min(max_postlen, post_len); + + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + latest ? (dL4 < max_postlen) : OPJ_FALSE, /* is it the latest? */ + packed, /* is it packed? */ + tileno, /* we are in TPH */ + *idx, /* its index */ + hprot, /* protection type parameters of following data */ + 0, /* pre-data: nothing for now */ + dL4 /* post-data: the stub computed previously */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (*jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[*jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[*jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + jwmarker[*jwmarker_num].pos = (int) place_pos; /* after SOT */ + jwmarker[*jwmarker_num].dpos = place_pos + 0.0000001 * (double)(*idx); /* not very first! */ + jwmarker[*jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[*jwmarker_num].len_ready = OPJ_TRUE; /* ready */ + jwmarker[*jwmarker_num].pos_ready = OPJ_TRUE; /* ready */ + jwmarker[*jwmarker_num].parms_ready = OPJ_TRUE; /* ready */ + jwmarker[*jwmarker_num].data_ready = OPJ_FALSE; /* not ready */ + (*jwmarker_num)++; + } + + /* increment epb index */ + (*idx)++; + + /* decrease postlen */ + post_len -= dL4; + + /* increase the total length of EPBs */ + epbs_len += epb_mark->Lepb + 2; + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB for UEP in tile %d\n", tileno); + }; + } + + return epbs_len; +} + + +jpwl_epb_ms_t *jpwl_epb_create(opj_j2k_t *j2k, opj_bool latest, opj_bool packed, int tileno, int idx, int hprot, + unsigned long int pre_len, unsigned long int post_len) { + + jpwl_epb_ms_t *epb = NULL; + /*unsigned short int data_len = 0;*/ + unsigned short int L2, L3; + unsigned long int L1, L4; + /*unsigned char *predata_in = NULL;*/ + + opj_bool insideMH = (tileno == -1); + + /* Alloc space */ + if (!(epb = (jpwl_epb_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_epb_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for one EPB MS\n"); + return NULL; + }; + + /* We set RS(n,k) for EPB parms and pre-data, if any */ + if (insideMH && (idx == 0)) { + /* First EPB in MH */ + epb->k_pre = 64; + epb->n_pre = 160; + } else if (!insideMH && (idx == 0)) { + /* First EPB in TH */ + epb->k_pre = 25; + epb->n_pre = 80; + } else { + /* Following EPBs in MH or TH */ + epb->k_pre = 13; + epb->n_pre = 40; + }; + + /* Find lengths, Figs. B3 and B4 */ + /* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */ + L1 = pre_len + 13; + epb->pre_len = pre_len; + + /* size of pre-data redundancy */ + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre); + + /* length of post-data */ + L4 = post_len; + epb->post_len = post_len; + + /* Find protection type for post data and its associated redundancy field length*/ + if ((hprot == 16) || (hprot == 32)) { + /* there is a CRC for post-data */ + epb->Pepb = 0x10000000 | ((unsigned long int) hprot >> 5); /* 0=CRC-16, 1=CRC-32 */ + epb->k_post = post_len; + epb->n_post = post_len + (hprot >> 3); + /*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */ + + } else if ((hprot >= 37) && (hprot <= 128)) { + /* there is a RS for post-data */ + epb->Pepb = 0x20000020 | (((unsigned long int) hprot & 0x000000FF) << 8); + epb->k_post = 32; + epb->n_post = hprot; + + } else if (hprot == 1) { + /* Use predefined codes */ + epb->Pepb = (unsigned long int) 0x00000000; + epb->n_post = epb->n_pre; + epb->k_post = epb->k_pre; + + } else if (hprot == 0) { + /* Placeholder EPB: only protects its parameters, no protection method */ + epb->Pepb = (unsigned long int) 0xFFFFFFFF; + epb->n_post = 1; + epb->k_post = 1; + + } else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Invalid protection value for EPB h = %d\n", hprot); + return NULL; + } + + epb->hprot = hprot; + + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post); + + /* private fields */ + epb->tileno = tileno; + + /* Fill some fields of the EPB */ + + /* total length of the EPB MS (less the EPB marker itself): */ + /* Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) + pre_redundancy + post-redundancy */ + epb->Lepb = 11 + L2 + L3; + + /* EPB style */ + epb->Depb = ((packed & 0x0001) << 7) | ((latest & 0x0001) << 6) | (idx & 0x003F); + + /* length of data protected by EPB: */ + epb->LDPepb = L1 + L4; + + return epb; +} + +void jpwl_epb_write(opj_j2k_t *j2k, jpwl_epb_ms_t *epb, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_EPB >> 8); + *(buf++) = (unsigned char) (J2K_MS_EPB >> 0); + + /* Lepb */ + *(buf++) = (unsigned char) (epb->Lepb >> 8); + *(buf++) = (unsigned char) (epb->Lepb >> 0); + + /* Depb */ + *(buf++) = (unsigned char) (epb->Depb >> 0); + + /* LDPepb */ + *(buf++) = (unsigned char) (epb->LDPepb >> 24); + *(buf++) = (unsigned char) (epb->LDPepb >> 16); + *(buf++) = (unsigned char) (epb->LDPepb >> 8); + *(buf++) = (unsigned char) (epb->LDPepb >> 0); + + /* Pepb */ + *(buf++) = (unsigned char) (epb->Pepb >> 24); + *(buf++) = (unsigned char) (epb->Pepb >> 16); + *(buf++) = (unsigned char) (epb->Pepb >> 8); + *(buf++) = (unsigned char) (epb->Pepb >> 0); + + /* Data */ + /*memcpy(buf, epb->data, (size_t) epb->Lepb - 11);*/ + memset(buf, 0, (size_t) epb->Lepb - 11); + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPB, -1, epb->Lepb + 2); + +}; + + +jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, opj_bool esd_on, opj_bool red_on, opj_bool epb_on, opj_bool info_on) { + + jpwl_epc_ms_t *epc = NULL; + + /* Alloc space */ + if (!(epc = (jpwl_epc_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_epc_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for EPC MS\n"); + return NULL; + }; + + /* Set the EPC parameters */ + epc->esd_on = esd_on; + epc->epb_on = epb_on; + epc->red_on = red_on; + epc->info_on = info_on; + + /* Fill the EPC fields with default values */ + epc->Lepc = 9; + epc->Pcrc = 0x0000; + epc->DL = 0x00000000; + epc->Pepc = ((j2k->cp->esd_on & 0x0001) << 4) | ((j2k->cp->red_on & 0x0001) << 5) | + ((j2k->cp->epb_on & 0x0001) << 6) | ((j2k->cp->info_on & 0x0001) << 7); + + return (epc); +} + +opj_bool jpwl_epb_fill(opj_j2k_t *j2k, jpwl_epb_ms_t *epb, unsigned char *buf, unsigned char *post_buf) { + + unsigned long int L1, L2, L3, L4; + int remaining; + unsigned long int P, NN_P; + + /* Operating buffer */ + static unsigned char codeword[NN], *parityword; + + unsigned char *L1_buf, *L2_buf; + /* these ones are static, since we need to keep memory of + the exact place from one call to the other */ + static unsigned char *L3_buf, *L4_buf; + + /* some consistency check */ + if (!buf) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs\n"); + return OPJ_FALSE; + } + + if (!post_buf && !L4_buf) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs data\n"); + return OPJ_FALSE; + } + + /* + * Compute parity bytes on pre-data, ALWAYS present (at least only for EPB parms) + */ + + /* Initialize RS structures */ + P = epb->n_pre - epb->k_pre; + NN_P = NN - P; + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* pre-data begins pre_len bytes before of EPB buf */ + L1_buf = buf - epb->pre_len; + L1 = epb->pre_len + 13; + + /* redundancy for pre-data begins immediately after EPB parms */ + L2_buf = buf + 13; + L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre); + + /* post-data + the position of L4 buffer can be: + 1) passed as a parameter: in that case use it + 2) null: in that case use the previous (static) one + */ + if (post_buf) + L4_buf = post_buf; + L4 = epb->post_len; + + /* post-data redundancy begins immediately after pre-data redundancy */ + L3_buf = L2_buf + L2; + L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post); + + /* let's check whether EPB length is sufficient to contain all these data */ + if (epb->Lepb < (11 + L2 + L3)) + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no room in EPB data field for writing redundancy data\n"); + /*printf("Env. %d, nec. %d (%d + %d)\n", epb->Lepb - 11, L2 + L3, L2, L3);*/ + + /* Compute redundancy of pre-data message words */ + remaining = L1; + while (remaining) { + + /* copy message data into codeword buffer */ + if (remaining < epb->k_pre) { + /* the last message word is zero-padded */ + memset(codeword, 0, NN); + memcpy(codeword, L1_buf, remaining); + L1_buf += remaining; + remaining = 0; + + } else { + memcpy(codeword, L1_buf, epb->k_pre); + L1_buf += epb->k_pre; + remaining -= epb->k_pre; + + } + + /* Encode the buffer and obtain parity bytes */ + if (encode_rs(codeword, parityword)) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible encoding error in codeword @ position #%d\n", (L1_buf - buf) / epb->k_pre); + + /* copy parity bytes only in redundancy buffer */ + memcpy(L2_buf, parityword, P); + + /* advance parity buffer */ + L2_buf += P; + } + + /* + * Compute parity bytes on post-data, may be absent if there are no data + */ + /*printf("Hprot is %d (tileno=%d, k_pre=%d, n_pre=%d, k_post=%d, n_post=%d, pre_len=%d, post_len=%d)\n", + epb->hprot, epb->tileno, epb->k_pre, epb->n_pre, epb->k_post, epb->n_post, epb->pre_len, + epb->post_len);*/ + if (epb->hprot < 0) { + + /* there should be no EPB */ + + } else if (epb->hprot == 0) { + + /* no protection for the data */ + /* advance anyway */ + L4_buf += epb->post_len; + + } else if (epb->hprot == 16) { + + /* CRC-16 */ + unsigned short int mycrc = 0x0000; + + /* compute the CRC field (excluding itself) */ + remaining = L4; + while (remaining--) + jpwl_updateCRC16(&mycrc, *(L4_buf++)); + + /* write the CRC field */ + *(L3_buf++) = (unsigned char) (mycrc >> 8); + *(L3_buf++) = (unsigned char) (mycrc >> 0); + + } else if (epb->hprot == 32) { + + /* CRC-32 */ + unsigned long int mycrc = 0x00000000; + + /* compute the CRC field (excluding itself) */ + remaining = L4; + while (remaining--) + jpwl_updateCRC32(&mycrc, *(L4_buf++)); + + /* write the CRC field */ + *(L3_buf++) = (unsigned char) (mycrc >> 24); + *(L3_buf++) = (unsigned char) (mycrc >> 16); + *(L3_buf++) = (unsigned char) (mycrc >> 8); + *(L3_buf++) = (unsigned char) (mycrc >> 0); + + } else { + + /* RS */ + + /* Initialize RS structures */ + P = epb->n_post - epb->k_post; + NN_P = NN - P; + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Compute redundancy of post-data message words */ + remaining = L4; + while (remaining) { + + /* copy message data into codeword buffer */ + if (remaining < epb->k_post) { + /* the last message word is zero-padded */ + memset(codeword, 0, NN); + memcpy(codeword, L4_buf, remaining); + L4_buf += remaining; + remaining = 0; + + } else { + memcpy(codeword, L4_buf, epb->k_post); + L4_buf += epb->k_post; + remaining -= epb->k_post; + + } + + /* Encode the buffer and obtain parity bytes */ + if (encode_rs(codeword, parityword)) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible encoding error in codeword @ position #%d\n", (L4_buf - buf) / epb->k_post); + + /* copy parity bytes only in redundancy buffer */ + memcpy(L3_buf, parityword, P); + + /* advance parity buffer */ + L3_buf += P; + } + + } + + return OPJ_TRUE; +} + + +opj_bool jpwl_correct(opj_j2k_t *j2k) { + + opj_cio_t *cio = j2k->cio; + opj_bool status; + static opj_bool mh_done = OPJ_FALSE; + int mark_pos, id, len, skips, sot_pos; + unsigned long int Psot = 0; + + /* go back to marker position */ + mark_pos = cio_tell(cio) - 2; + cio_seek(cio, mark_pos); + + if ((j2k->state == J2K_STATE_MHSOC) && !mh_done) { + + int mark_val = 0, skipnum = 0; + + /* + COLOR IMAGE + first thing to do, if we are here, is to look whether + 51 (skipnum) positions ahead there is an EPB, in case of MH + */ + /* + B/W IMAGE + first thing to do, if we are here, is to look whether + 45 (skipnum) positions ahead there is an EPB, in case of MH + */ + /* SIZ SIZ_FIELDS SIZ_COMPS FOLLOWING_MARKER */ + skipnum = 2 + 38 + 3 * j2k->cp->exp_comps + 2; + if ((cio->bp + skipnum) < cio->end) { + + cio_skip(cio, skipnum); + + /* check that you are not going beyond the end of codestream */ + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 0, /* EPB type: MH */ + skipnum, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + + /* read the marker value */ + mark_val = (*(cio->bp) << 8) | *(cio->bp + 1); + + if (status && (mark_val == J2K_MS_EPB)) { + /* we found it! */ + mh_done = OPJ_TRUE; + return OPJ_TRUE; + } + + /* Disable correction in case of missing or bad head EPB */ + /* We can't do better! */ + /* PATCHED: 2008-01-25 */ + /* MOVED UP: 2008-02-01 */ + if (!status) { + j2k->cp->correct = OPJ_FALSE; + opj_event_msg(j2k->cinfo, EVT_WARNING, "Couldn't find the MH EPB: disabling JPWL\n"); + } + + } + + } + + if (OPJ_TRUE /*(j2k->state == J2K_STATE_TPHSOT) || (j2k->state == J2K_STATE_TPH)*/) { + /* else, look if 12 positions ahead there is an EPB, in case of TPH */ + cio_seek(cio, mark_pos); + if ((cio->bp + 12) < cio->end) { + + cio_skip(cio, 12); + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 1, /* EPB type: TPH */ + 12, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + if (status) + /* we found it! */ + return OPJ_TRUE; + } + } + + return OPJ_FALSE; + + /* for now, don't use this code */ + + /* else, look if here is an EPB, in case of other */ + if (mark_pos > 64) { + /* it cannot stay before the first MH EPB */ + cio_seek(cio, mark_pos); + cio_skip(cio, 0); + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 2, /* EPB type: TPH */ + 0, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + if (status) + /* we found it! */ + return OPJ_TRUE; + } + + /* nope, no EPBs probably, or they are so damaged that we can give up */ + return OPJ_FALSE; + + return OPJ_TRUE; + + /* AN ATTEMPT OF PARSER */ + /* NOT USED ACTUALLY */ + + /* go to the beginning of the file */ + cio_seek(cio, 0); + + /* let's begin */ + j2k->state = J2K_STATE_MHSOC; + + /* cycle all over the markers */ + while (cio_tell(cio) < cio->length) { + + /* read the marker */ + mark_pos = cio_tell(cio); + id = cio_read(cio, 2); + + /* details */ + printf("Marker@%d: %X\n", cio_tell(cio) - 2, id); + + /* do an action in response to the read marker */ + switch (id) { + + /* short markers */ + + /* SOC */ + case J2K_MS_SOC: + j2k->state = J2K_STATE_MHSIZ; + len = 0; + skips = 0; + break; + + /* EOC */ + case J2K_MS_EOC: + j2k->state = J2K_STATE_MT; + len = 0; + skips = 0; + break; + + /* particular case of SOD */ + case J2K_MS_SOD: + len = Psot - (mark_pos - sot_pos) - 2; + skips = len; + break; + + /* long markers */ + + /* SOT */ + case J2K_MS_SOT: + j2k->state = J2K_STATE_TPH; + sot_pos = mark_pos; /* position of SOT */ + len = cio_read(cio, 2); /* read the length field */ + cio_skip(cio, 2); /* this field is unnecessary */ + Psot = cio_read(cio, 4); /* tile length */ + skips = len - 8; + break; + + /* remaining */ + case J2K_MS_SIZ: + j2k->state = J2K_STATE_MH; + /* read the length field */ + len = cio_read(cio, 2); + skips = len - 2; + break; + + /* remaining */ + default: + /* read the length field */ + len = cio_read(cio, 2); + skips = len - 2; + break; + + } + + /* skip to marker's end */ + cio_skip(cio, skips); + + } + + +} + +opj_bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn, + unsigned char **L4_bufp) { + + /* Operating buffer */ + unsigned char codeword[NN], *parityword; + + unsigned long int P, NN_P; + unsigned long int L1, L4; + int remaining, n_pre, k_pre, n_post, k_post; + + int status, tt; + + int orig_pos = cio_tell(j2k->cio); + + unsigned char *L1_buf, *L2_buf; + unsigned char *L3_buf, *L4_buf; + + unsigned long int LDPepb, Pepb; + unsigned short int Lepb; + unsigned char Depb; + char str1[25] = ""; + int myconn, errnum = 0; + opj_bool errflag = OPJ_FALSE; + + opj_cio_t *cio = j2k->cio; + + /* check for common errors */ + if (!buffer) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "The EPB pointer is a NULL buffer\n"); + return OPJ_FALSE; + } + + /* set bignesses */ + L1 = pre_len + 13; + + /* pre-data correction */ + switch (type) { + + case 0: + /* MH EPB */ + k_pre = 64; + n_pre = 160; + break; + + case 1: + /* TPH EPB */ + k_pre = 25; + n_pre = 80; + break; + + case 2: + /* other EPBs */ + k_pre = 13; + n_pre = 40; + break; + + case 3: + /* automatic setup */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Auto. setup not yet implemented\n"); + return OPJ_FALSE; + break; + + default: + /* unknown type */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Unknown expected EPB type\n"); + return OPJ_FALSE; + break; + + } + + /* Initialize RS structures */ + P = n_pre - k_pre; + NN_P = NN - P; + tt = (int) floor((float) P / 2.0F); /* correction capability of the code */ + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Correct pre-data message words */ + L1_buf = buffer - pre_len; + L2_buf = buffer + 13; + remaining = L1; + while (remaining) { + + /* always zero-pad codewords */ + /* (this is required, since after decoding the zeros in the long codeword + could change, and keep unchanged in subsequent calls) */ + memset(codeword, 0, NN); + + /* copy codeword buffer into message bytes */ + if (remaining < k_pre) + memcpy(codeword, L1_buf, remaining); + else + memcpy(codeword, L1_buf, k_pre); + + /* copy redundancy buffer in parity bytes */ + memcpy(parityword, L2_buf, P); + + /* Decode the buffer and possibly obtain corrected bytes */ + status = eras_dec_rs(codeword, NULL, 0); + if (status == -1) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible decoding error in codeword @ position #%d\n", (L1_buf - buffer) / k_pre);*/ + errflag = OPJ_TRUE; + /* we can try to safely get out from the function: + if we are here, either this is not an EPB or the first codeword + is too damaged to be helpful */ + /*return OPJ_FALSE;*/ + + } else if (status == 0) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/ + + } else if (status <= tt) { + /* it has corrected 0 <= errs <= tt */ + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/ + errnum += status; + + } else { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n"); + return OPJ_FALSE;*/ + errflag = OPJ_TRUE; + } + + + /* advance parity buffer */ + if ((status >= 0) && (status <= tt)) + /* copy back corrected parity only if all is OK */ + memcpy(L2_buf, parityword, P); + L2_buf += P; + + /* advance message buffer */ + if (remaining < k_pre) { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L1_buf, codeword, remaining); + L1_buf += remaining; + remaining = 0; + + } else { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L1_buf, codeword, k_pre); + L1_buf += k_pre; + remaining -= k_pre; + + } + } + + /* print summary */ + if (!conn) { + + /*if (errnum) + opj_event_msg(j2k->cinfo, EVT_INFO, "+ %d symbol errors corrected (Ps=%.1e)\n", errnum, + (float) errnum / ((float) n_pre * (float) L1 / (float) k_pre));*/ + if (errflag) { + /*opj_event_msg(j2k->cinfo, EVT_INFO, "+ there were unrecoverable errors\n");*/ + return OPJ_FALSE; + } + + } + + /* presumably, now, EPB parameters are correct */ + /* let's get them */ + + /* Simply read the EPB parameters */ + if (conn) + cio->bp = buffer; + cio_skip(cio, 2); /* the marker */ + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + /* What does Pepb tells us about the protection method? */ + if (((Pepb & 0xF0000000) >> 28) == 0) + sprintf(str1, "pred"); /* predefined */ + else if (((Pepb & 0xF0000000) >> 28) == 1) + sprintf(str1, "crc-%lu", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */ + else if (((Pepb & 0xF0000000) >> 28) == 2) + sprintf(str1, "rs(%lu,32)", (Pepb & 0x0000FF00) >> 8); /* RS mode */ + else if (Pepb == 0xFFFFFFFF) + sprintf(str1, "nometh"); /* RS mode */ + else + sprintf(str1, "unknown"); /* unknown */ + + /* Now we write them to screen */ + if (!conn && post_len) + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPB(%d): (%sl, %sp, %u), %lu, %s\n", + cio_tell(cio) - 13, + (Depb & 0x40) ? "" : "n", /* latest EPB or not? */ + (Depb & 0x80) ? "" : "n", /* packed or unpacked EPB? */ + (Depb & 0x3F), /* EPB index value */ + LDPepb, /*length of the data protected by the EPB */ + str1); /* protection method */ + + + /* well, we need to investigate how long is the connected length of packed EPBs */ + myconn = Lepb + 2; + if ((Depb & 0x40) == 0) /* not latest in header */ + jpwl_epb_correct(j2k, /* J2K decompressor handle */ + buffer + Lepb + 2, /* pointer to next EPB in codestream buffer */ + 2, /* EPB type: should be of other type */ + 0, /* only EPB fields */ + 0, /* do not look after */ + &myconn, + NULL + ); + if (conn) + *conn += myconn; + + /*if (!conn) + printf("connected = %d\n", myconn);*/ + + /*cio_seek(j2k->cio, orig_pos); + return OPJ_TRUE;*/ + + /* post-data + the position of L4 buffer is at the end of currently connected EPBs + */ + if (!(L4_bufp)) + L4_buf = buffer + myconn; + else if (!(*L4_bufp)) + L4_buf = buffer + myconn; + else + L4_buf = *L4_bufp; + if (post_len == -1) + L4 = LDPepb - pre_len - 13; + else if (post_len == 0) + L4 = 0; + else + L4 = post_len; + + L3_buf = L2_buf; + + /* Do a further check here on the read parameters */ + if (L4 > (unsigned long) cio_numbytesleft(j2k->cio)) + /* overflow */ + return OPJ_FALSE; + + /* we are ready for decoding the remaining data */ + if (((Pepb & 0xF0000000) >> 28) == 1) { + /* CRC here */ + if ((16 * ((Pepb & 0x00000001) + 1)) == 16) { + + /* CRC-16 */ + unsigned short int mycrc = 0x0000, filecrc = 0x0000; + + /* compute the CRC field */ + remaining = L4; + while (remaining--) + jpwl_updateCRC16(&mycrc, *(L4_buf++)); + + /* read the CRC field */ + filecrc = *(L3_buf++) << 8; + filecrc |= *(L3_buf++); + + /* check the CRC field */ + if (mycrc == filecrc) { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n"); + } else { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc); + errflag = OPJ_TRUE; + } + } + + if ((16 * ((Pepb & 0x00000001) + 1)) == 32) { + + /* CRC-32 */ + unsigned long int mycrc = 0x00000000, filecrc = 0x00000000; + + /* compute the CRC field */ + remaining = L4; + while (remaining--) + jpwl_updateCRC32(&mycrc, *(L4_buf++)); + + /* read the CRC field */ + filecrc = *(L3_buf++) << 24; + filecrc |= *(L3_buf++) << 16; + filecrc |= *(L3_buf++) << 8; + filecrc |= *(L3_buf++); + + /* check the CRC field */ + if (mycrc == filecrc) { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n"); + } else { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc); + errflag = OPJ_TRUE; + } + } + + } else if (Pepb == 0xFFFFFFFF) { + /* no method */ + + /* advance without doing anything */ + remaining = L4; + while (remaining--) + L4_buf++; + + } else if ((((Pepb & 0xF0000000) >> 28) == 2) || (((Pepb & 0xF0000000) >> 28) == 0)) { + /* RS coding here */ + + if (((Pepb & 0xF0000000) >> 28) == 0) { + + k_post = k_pre; + n_post = n_pre; + + } else { + + k_post = 32; + n_post = (Pepb & 0x0000FF00) >> 8; + } + + /* Initialize RS structures */ + P = n_post - k_post; + NN_P = NN - P; + tt = (int) floor((float) P / 2.0F); /* again, correction capability */ + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Correct post-data message words */ + /*L4_buf = buffer + Lepb + 2;*/ + L3_buf = L2_buf; + remaining = L4; + while (remaining) { + + /* always zero-pad codewords */ + /* (this is required, since after decoding the zeros in the long codeword + could change, and keep unchanged in subsequent calls) */ + memset(codeword, 0, NN); + + /* copy codeword buffer into message bytes */ + if (remaining < k_post) + memcpy(codeword, L4_buf, remaining); + else + memcpy(codeword, L4_buf, k_post); + + /* copy redundancy buffer in parity bytes */ + memcpy(parityword, L3_buf, P); + + /* Decode the buffer and possibly obtain corrected bytes */ + status = eras_dec_rs(codeword, NULL, 0); + if (status == -1) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible decoding error in codeword @ position #%d\n", (L4_buf - (buffer + Lepb + 2)) / k_post);*/ + errflag = OPJ_TRUE; + + } else if (status == 0) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/ + + } else if (status <= tt) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/ + errnum += status; + + } else { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n"); + return OPJ_FALSE;*/ + errflag = OPJ_TRUE; + } + + + /* advance parity buffer */ + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L3_buf, parityword, P); + L3_buf += P; + + /* advance message buffer */ + if (remaining < k_post) { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L4_buf, codeword, remaining); + L4_buf += remaining; + remaining = 0; + + } else { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L4_buf, codeword, k_post); + L4_buf += k_post; + remaining -= k_post; + + } + } + } + + /* give back the L4_buf address */ + if (L4_bufp) + *L4_bufp = L4_buf; + + /* print summary */ + if (!conn) { + + if (errnum) + opj_event_msg(j2k->cinfo, EVT_INFO, "- %d symbol errors corrected (Ps=%.1e)\n", errnum, + (float) errnum / (float) LDPepb); + if (errflag) + opj_event_msg(j2k->cinfo, EVT_INFO, "- there were unrecoverable errors\n"); + + } + + cio_seek(j2k->cio, orig_pos); + + return OPJ_TRUE; +} + +void jpwl_epc_write(opj_j2k_t *j2k, jpwl_epc_ms_t *epc, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_EPC >> 8); + *(buf++) = (unsigned char) (J2K_MS_EPC >> 0); + + /* Lepc */ + *(buf++) = (unsigned char) (epc->Lepc >> 8); + *(buf++) = (unsigned char) (epc->Lepc >> 0); + + /* Pcrc */ + *(buf++) = (unsigned char) (epc->Pcrc >> 8); + *(buf++) = (unsigned char) (epc->Pcrc >> 0); + + /* DL */ + *(buf++) = (unsigned char) (epc->DL >> 24); + *(buf++) = (unsigned char) (epc->DL >> 16); + *(buf++) = (unsigned char) (epc->DL >> 8); + *(buf++) = (unsigned char) (epc->DL >> 0); + + /* Pepc */ + *(buf++) = (unsigned char) (epc->Pepc >> 0); + + /* Data */ + /*memcpy(buf, epc->data, (size_t) epc->Lepc - 9);*/ + memset(buf, 0, (size_t) epc->Lepc - 9); + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPC, -1, epc->Lepc + 2); + +}; + +int jpwl_esds_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, + double place_pos, int tileno) { + + return 0; +} + +jpwl_esd_ms_t *jpwl_esd_create(opj_j2k_t *j2k, int comp, + unsigned char addrm, unsigned char ad_size, + unsigned char senst, int se_size, int tileno, + unsigned long int svalnum, void *sensval) { + + jpwl_esd_ms_t *esd = NULL; + + /* Alloc space */ + if (!(esd = (jpwl_esd_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_esd_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for ESD MS\n"); + return NULL; + }; + + /* if relative sensitivity, activate byte range mode */ + if (senst == 0) + addrm = 1; + + /* size of sensval's ... */ + if ((ad_size != 0) && (ad_size != 2) && (ad_size != 4)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address size %d for ESD MS is forbidden\n", ad_size); + return NULL; + } + if ((se_size != 1) && (se_size != 2)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Sensitivity size %d for ESD MS is forbidden\n", se_size); + return NULL; + } + + /* ... depends on the addressing mode */ + switch (addrm) { + + /* packet mode */ + case (0): + ad_size = 0; /* as per the standard */ + esd->sensval_size = (unsigned int)se_size; + break; + + /* byte range */ + case (1): + /* auto sense address size */ + if (ad_size == 0) + /* if there are more than 66% of (2^16 - 1) bytes, switch to 4 bytes + (we keep space for possible EPBs being inserted) */ + ad_size = (j2k->cstr_info->codestream_size > (1 * 65535 / 3)) ? 4 : 2; + esd->sensval_size = ad_size + ad_size + se_size; + break; + + /* packet range */ + case (2): + /* auto sense address size */ + if (ad_size == 0) + /* if there are more than 2^16 - 1 packets, switch to 4 bytes */ + ad_size = (j2k->cstr_info->packno > 65535) ? 4 : 2; + esd->sensval_size = ad_size + ad_size + se_size; + break; + + case (3): + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is unimplemented\n", addrm); + return NULL; + + default: + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is forbidden\n", addrm); + return NULL; + } + + /* set or unset sensitivity values */ + if (svalnum <= 0) { + + switch (senst) { + + /* just based on the portions of a codestream */ + case (0): + /* MH + no. of THs + no. of packets */ + svalnum = 1 + (j2k->cstr_info->tw * j2k->cstr_info->th) * (1 + j2k->cstr_info->packno); + break; + + /* all the ones that are based on the packets */ + default: + if (tileno < 0) + /* MH: all the packets and all the tiles info is written */ + svalnum = j2k->cstr_info->tw * j2k->cstr_info->th * j2k->cstr_info->packno; + else + /* TPH: only that tile info is written */ + svalnum = j2k->cstr_info->packno; + break; + + } + } + + /* fill private fields */ + esd->senst = senst; + esd->ad_size = ad_size; + esd->se_size = se_size; + esd->addrm = addrm; + esd->svalnum = svalnum; + esd->numcomps = j2k->image->numcomps; + esd->tileno = tileno; + + /* Set the ESD parameters */ + /* length, excluding data field */ + if (esd->numcomps < 257) + esd->Lesd = 4 + (unsigned short int) (esd->svalnum * esd->sensval_size); + else + esd->Lesd = 5 + (unsigned short int) (esd->svalnum * esd->sensval_size); + + /* component data field */ + if (comp >= 0) + esd->Cesd = comp; + else + /* we are averaging */ + esd->Cesd = 0; + + /* Pesd field */ + esd->Pesd = 0x00; + esd->Pesd |= (esd->addrm & 0x03) << 6; /* addressing mode */ + esd->Pesd |= (esd->senst & 0x07) << 3; /* sensitivity type */ + esd->Pesd |= ((esd->se_size >> 1) & 0x01) << 2; /* sensitivity size */ + esd->Pesd |= ((esd->ad_size >> 2) & 0x01) << 1; /* addressing size */ + esd->Pesd |= (comp < 0) ? 0x01 : 0x00; /* averaging components */ + + /* if pointer to sensval is NULL, we can fill data field by ourselves */ + if (!sensval) { + + /* old code moved to jpwl_esd_fill() */ + esd->data = NULL; + + } else { + /* we set the data field as the sensitivity values poinnter passed to the function */ + esd->data = (unsigned char *) sensval; + } + + return (esd); +} + +opj_bool jpwl_esd_fill(opj_j2k_t *j2k, jpwl_esd_ms_t *esd, unsigned char *buf) { + + int i; + unsigned long int vv; + unsigned long int addr1 = 0L, addr2 = 0L; + double dvalue = 0.0, Omax2, tmp, TSE = 0.0, MSE, oldMSE = 0.0, PSNR, oldPSNR = 0.0; + unsigned short int pfpvalue; + unsigned long int addrmask = 0x00000000; + opj_bool doneMH = OPJ_FALSE, doneTPH = OPJ_FALSE; + + /* sensitivity values in image info are as follows: + - for each tile, distotile is the starting distortion for that tile, sum of all components + - for each packet in a tile, disto is the distortion reduction caused by that packet to that tile + - the TSE for a single tile should be given by distotile - sum(disto) , for all components + - the MSE for a single tile is given by TSE / nbpix , for all components + - the PSNR for a single tile is given by 10*log10( Omax^2 / MSE) , for all components + (Omax is given by 2^bpp - 1 for unsigned images and by 2^(bpp - 1) - 1 for signed images + */ + + /* browse all components and find Omax */ + Omax2 = 0.0; + for (i = 0; i < j2k->image->numcomps; i++) { + tmp = pow(2.0, (double) (j2k->image->comps[i].sgnd ? + (j2k->image->comps[i].bpp - 1) : (j2k->image->comps[i].bpp))) - 1; + if (tmp > Omax2) + Omax2 = tmp; + } + Omax2 = Omax2 * Omax2; + + /* if pointer of esd->data is not null, simply write down all the values byte by byte */ + if (esd->data) { + for (i = 0; i < (int) esd->svalnum; i++) + *(buf++) = esd->data[i]; + return OPJ_TRUE; + } + + /* addressing mask */ + if (esd->ad_size == 2) + addrmask = 0x0000FFFF; /* two bytes */ + else + addrmask = 0xFFFFFFFF; /* four bytes */ + + /* set on precise point where sensitivity starts */ + if (esd->numcomps < 257) + buf += 6; + else + buf += 7; + + /* let's fill the data fields */ + for (vv = (esd->tileno < 0) ? 0 : (j2k->cstr_info->packno * esd->tileno); vv < esd->svalnum; vv++) { + + int thistile = vv / j2k->cstr_info->packno, thispacket = vv % j2k->cstr_info->packno; + + /* skip for the hack some lines below */ + if (thistile == j2k->cstr_info->tw * j2k->cstr_info->th) + break; + + /* starting tile distortion */ + if (thispacket == 0) { + TSE = j2k->cstr_info->tile[thistile].distotile; + oldMSE = TSE / j2k->cstr_info->tile[thistile].numpix; + oldPSNR = 10.0 * log10(Omax2 / oldMSE); + } + + /* TSE */ + TSE -= j2k->cstr_info->tile[thistile].packet[thispacket].disto; + + /* MSE */ + MSE = TSE / j2k->cstr_info->tile[thistile].numpix; + + /* PSNR */ + PSNR = 10.0 * log10(Omax2 / MSE); + + /* fill the address range */ + switch (esd->addrm) { + + /* packet mode */ + case (0): + /* nothing, there is none */ + break; + + /* byte range */ + case (1): + /* start address of packet */ + addr1 = (j2k->cstr_info->tile[thistile].packet[thispacket].start_pos) & addrmask; + /* end address of packet */ + addr2 = (j2k->cstr_info->tile[thistile].packet[thispacket].end_pos) & addrmask; + break; + + /* packet range */ + case (2): + /* not implemented here */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "Addressing mode packet_range is not implemented\n"); + break; + + /* unknown addressing method */ + default: + /* not implemented here */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown addressing mode\n"); + break; + + } + + /* hack for writing relative sensitivity of MH and TPHs */ + if ((esd->senst == 0) && (thispacket == 0)) { + + /* possible MH */ + if ((thistile == 0) && !doneMH) { + /* we have to manage MH addresses */ + addr1 = 0; /* start of MH */ + addr2 = j2k->cstr_info->main_head_end; /* end of MH */ + /* set special dvalue for this MH */ + dvalue = -10.0; + doneMH = OPJ_TRUE; /* don't come here anymore */ + vv--; /* wrap back loop counter */ + + } else if (!doneTPH) { + /* we have to manage TPH addresses */ + addr1 = j2k->cstr_info->tile[thistile].start_pos; + addr2 = j2k->cstr_info->tile[thistile].end_header; + /* set special dvalue for this TPH */ + dvalue = -1.0; + doneTPH = OPJ_TRUE; /* don't come here till the next tile */ + vv--; /* wrap back loop counter */ + } + + } else + doneTPH = OPJ_FALSE; /* reset TPH counter */ + + /* write the addresses to the buffer */ + switch (esd->ad_size) { + + case (0): + /* do nothing */ + break; + + case (2): + /* two bytes */ + *(buf++) = (unsigned char) (addr1 >> 8); + *(buf++) = (unsigned char) (addr1 >> 0); + *(buf++) = (unsigned char) (addr2 >> 8); + *(buf++) = (unsigned char) (addr2 >> 0); + break; + + case (4): + /* four bytes */ + *(buf++) = (unsigned char) (addr1 >> 24); + *(buf++) = (unsigned char) (addr1 >> 16); + *(buf++) = (unsigned char) (addr1 >> 8); + *(buf++) = (unsigned char) (addr1 >> 0); + *(buf++) = (unsigned char) (addr2 >> 24); + *(buf++) = (unsigned char) (addr2 >> 16); + *(buf++) = (unsigned char) (addr2 >> 8); + *(buf++) = (unsigned char) (addr2 >> 0); + break; + + default: + /* do nothing */ + break; + } + + + /* let's fill the value field */ + switch (esd->senst) { + + /* relative sensitivity */ + case (0): + /* we just write down the packet ordering */ + if (dvalue == -10) + /* MH */ + dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */ + else if (dvalue == -1) + /* TPH */ + dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */ + else + /* packet: first is most important, and then in decreasing order + down to the last, which counts for 1 */ + dvalue = jpwl_pfp_to_double((unsigned short) (j2k->cstr_info->packno - thispacket), esd->se_size); + break; + + /* MSE */ + case (1): + /* !!! WRONG: let's put here disto field of packets !!! */ + dvalue = MSE; + break; + + /* MSE reduction */ + case (2): + dvalue = oldMSE - MSE; + oldMSE = MSE; + break; + + /* PSNR */ + case (3): + dvalue = PSNR; + break; + + /* PSNR increase */ + case (4): + dvalue = PSNR - oldPSNR; + oldPSNR = PSNR; + break; + + /* MAXERR */ + case (5): + dvalue = 0.0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "MAXERR sensitivity mode is not implemented\n"); + break; + + /* TSE */ + case (6): + dvalue = TSE; + break; + + /* reserved */ + case (7): + dvalue = 0.0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "Reserved sensitivity mode is not implemented\n"); + break; + + default: + dvalue = 0.0; + break; + } + + /* compute the pseudo-floating point value */ + pfpvalue = jpwl_double_to_pfp(dvalue, esd->se_size); + + /* write the pfp value to the buffer */ + switch (esd->se_size) { + + case (1): + /* one byte */ + *(buf++) = (unsigned char) (pfpvalue >> 0); + break; + + case (2): + /* two bytes */ + *(buf++) = (unsigned char) (pfpvalue >> 8); + *(buf++) = (unsigned char) (pfpvalue >> 0); + break; + } + + } + + return OPJ_TRUE; +} + +void jpwl_esd_write(opj_j2k_t *j2k, jpwl_esd_ms_t *esd, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_ESD >> 8); + *(buf++) = (unsigned char) (J2K_MS_ESD >> 0); + + /* Lesd */ + *(buf++) = (unsigned char) (esd->Lesd >> 8); + *(buf++) = (unsigned char) (esd->Lesd >> 0); + + /* Cesd */ + if (esd->numcomps >= 257) + *(buf++) = (unsigned char) (esd->Cesd >> 8); + *(buf++) = (unsigned char) (esd->Cesd >> 0); + + /* Pesd */ + *(buf++) = (unsigned char) (esd->Pesd >> 0); + + /* Data */ + if (esd->numcomps < 257) + memset(buf, 0xAA, (size_t) esd->Lesd - 4); + /*memcpy(buf, esd->data, (size_t) esd->Lesd - 4);*/ + else + memset(buf, 0xAA, (size_t) esd->Lesd - 5); + /*memcpy(buf, esd->data, (size_t) esd->Lesd - 5);*/ + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_ESD, -1, esd->Lesd + 2); + +} + +unsigned short int jpwl_double_to_pfp(double V, int bytes) { + + unsigned short int em, e, m; + + switch (bytes) { + + case (1): + + if (V < MIN_V1) { + e = 0x0000; + m = 0x0000; + } else if (V > MAX_V1) { + e = 0x000F; + m = 0x000F; + } else { + e = (unsigned short int) (floor(log(V) * 1.44269504088896) / 4.0); + m = (unsigned short int) (0.5 + (V / (pow(2.0, (double) (4 * e))))); + } + em = ((e & 0x000F) << 4) + (m & 0x000F); + break; + + case (2): + + if (V < MIN_V2) { + e = 0x0000; + m = 0x0000; + } else if (V > MAX_V2) { + e = 0x001F; + m = 0x07FF; + } else { + e = (unsigned short int) floor(log(V) * 1.44269504088896) + 15; + m = (unsigned short int) (0.5 + 2048.0 * ((V / (pow(2.0, (double) e - 15.0))) - 1.0)); + } + em = ((e & 0x001F) << 11) + (m & 0x07FF); + break; + + default: + + em = 0x0000; + break; + }; + + return em; +} + +double jpwl_pfp_to_double(unsigned short int em, int bytes) { + + double V; + + switch (bytes) { + + case 1: + V = (double) (em & 0x0F) * pow(2.0, (double) (em & 0xF0)); + break; + + case 2: + + V = pow(2.0, (double) ((em & 0xF800) >> 11) - 15.0) * (1.0 + (double) (em & 0x07FF) / 2048.0); + break; + + default: + V = 0.0; + break; + + } + + return V; + +} + +opj_bool jpwl_update_info(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int jwmarker_num) { + + int mm; + unsigned long int addlen; + + opj_codestream_info_t *info = j2k->cstr_info; + int tileno, tpno, packno, numtiles = info->th * info->tw, numpacks = info->packno; + + if (!j2k || !jwmarker ) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "J2K handle or JPWL markers list badly allocated\n"); + return OPJ_FALSE; + } + + /* main_head_end: how many markers are there before? */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->main_head_end) + addlen += jwmarker[mm].len + 2; + info->main_head_end += addlen; + + /* codestream_size: always increment with all markers */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + addlen += jwmarker[mm].len + 2; + info->codestream_size += addlen; + + /* navigate through all the tiles */ + for (tileno = 0; tileno < numtiles; tileno++) { + + /* start_pos: increment with markers before SOT */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].start_pos += addlen; + + /* end_header: increment with markers before of it */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_header) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].end_header += addlen; + + /* end_pos: increment with markers before the end of this tile */ + /* code is disabled, since according to JPWL no markers can be beyond TPH */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].end_pos += addlen; + + /* navigate through all the tile parts */ + for (tpno = 0; tpno < info->tile[tileno].num_tps; tpno++) { + + /* start_pos: increment with markers before SOT */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_start_pos += addlen; + + /* end_header: increment with markers before of it */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_header) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_end_header += addlen; + + /* end_pos: increment with markers before the end of this tile part */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_end_pos += addlen; + + } + + /* navigate through all the packets in this tile */ + for (packno = 0; packno < numpacks; packno++) { + + /* start_pos: increment with markers before the packet */ + /* disabled for the same reason as before */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos <= (unsigned long int) info->tile[tileno].packet[packno].start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].packet[packno].start_pos += addlen; + + /* end_ph_pos: increment with markers before the packet */ + /* disabled for the same reason as before */ + /*addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].end_ph_pos) + addlen += jwmarker[mm].len + 2;*/ + info->tile[tileno].packet[packno].end_ph_pos += addlen; + + /* end_pos: increment if marker is before the end of packet */ + /* disabled for the same reason as before */ + /*addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].end_pos) + addlen += jwmarker[mm].len + 2;*/ + info->tile[tileno].packet[packno].end_pos += addlen; + + } + } + + /* reorder the markers list */ + + return OPJ_TRUE; +} + +#endif /* USE_JPWL */ diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/rs.c b/openjpeg-dotnet/libopenjpeg/jpwl/rs.c new file mode 100644 index 0000000..0841c63 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/rs.c @@ -0,0 +1,597 @@ + /* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef USE_JPWL + +/** +@file rs.c +@brief Functions used to compute the Reed-Solomon parity and check of byte arrays + +*/ + +/** + * Reed-Solomon coding and decoding + * Phil Karn (karn@ka9q.ampr.org) September 1996 + * + * This file is derived from the program "new_rs_erasures.c" by Robert + * Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy + * (harit@spectra.eng.hawaii.edu), Aug 1995 + * + * I've made changes to improve performance, clean up the code and make it + * easier to follow. Data is now passed to the encoding and decoding functions + * through arguments rather than in global arrays. The decode function returns + * the number of corrected symbols, or -1 if the word is uncorrectable. + * + * This code supports a symbol size from 2 bits up to 16 bits, + * implying a block size of 3 2-bit symbols (6 bits) up to 65535 + * 16-bit symbols (1,048,560 bits). The code parameters are set in rs.h. + * + * Note that if symbols larger than 8 bits are used, the type of each + * data array element switches from unsigned char to unsigned int. The + * caller must ensure that elements larger than the symbol range are + * not passed to the encoder or decoder. + * + */ +#include +#include +#include "rs.h" + +/* This defines the type used to store an element of the Galois Field + * used by the code. Make sure this is something larger than a char if + * if anything larger than GF(256) is used. + * + * Note: unsigned char will work up to GF(256) but int seems to run + * faster on the Pentium. + */ +typedef int gf; + +/* KK = number of information symbols */ +static int KK; + +/* Primitive polynomials - see Lin & Costello, Appendix A, + * and Lee & Messerschmitt, p. 453. + */ +#if(MM == 2)/* Admittedly silly */ +int Pp[MM+1] = { 1, 1, 1 }; + +#elif(MM == 3) +/* 1 + x + x^3 */ +int Pp[MM+1] = { 1, 1, 0, 1 }; + +#elif(MM == 4) +/* 1 + x + x^4 */ +int Pp[MM+1] = { 1, 1, 0, 0, 1 }; + +#elif(MM == 5) +/* 1 + x^2 + x^5 */ +int Pp[MM+1] = { 1, 0, 1, 0, 0, 1 }; + +#elif(MM == 6) +/* 1 + x + x^6 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1 }; + +#elif(MM == 7) +/* 1 + x^3 + x^7 */ +int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 1 }; + +#elif(MM == 8) +/* 1+x^2+x^3+x^4+x^8 */ +int Pp[MM+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 }; + +#elif(MM == 9) +/* 1+x^4+x^9 */ +int Pp[MM+1] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + +#elif(MM == 10) +/* 1+x^3+x^10 */ +int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 11) +/* 1+x^2+x^11 */ +int Pp[MM+1] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 12) +/* 1+x+x^4+x^6+x^12 */ +int Pp[MM+1] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 13) +/* 1+x+x^3+x^4+x^13 */ +int Pp[MM+1] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 14) +/* 1+x+x^6+x^10+x^14 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + +#elif(MM == 15) +/* 1+x+x^15 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 16) +/* 1+x+x^3+x^12+x^16 */ +int Pp[MM+1] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 }; + +#else +#error "MM must be in range 2-16" +#endif + +/* Alpha exponent for the first root of the generator polynomial */ +#define B0 0 /* Different from the default 1 */ + +/* index->polynomial form conversion table */ +gf Alpha_to[NN + 1]; + +/* Polynomial->index form conversion table */ +gf Index_of[NN + 1]; + +/* No legal value in index form represents zero, so + * we need a special value for this purpose + */ +#define A0 (NN) + +/* Generator polynomial g(x) + * Degree of g(x) = 2*TT + * has roots @**B0, @**(B0+1), ... ,@^(B0+2*TT-1) + */ +/*gf Gg[NN - KK + 1];*/ +gf Gg[NN - 1]; + +/* Compute x % NN, where NN is 2**MM - 1, + * without a slow divide + */ +static /*inline*/ gf +modnn(int x) +{ + while (x >= NN) { + x -= NN; + x = (x >> MM) + (x & NN); + } + return x; +} + +/*#define min(a,b) ((a) < (b) ? (a) : (b))*/ + +#define CLEAR(a,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = 0;\ + } + +#define COPY(a,b,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = (b)[ci];\ + } +#define COPYDOWN(a,b,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = (b)[ci];\ + } + +void init_rs(int k) +{ + KK = k; + if (KK >= NN) { + printf("KK must be less than 2**MM - 1\n"); + exit(1); + } + + generate_gf(); + gen_poly(); +} + +/* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; + polynomial form -> index form index_of[j=alpha**i] = i + alpha=2 is the primitive element of GF(2**m) + HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows: + Let @ represent the primitive element commonly called "alpha" that + is the root of the primitive polynomial p(x). Then in GF(2^m), for any + 0 <= i <= 2^m-2, + @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation + of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for + example the polynomial representation of @^5 would be given by the binary + representation of the integer "alpha_to[5]". + Similarily, index_of[] can be used as follows: + As above, let @ represent the primitive element of GF(2^m) that is + the root of the primitive polynomial p(x). In order to find the power + of @ (alpha) that has the polynomial representation + a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + we consider the integer "i" whose binary representation with a(0) being LSB + and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry + "index_of[i]". Now, @^index_of[i] is that element whose polynomial + representation is (a(0),a(1),a(2),...,a(m-1)). + NOTE: + The element alpha_to[2^m-1] = 0 always signifying that the + representation of "@^infinity" = 0 is (0,0,0,...,0). + Similarily, the element index_of[0] = A0 always signifying + that the power of alpha which has the polynomial representation + (0,0,...,0) is "infinity". + +*/ + +void +generate_gf(void) +{ + register int i, mask; + + mask = 1; + Alpha_to[MM] = 0; + for (i = 0; i < MM; i++) { + Alpha_to[i] = mask; + Index_of[Alpha_to[i]] = i; + /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */ + if (Pp[i] != 0) + Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */ + mask <<= 1; /* single left-shift */ + } + Index_of[Alpha_to[MM]] = MM; + /* + * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by + * poly-repr of @^i shifted left one-bit and accounting for any @^MM + * term that may occur when poly-repr of @^i is shifted. + */ + mask >>= 1; + for (i = MM + 1; i < NN; i++) { + if (Alpha_to[i - 1] >= mask) + Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1); + else + Alpha_to[i] = Alpha_to[i - 1] << 1; + Index_of[Alpha_to[i]] = i; + } + Index_of[0] = A0; + Alpha_to[NN] = 0; +} + + +/* + * Obtain the generator polynomial of the TT-error correcting, length + * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0, + * ... ,(2*TT-1) + * + * Examples: + * + * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2. + * g(x) = (x+@) (x+@**2) + * + * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4. + * g(x) = (x+1) (x+@) (x+@**2) (x+@**3) + */ +void +gen_poly(void) +{ + register int i, j; + + Gg[0] = Alpha_to[B0]; + Gg[1] = 1; /* g(x) = (X+@**B0) initially */ + for (i = 2; i <= NN - KK; i++) { + Gg[i] = 1; + /* + * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by + * (@**(B0+i-1) + x) + */ + for (j = i - 1; j > 0; j--) + if (Gg[j] != 0) + Gg[j] = Gg[j - 1] ^ Alpha_to[modnn((Index_of[Gg[j]]) + B0 + i - 1)]; + else + Gg[j] = Gg[j - 1]; + /* Gg[0] can never be zero */ + Gg[0] = Alpha_to[modnn((Index_of[Gg[0]]) + B0 + i - 1)]; + } + /* convert Gg[] to index form for quicker encoding */ + for (i = 0; i <= NN - KK; i++) + Gg[i] = Index_of[Gg[i]]; +} + + +/* + * take the string of symbols in data[i], i=0..(k-1) and encode + * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[] + * is input and bb[] is output in polynomial form. Encoding is done by using + * a feedback shift register with appropriate connections specified by the + * elements of Gg[], which was generated above. Codeword is c(X) = + * data(X)*X**(NN-KK)+ b(X) + */ +int +encode_rs(dtype *data, dtype *bb) +{ + register int i, j; + gf feedback; + + CLEAR(bb,NN-KK); + for (i = KK - 1; i >= 0; i--) { +#if (MM != 8) + if(data[i] > NN) + return -1; /* Illegal symbol */ +#endif + feedback = Index_of[data[i] ^ bb[NN - KK - 1]]; + if (feedback != A0) { /* feedback term is non-zero */ + for (j = NN - KK - 1; j > 0; j--) + if (Gg[j] != A0) + bb[j] = bb[j - 1] ^ Alpha_to[modnn(Gg[j] + feedback)]; + else + bb[j] = bb[j - 1]; + bb[0] = Alpha_to[modnn(Gg[0] + feedback)]; + } else { /* feedback term is zero. encoder becomes a + * single-byte shifter */ + for (j = NN - KK - 1; j > 0; j--) + bb[j] = bb[j - 1]; + bb[0] = 0; + } + } + return 0; +} + +/* + * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful, + * writes the codeword into data[] itself. Otherwise data[] is unaltered. + * + * Return number of symbols corrected, or -1 if codeword is illegal + * or uncorrectable. + * + * First "no_eras" erasures are declared by the calling program. Then, the + * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). + * If the number of channel errors is not greater than "t_after_eras" the + * transmitted codeword will be recovered. Details of algorithm can be found + * in R. Blahut's "Theory ... of Error-Correcting Codes". + */ +int +eras_dec_rs(dtype *data, int *eras_pos, int no_eras) +{ + int deg_lambda, el, deg_omega; + int i, j, r; + gf u,q,tmp,num1,num2,den,discr_r; + gf recd[NN]; + /* Err+Eras Locator poly and syndrome poly */ + /*gf lambda[NN-KK + 1], s[NN-KK + 1]; + gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1]; + gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];*/ + gf lambda[NN + 1], s[NN + 1]; + gf b[NN + 1], t[NN + 1], omega[NN + 1]; + gf root[NN], reg[NN + 1], loc[NN]; + int syn_error, count; + + /* data[] is in polynomial form, copy and convert to index form */ + for (i = NN-1; i >= 0; i--){ +#if (MM != 8) + if(data[i] > NN) + return -1; /* Illegal symbol */ +#endif + recd[i] = Index_of[data[i]]; + } + /* first form the syndromes; i.e., evaluate recd(x) at roots of g(x) + * namely @**(B0+i), i = 0, ... ,(NN-KK-1) + */ + syn_error = 0; + for (i = 1; i <= NN-KK; i++) { + tmp = 0; + for (j = 0; j < NN; j++) + if (recd[j] != A0) /* recd[j] in index form */ + tmp ^= Alpha_to[modnn(recd[j] + (B0+i-1)*j)]; + syn_error |= tmp; /* set flag if non-zero syndrome => + * error */ + /* store syndrome in index form */ + s[i] = Index_of[tmp]; + } + if (!syn_error) { + /* + * if syndrome is zero, data[] is a codeword and there are no + * errors to correct. So return data[] unmodified + */ + return 0; + } + CLEAR(&lambda[1],NN-KK); + lambda[0] = 1; + if (no_eras > 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = Alpha_to[eras_pos[0]]; + for (i = 1; i < no_eras; i++) { + u = eras_pos[i]; + for (j = i+1; j > 0; j--) { + tmp = Index_of[lambda[j - 1]]; + if(tmp != A0) + lambda[j] ^= Alpha_to[modnn(u + tmp)]; + } + } +#ifdef ERASURE_DEBUG + /* find roots of the erasure location polynomial */ + for(i=1;i<=no_eras;i++) + reg[i] = Index_of[lambda[i]]; + count = 0; + for (i = 1; i <= NN; i++) { + q = 1; + for (j = 1; j <= no_eras; j++) + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + if (!q) { + /* store root and error location + * number indices + */ + root[count] = i; + loc[count] = NN - i; + count++; + } + } + if (count != no_eras) { + printf("\n lambda(x) is WRONG\n"); + return -1; + } +#ifndef NO_PRINT + printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif +#endif + } + for(i=0;i 0; j--) + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + if (!q) { + /* store root (index-form) and error location number */ + root[count] = i; + loc[count] = NN - i; + count++; + } + } + +#ifdef DEBUG + printf("\n Final error positions:\t"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + return -1; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**(NN-KK)). in index form. Also find deg(omega). + */ + deg_omega = 0; + for (i = 0; i < NN-KK;i++){ + tmp = 0; + j = (deg_lambda < i) ? deg_lambda : i; + for(;j >= 0; j--){ + if ((s[i + 1 - j] != A0) && (lambda[j] != A0)) + tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])]; + } + if(tmp != 0) + deg_omega = i; + omega[i] = Index_of[tmp]; + } + omega[NN-KK] = A0; + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count-1; j >=0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= Alpha_to[modnn(omega[i] + i * root[j])]; + } + num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { + if(lambda[i+1] != A0) + den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])]; + } + if (den == 0) { +#ifdef DEBUG + printf("\n ERROR: denominator = 0\n"); +#endif + return -1; + } + /* Apply error to data */ + if (num1 != 0) { + data[loc[j]] ^= Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])]; + } + } + return count; +} + + +#endif /* USE_JPWL */ diff --git a/openjpeg-dotnet/libopenjpeg/jpwl/rs.h b/openjpeg-dotnet/libopenjpeg/jpwl/rs.h new file mode 100644 index 0000000..7d02a47 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/jpwl/rs.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef USE_JPWL + +/** +@file rs.h +@brief Functions used to compute Reed-Solomon parity and check of byte arrays + +*/ + +#ifndef __RS_HEADER__ +#define __RS_HEADER__ + +/** Global definitions for Reed-Solomon encoder/decoder + * Phil Karn KA9Q, September 1996 + * + * The parameters MM and KK specify the Reed-Solomon code parameters. + * + * Set MM to be the size of each code symbol in bits. The Reed-Solomon + * block size will then be NN = 2**M - 1 symbols. Supported values are + * defined in rs.c. + * + * Set KK to be the number of data symbols in each block, which must be + * less than the block size. The code will then be able to correct up + * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with + * each error counting as two erasures. + */ +#define MM 8 /* RS code over GF(2**MM) - change to suit */ + +/* KK defined in rs.c */ + +#define NN ((1 << MM) - 1) + +#if (MM <= 8) +typedef unsigned char dtype; +#else +typedef unsigned int dtype; +#endif + +/** Initialization function */ +void init_rs(int); + +/** These two functions *must* be called in this order (e.g., + * by init_rs()) before any encoding/decoding + */ +void generate_gf(void); /* Generate Galois Field */ +void gen_poly(void); /* Generate generator polynomial */ + +/** Reed-Solomon encoding + * data[] is the input block, parity symbols are placed in bb[] + * bb[] may lie past the end of the data, e.g., for (255,223): + * encode_rs(&data[0],&data[223]); + */ +int encode_rs(dtype data[], dtype bb[]); + +/** Reed-Solomon erasures-and-errors decoding + * The received block goes into data[], and a list of zero-origin + * erasure positions, if any, goes in eras_pos[] with a count in no_eras. + * + * The decoder corrects the symbols in place, if possible and returns + * the number of corrected symbols. If the codeword is illegal or + * uncorrectible, the data array is unchanged and -1 is returned + */ +int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); + +/** +Computes the minimum between two integers +@param a first integer to compare +@param b second integer to compare +@return returns the minimum integer between a and b +*/ +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif /* min */ + +#endif /* __RS_HEADER__ */ + + +#endif /* USE_JPWL */ diff --git a/openjpeg-dotnet/libopenjpeg/mct.c b/openjpeg-dotnet/libopenjpeg/mct.c new file mode 100644 index 0000000..870993b --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/mct.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef __SSE__ +#include +#endif + +#include "opj_includes.h" + +/* */ +/* This table contains the norms of the basis function of the reversible MCT. */ +/* */ +static const double mct_norms[3] = { 1.732, .8292, .8292 }; + +/* */ +/* This table contains the norms of the basis function of the irreversible MCT. */ +/* */ +static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 }; + +/* */ +/* Foward reversible MCT. */ +/* */ +void mct_encode( + int* restrict c0, + int* restrict c1, + int* restrict c2, + int n) +{ + int i; + for(i = 0; i < n; ++i) { + int r = c0[i]; + int g = c1[i]; + int b = c2[i]; + int y = (r + (g * 2) + b) >> 2; + int u = b - g; + int v = r - g; + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse reversible MCT. */ +/* */ +void mct_decode( + int* restrict c0, + int* restrict c1, + int* restrict c2, + int n) +{ + int i; + for (i = 0; i < n; ++i) { + int y = c0[i]; + int u = c1[i]; + int v = c2[i]; + int g = y - ((u + v) >> 2); + int r = v + g; + int b = u + g; + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of reversible MCT. */ +/* */ +double mct_getnorm(int compno) { + return mct_norms[compno]; +} + +/* */ +/* Foward irreversible MCT. */ +/* */ +void mct_encode_real( + int* restrict c0, + int* restrict c1, + int* restrict c2, + int n) +{ + int i; + for(i = 0; i < n; ++i) { + int r = c0[i]; + int g = c1[i]; + int b = c2[i]; + int y = fix_mul(r, 2449) + fix_mul(g, 4809) + fix_mul(b, 934); + int u = -fix_mul(r, 1382) - fix_mul(g, 2714) + fix_mul(b, 4096); + int v = fix_mul(r, 4096) - fix_mul(g, 3430) - fix_mul(b, 666); + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse irreversible MCT. */ +/* */ +void mct_decode_real( + float* restrict c0, + float* restrict c1, + float* restrict c2, + int n) +{ + int i; +#ifdef __SSE__ + __m128 vrv, vgu, vgv, vbu; + vrv = _mm_set1_ps(1.402f); + vgu = _mm_set1_ps(0.34413f); + vgv = _mm_set1_ps(0.71414f); + vbu = _mm_set1_ps(1.772f); + for (i = 0; i < (n >> 3); ++i) { + __m128 vy, vu, vv; + __m128 vr, vg, vb; + + vy = _mm_load_ps(c0); + vu = _mm_load_ps(c1); + vv = _mm_load_ps(c2); + vr = _mm_add_ps(vy, _mm_mul_ps(vv, vrv)); + vg = _mm_sub_ps(_mm_sub_ps(vy, _mm_mul_ps(vu, vgu)), _mm_mul_ps(vv, vgv)); + vb = _mm_add_ps(vy, _mm_mul_ps(vu, vbu)); + _mm_store_ps(c0, vr); + _mm_store_ps(c1, vg); + _mm_store_ps(c2, vb); + c0 += 4; + c1 += 4; + c2 += 4; + + vy = _mm_load_ps(c0); + vu = _mm_load_ps(c1); + vv = _mm_load_ps(c2); + vr = _mm_add_ps(vy, _mm_mul_ps(vv, vrv)); + vg = _mm_sub_ps(_mm_sub_ps(vy, _mm_mul_ps(vu, vgu)), _mm_mul_ps(vv, vgv)); + vb = _mm_add_ps(vy, _mm_mul_ps(vu, vbu)); + _mm_store_ps(c0, vr); + _mm_store_ps(c1, vg); + _mm_store_ps(c2, vb); + c0 += 4; + c1 += 4; + c2 += 4; + } + n &= 7; +#endif + for(i = 0; i < n; ++i) { + float y = c0[i]; + float u = c1[i]; + float v = c2[i]; + float r = y + (v * 1.402f); + float g = y - (u * 0.34413f) - (v * (0.71414f)); + float b = y + (u * 1.772f); + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of irreversible MCT. */ +/* */ +double mct_getnorm_real(int compno) { + return mct_norms_real[compno]; +} diff --git a/openjpeg-dotnet/libopenjpeg/mct.h b/openjpeg-dotnet/libopenjpeg/mct.h new file mode 100644 index 0000000..84e3f8a --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/mct.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __MCT_H +#define __MCT_H +/** +@file mct.h +@brief Implementation of a multi-component transforms (MCT) + +The functions in MCT.C have for goal to realize reversible and irreversible multicomponent +transform. The functions in MCT.C are used by some function in TCD.C. +*/ + +/** @defgroup MCT MCT - Implementation of a multi-component transform */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Apply a reversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode(int *c0, int *c1, int *c2, int n); +/** +Apply a reversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode(int *c0, int *c1, int *c2, int n); +/** +Get norm of the basis function used for the reversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +double mct_getnorm(int compno); + +/** +Apply an irreversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode_real(int *c0, int *c1, int *c2, int n); +/** +Apply an irreversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode_real(float* c0, float* c1, float* c2, int n); +/** +Get norm of the basis function used for the irreversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +double mct_getnorm_real(int compno); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MCT_H */ diff --git a/openjpeg-dotnet/libopenjpeg/mqc.c b/openjpeg-dotnet/libopenjpeg/mqc.c new file mode 100644 index 0000000..14129fb --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/mqc.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Output a byte, doing bit-stuffing if necessary. +After a 0xff byte, the next byte must be smaller than 0x90. +@param mqc MQC handle +*/ +static void mqc_byteout(opj_mqc_t *mqc); +/** +Renormalize mqc->a and mqc->c while encoding, so that mqc->a stays between 0x8000 and 0x10000 +@param mqc MQC handle +*/ +static void mqc_renorme(opj_mqc_t *mqc); +/** +Encode the most probable symbol +@param mqc MQC handle +*/ +static void mqc_codemps(opj_mqc_t *mqc); +/** +Encode the most least symbol +@param mqc MQC handle +*/ +static void mqc_codelps(opj_mqc_t *mqc); +/** +Fill mqc->c with 1's for flushing +@param mqc MQC handle +*/ +static void mqc_setbits(opj_mqc_t *mqc); +/** +FIXME: documentation ??? +@param mqc MQC handle +@return +*/ +static INLINE int mqc_mpsexchange(opj_mqc_t *const mqc); +/** +FIXME: documentation ??? +@param mqc MQC handle +@return +*/ +static INLINE int mqc_lpsexchange(opj_mqc_t *const mqc); +/** +Input a byte +@param mqc MQC handle +*/ +static INLINE void mqc_bytein(opj_mqc_t *const mqc); +/** +Renormalize mqc->a and mqc->c while decoding +@param mqc MQC handle +*/ +static INLINE void mqc_renormd(opj_mqc_t *const mqc); +/*@}*/ + +/*@}*/ + +/* */ +/* This array defines all the possible states for a context. */ +/* */ +static opj_mqc_state_t mqc_states[47 * 2] = { + {0x5601, 0, &mqc_states[2], &mqc_states[3]}, + {0x5601, 1, &mqc_states[3], &mqc_states[2]}, + {0x3401, 0, &mqc_states[4], &mqc_states[12]}, + {0x3401, 1, &mqc_states[5], &mqc_states[13]}, + {0x1801, 0, &mqc_states[6], &mqc_states[18]}, + {0x1801, 1, &mqc_states[7], &mqc_states[19]}, + {0x0ac1, 0, &mqc_states[8], &mqc_states[24]}, + {0x0ac1, 1, &mqc_states[9], &mqc_states[25]}, + {0x0521, 0, &mqc_states[10], &mqc_states[58]}, + {0x0521, 1, &mqc_states[11], &mqc_states[59]}, + {0x0221, 0, &mqc_states[76], &mqc_states[66]}, + {0x0221, 1, &mqc_states[77], &mqc_states[67]}, + {0x5601, 0, &mqc_states[14], &mqc_states[13]}, + {0x5601, 1, &mqc_states[15], &mqc_states[12]}, + {0x5401, 0, &mqc_states[16], &mqc_states[28]}, + {0x5401, 1, &mqc_states[17], &mqc_states[29]}, + {0x4801, 0, &mqc_states[18], &mqc_states[28]}, + {0x4801, 1, &mqc_states[19], &mqc_states[29]}, + {0x3801, 0, &mqc_states[20], &mqc_states[28]}, + {0x3801, 1, &mqc_states[21], &mqc_states[29]}, + {0x3001, 0, &mqc_states[22], &mqc_states[34]}, + {0x3001, 1, &mqc_states[23], &mqc_states[35]}, + {0x2401, 0, &mqc_states[24], &mqc_states[36]}, + {0x2401, 1, &mqc_states[25], &mqc_states[37]}, + {0x1c01, 0, &mqc_states[26], &mqc_states[40]}, + {0x1c01, 1, &mqc_states[27], &mqc_states[41]}, + {0x1601, 0, &mqc_states[58], &mqc_states[42]}, + {0x1601, 1, &mqc_states[59], &mqc_states[43]}, + {0x5601, 0, &mqc_states[30], &mqc_states[29]}, + {0x5601, 1, &mqc_states[31], &mqc_states[28]}, + {0x5401, 0, &mqc_states[32], &mqc_states[28]}, + {0x5401, 1, &mqc_states[33], &mqc_states[29]}, + {0x5101, 0, &mqc_states[34], &mqc_states[30]}, + {0x5101, 1, &mqc_states[35], &mqc_states[31]}, + {0x4801, 0, &mqc_states[36], &mqc_states[32]}, + {0x4801, 1, &mqc_states[37], &mqc_states[33]}, + {0x3801, 0, &mqc_states[38], &mqc_states[34]}, + {0x3801, 1, &mqc_states[39], &mqc_states[35]}, + {0x3401, 0, &mqc_states[40], &mqc_states[36]}, + {0x3401, 1, &mqc_states[41], &mqc_states[37]}, + {0x3001, 0, &mqc_states[42], &mqc_states[38]}, + {0x3001, 1, &mqc_states[43], &mqc_states[39]}, + {0x2801, 0, &mqc_states[44], &mqc_states[38]}, + {0x2801, 1, &mqc_states[45], &mqc_states[39]}, + {0x2401, 0, &mqc_states[46], &mqc_states[40]}, + {0x2401, 1, &mqc_states[47], &mqc_states[41]}, + {0x2201, 0, &mqc_states[48], &mqc_states[42]}, + {0x2201, 1, &mqc_states[49], &mqc_states[43]}, + {0x1c01, 0, &mqc_states[50], &mqc_states[44]}, + {0x1c01, 1, &mqc_states[51], &mqc_states[45]}, + {0x1801, 0, &mqc_states[52], &mqc_states[46]}, + {0x1801, 1, &mqc_states[53], &mqc_states[47]}, + {0x1601, 0, &mqc_states[54], &mqc_states[48]}, + {0x1601, 1, &mqc_states[55], &mqc_states[49]}, + {0x1401, 0, &mqc_states[56], &mqc_states[50]}, + {0x1401, 1, &mqc_states[57], &mqc_states[51]}, + {0x1201, 0, &mqc_states[58], &mqc_states[52]}, + {0x1201, 1, &mqc_states[59], &mqc_states[53]}, + {0x1101, 0, &mqc_states[60], &mqc_states[54]}, + {0x1101, 1, &mqc_states[61], &mqc_states[55]}, + {0x0ac1, 0, &mqc_states[62], &mqc_states[56]}, + {0x0ac1, 1, &mqc_states[63], &mqc_states[57]}, + {0x09c1, 0, &mqc_states[64], &mqc_states[58]}, + {0x09c1, 1, &mqc_states[65], &mqc_states[59]}, + {0x08a1, 0, &mqc_states[66], &mqc_states[60]}, + {0x08a1, 1, &mqc_states[67], &mqc_states[61]}, + {0x0521, 0, &mqc_states[68], &mqc_states[62]}, + {0x0521, 1, &mqc_states[69], &mqc_states[63]}, + {0x0441, 0, &mqc_states[70], &mqc_states[64]}, + {0x0441, 1, &mqc_states[71], &mqc_states[65]}, + {0x02a1, 0, &mqc_states[72], &mqc_states[66]}, + {0x02a1, 1, &mqc_states[73], &mqc_states[67]}, + {0x0221, 0, &mqc_states[74], &mqc_states[68]}, + {0x0221, 1, &mqc_states[75], &mqc_states[69]}, + {0x0141, 0, &mqc_states[76], &mqc_states[70]}, + {0x0141, 1, &mqc_states[77], &mqc_states[71]}, + {0x0111, 0, &mqc_states[78], &mqc_states[72]}, + {0x0111, 1, &mqc_states[79], &mqc_states[73]}, + {0x0085, 0, &mqc_states[80], &mqc_states[74]}, + {0x0085, 1, &mqc_states[81], &mqc_states[75]}, + {0x0049, 0, &mqc_states[82], &mqc_states[76]}, + {0x0049, 1, &mqc_states[83], &mqc_states[77]}, + {0x0025, 0, &mqc_states[84], &mqc_states[78]}, + {0x0025, 1, &mqc_states[85], &mqc_states[79]}, + {0x0015, 0, &mqc_states[86], &mqc_states[80]}, + {0x0015, 1, &mqc_states[87], &mqc_states[81]}, + {0x0009, 0, &mqc_states[88], &mqc_states[82]}, + {0x0009, 1, &mqc_states[89], &mqc_states[83]}, + {0x0005, 0, &mqc_states[90], &mqc_states[84]}, + {0x0005, 1, &mqc_states[91], &mqc_states[85]}, + {0x0001, 0, &mqc_states[90], &mqc_states[86]}, + {0x0001, 1, &mqc_states[91], &mqc_states[87]}, + {0x5601, 0, &mqc_states[92], &mqc_states[92]}, + {0x5601, 1, &mqc_states[93], &mqc_states[93]}, +}; + +/* +========================================================== + local functions +========================================================== +*/ + +static void mqc_byteout(opj_mqc_t *mqc) { + if (*mqc->bp == 0xff) { + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + if ((mqc->c & 0x8000000) == 0) { /* ((mqc->c&0x8000000)==0) CHANGE */ + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } else { + (*mqc->bp)++; + if (*mqc->bp == 0xff) { + mqc->c &= 0x7ffffff; + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } + } + } +} + +static void mqc_renorme(opj_mqc_t *mqc) { + do { + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + if (mqc->ct == 0) { + mqc_byteout(mqc); + } + } while ((mqc->a & 0x8000) == 0); +} + +static void mqc_codemps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->a & 0x8000) == 0) { + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + } else { + mqc->c += (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nmps; + mqc_renorme(mqc); + } else { + mqc->c += (*mqc->curctx)->qeval; + } +} + +static void mqc_codelps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->c += (*mqc->curctx)->qeval; + } else { + mqc->a = (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nlps; + mqc_renorme(mqc); +} + +static void mqc_setbits(opj_mqc_t *mqc) { + unsigned int tempc = mqc->c + mqc->a; + mqc->c |= 0xffff; + if (mqc->c >= tempc) { + mqc->c -= 0x8000; + } +} + +static INLINE int mqc_mpsexchange(opj_mqc_t *const mqc) { + int d; + if (mqc->a < (*mqc->curctx)->qeval) { + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } else { + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } + + return d; +} + +static INLINE int mqc_lpsexchange(opj_mqc_t *const mqc) { + int d; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } else { + mqc->a = (*mqc->curctx)->qeval; + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } + + return d; +} + +#ifdef MQC_PERF_OPT +static INLINE void mqc_bytein(opj_mqc_t *const mqc) { + unsigned int i = *((unsigned int *) mqc->bp); + mqc->c += i & 0xffff00; + mqc->ct = i & 0x0f; + mqc->bp += (i >> 2) & 0x04; +} +#else +static void mqc_bytein(opj_mqc_t *const mqc) { + if (mqc->bp != mqc->end) { + unsigned int c; + if (mqc->bp + 1 != mqc->end) { + c = *(mqc->bp + 1); + } else { + c = 0xff; + } + if (*mqc->bp == 0xff) { + if (c > 0x8f) { + mqc->c += 0xff00; + mqc->ct = 8; + } else { + mqc->bp++; + mqc->c += c << 9; + mqc->ct = 7; + } + } else { + mqc->bp++; + mqc->c += c << 8; + mqc->ct = 8; + } + } else { + mqc->c += 0xff00; + mqc->ct = 8; + } +} +#endif + +static INLINE void mqc_renormd(opj_mqc_t *const mqc) { + do { + if (mqc->ct == 0) { + mqc_bytein(mqc); + } + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + } while (mqc->a < 0x8000); +} + +/* +========================================================== + MQ-Coder interface +========================================================== +*/ + +opj_mqc_t* mqc_create(void) { + opj_mqc_t *mqc = (opj_mqc_t*)opj_malloc(sizeof(opj_mqc_t)); +#ifdef MQC_PERF_OPT + mqc->buffer = NULL; +#endif + return mqc; +} + +void mqc_destroy(opj_mqc_t *mqc) { + if(mqc) { +#ifdef MQC_PERF_OPT + if (mqc->buffer) { + opj_free(mqc->buffer); + } +#endif + opj_free(mqc); + } +} + +int mqc_numbytes(opj_mqc_t *mqc) { + return mqc->bp - mqc->start; +} + +void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp) { + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->bp = bp - 1; + mqc->ct = 12; + if (*mqc->bp == 0xff) { + mqc->ct = 13; + } + mqc->start = bp; +} + +void mqc_encode(opj_mqc_t *mqc, int d) { + if ((*mqc->curctx)->mps == d) { + mqc_codemps(mqc); + } else { + mqc_codelps(mqc); + } +} + +void mqc_flush(opj_mqc_t *mqc) { + mqc_setbits(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + + if (*mqc->bp != 0xff) { + mqc->bp++; + } +} + +void mqc_bypass_init_enc(opj_mqc_t *mqc) { + mqc->c = 0; + mqc->ct = 8; + /*if (*mqc->bp == 0xff) { + mqc->ct = 7; + } */ +} + +void mqc_bypass_enc(opj_mqc_t *mqc, int d) { + mqc->ct--; + mqc->c = mqc->c + (d << mqc->ct); + if (mqc->ct == 0) { + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + if (*mqc->bp == 0xff) { + mqc->ct = 7; + } + mqc->c = 0; + } +} + +int mqc_bypass_flush_enc(opj_mqc_t *mqc) { + unsigned char bit_padding; + + bit_padding = 0; + + if (mqc->ct != 0) { + while (mqc->ct > 0) { + mqc->ct--; + mqc->c += bit_padding << mqc->ct; + bit_padding = (bit_padding + 1) & 0x01; + } + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + mqc->c = 0; + } + + return 1; +} + +void mqc_reset_enc(opj_mqc_t *mqc) { + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); +} + +int mqc_restart_enc(opj_mqc_t *mqc) { + int correction = 1; + + /* */ + int n = 27 - 15 - mqc->ct; + mqc->c <<= mqc->ct; + while (n > 0) { + mqc_byteout(mqc); + n -= mqc->ct; + mqc->c <<= mqc->ct; + } + mqc_byteout(mqc); + + return correction; +} + +void mqc_restart_init_enc(opj_mqc_t *mqc) { + /* */ + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->ct = 12; + mqc->bp--; + if (*mqc->bp == 0xff) { + mqc->ct = 13; + } +} + +void mqc_erterm_enc(opj_mqc_t *mqc) { + int k = 11 - mqc->ct + 1; + + while (k > 0) { + mqc->c <<= mqc->ct; + mqc->ct = 0; + mqc_byteout(mqc); + k -= mqc->ct; + } + + if (*mqc->bp != 0xff) { + mqc_byteout(mqc); + } +} + +void mqc_segmark_enc(opj_mqc_t *mqc) { + int i; + mqc_setcurctx(mqc, 18); + + for (i = 1; i < 5; i++) { + mqc_encode(mqc, i % 2); + } +} + +void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len) { + mqc_setcurctx(mqc, 0); + mqc->start = bp; + mqc->end = bp + len; + mqc->bp = bp; + if (len==0) mqc->c = 0xff << 16; + else mqc->c = *mqc->bp << 16; + +#ifdef MQC_PERF_OPT + { + unsigned int c; + unsigned int *ip; + unsigned char *end = mqc->end - 1; + mqc->buffer = opj_realloc(mqc->buffer, (len + 1) * sizeof(unsigned int)); + ip = (unsigned int *) mqc->buffer; + + while (bp < end) { + c = *(bp + 1); + if (*bp == 0xff) { + if (c > 0x8f) { + break; + } else { + *ip = 0x00000017 | (c << 9); + } + } else { + *ip = 0x00000018 | (c << 8); + } + bp++; + ip++; + } + + /* Handle last byte of data */ + c = 0xff; + if (*bp == 0xff) { + *ip = 0x0000ff18; + } else { + bp++; + *ip = 0x00000018 | (c << 8); + } + ip++; + + *ip = 0x0000ff08; + mqc->bp = mqc->buffer; + } +#endif + mqc_bytein(mqc); + mqc->c <<= 7; + mqc->ct -= 7; + mqc->a = 0x8000; +} + +int mqc_decode(opj_mqc_t *const mqc) { + int d; + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->c >> 16) < (*mqc->curctx)->qeval) { + d = mqc_lpsexchange(mqc); + mqc_renormd(mqc); + } else { + mqc->c -= (*mqc->curctx)->qeval << 16; + if ((mqc->a & 0x8000) == 0) { + d = mqc_mpsexchange(mqc); + mqc_renormd(mqc); + } else { + d = (*mqc->curctx)->mps; + } + } + + return d; +} + +void mqc_resetstates(opj_mqc_t *mqc) { + int i; + for (i = 0; i < MQC_NUMCTXS; i++) { + mqc->ctxs[i] = mqc_states; + } +} + +void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob) { + mqc->ctxs[ctxno] = &mqc_states[msb + (prob << 1)]; +} + + diff --git a/openjpeg-dotnet/libopenjpeg/mqc.h b/openjpeg-dotnet/libopenjpeg/mqc.h new file mode 100644 index 0000000..d00cd10 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/mqc.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __MQC_H +#define __MQC_H +/** +@file mqc.h +@brief Implementation of an MQ-Coder (MQC) + +The functions in MQC.C have for goal to realize the MQ-coder operations. The functions +in MQC.C are used by some function in T1.C. +*/ + +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** +This struct defines the state of a context. +*/ +typedef struct opj_mqc_state { + /** the probability of the Least Probable Symbol (0.75->0x8000, 1.5->0xffff) */ + unsigned int qeval; + /** the Most Probable Symbol (0 or 1) */ + int mps; + /** next state if the next encoded symbol is the MPS */ + struct opj_mqc_state *nmps; + /** next state if the next encoded symbol is the LPS */ + struct opj_mqc_state *nlps; +} opj_mqc_state_t; + +#define MQC_NUMCTXS 19 + +/** +MQ coder +*/ +typedef struct opj_mqc { + unsigned int c; + unsigned int a; + unsigned int ct; + unsigned char *bp; + unsigned char *start; + unsigned char *end; + opj_mqc_state_t *ctxs[MQC_NUMCTXS]; + opj_mqc_state_t **curctx; +#ifdef MQC_PERF_OPT + unsigned char *buffer; +#endif +} opj_mqc_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new MQC handle +@return Returns a new MQC handle if successful, returns NULL otherwise +*/ +opj_mqc_t* mqc_create(void); +/** +Destroy a previously created MQC handle +@param mqc MQC handle to destroy +*/ +void mqc_destroy(opj_mqc_t *mqc); +/** +Return the number of bytes written/read since initialisation +@param mqc MQC handle +@return Returns the number of bytes already encoded +*/ +int mqc_numbytes(opj_mqc_t *mqc); +/** +Reset the states of all the context of the coder/decoder +(each context is set to a state where 0 and 1 are more or less equiprobable) +@param mqc MQC handle +*/ +void mqc_resetstates(opj_mqc_t *mqc); +/** +Set the state of a particular context +@param mqc MQC handle +@param ctxno Number that identifies the context +@param msb The MSB of the new state of the context +@param prob Number that identifies the probability of the symbols for the new state of the context +*/ +void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob); +/** +Initialize the encoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer where the bytes will be written +*/ +void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp); +/** +Set the current context used for coding/decoding +@param mqc MQC handle +@param ctxno Number that identifies the context +*/ +#define mqc_setcurctx(mqc, ctxno) (mqc)->curctx = &(mqc)->ctxs[(int)(ctxno)] +/** +Encode a symbol using the MQ-coder +@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_encode(opj_mqc_t *mqc, int d); +/** +Flush the encoder, so that all remaining data is written +@param mqc MQC handle +*/ +void mqc_flush(opj_mqc_t *mqc); +/** +BYPASS mode switch, initialization operation. +JPEG 2000 p 505. +

Not fully implemented and tested !!

+@param mqc MQC handle +*/ +void mqc_bypass_init_enc(opj_mqc_t *mqc); +/** +BYPASS mode switch, coding operation. +JPEG 2000 p 505. +

Not fully implemented and tested !!

+@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_bypass_enc(opj_mqc_t *mqc, int d); +/** +BYPASS mode switch, flush operation +

Not fully implemented and tested !!

+@param mqc MQC handle +@return Returns 1 (always) +*/ +int mqc_bypass_flush_enc(opj_mqc_t *mqc); +/** +RESET mode switch +@param mqc MQC handle +*/ +void mqc_reset_enc(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) +@param mqc MQC handle +@return Returns 1 (always) +*/ +int mqc_restart_enc(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) reinitialisation +@param mqc MQC handle +*/ +void mqc_restart_init_enc(opj_mqc_t *mqc); +/** +ERTERM mode switch (PTERM) +@param mqc MQC handle +*/ +void mqc_erterm_enc(opj_mqc_t *mqc); +/** +SEGMARK mode switch (SEGSYM) +@param mqc MQC handle +*/ +void mqc_segmark_enc(opj_mqc_t *mqc); +/** +Initialize the decoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len); +/** +Decode a symbol +@param mqc MQC handle +@return Returns the decoded symbol (0 or 1) +*/ +int mqc_decode(opj_mqc_t *const mqc); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MQC_H */ diff --git a/openjpeg-dotnet/libopenjpeg/openjpeg.c b/openjpeg-dotnet/libopenjpeg/openjpeg.c new file mode 100644 index 0000000..180cc84 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/openjpeg.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifdef _WIN32 +#include +#endif /* _WIN32 */ + +#include "opj_config.h" +#include "opj_includes.h" + +/* ---------------------------------------------------------------------- */ +#ifdef _WIN32 +#ifndef OPJ_STATIC +BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + + OPJ_ARG_NOT_USED(lpReserved); + OPJ_ARG_NOT_USED(hModule); + + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH : + break; + case DLL_PROCESS_DETACH : + break; + case DLL_THREAD_ATTACH : + case DLL_THREAD_DETACH : + break; + } + + return TRUE; +} +#endif /* OPJ_STATIC */ +#endif /* _WIN32 */ + +/* ---------------------------------------------------------------------- */ + + +const char* OPJ_CALLCONV opj_version(void) { + return PACKAGE_VERSION; +} + +opj_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format) { + opj_dinfo_t *dinfo = (opj_dinfo_t*)opj_calloc(1, sizeof(opj_dinfo_t)); + if(!dinfo) return NULL; + dinfo->is_decompressor = OPJ_TRUE; + switch(format) { + case CODEC_J2K: + case CODEC_JPT: + /* get a J2K decoder handle */ + dinfo->j2k_handle = (void*)j2k_create_decompress((opj_common_ptr)dinfo); + if(!dinfo->j2k_handle) { + opj_free(dinfo); + return NULL; + } + break; + case CODEC_JP2: + /* get a JP2 decoder handle */ + dinfo->jp2_handle = (void*)jp2_create_decompress((opj_common_ptr)dinfo); + if(!dinfo->jp2_handle) { + opj_free(dinfo); + return NULL; + } + break; + case CODEC_UNKNOWN: + default: + opj_free(dinfo); + return NULL; + } + + dinfo->codec_format = format; + + return dinfo; +} + +void OPJ_CALLCONV opj_destroy_decompress(opj_dinfo_t *dinfo) { + if(dinfo) { + /* destroy the codec */ + switch(dinfo->codec_format) { + case CODEC_J2K: + case CODEC_JPT: + j2k_destroy_decompress((opj_j2k_t*)dinfo->j2k_handle); + break; + case CODEC_JP2: + jp2_destroy_decompress((opj_jp2_t*)dinfo->jp2_handle); + break; + case CODEC_UNKNOWN: + default: + break; + } + /* destroy the decompressor */ + opj_free(dinfo); + } +} + +void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_dparameters_t)); + /* default decoding parameters */ + parameters->cp_layer = 0; + parameters->cp_reduce = 0; + parameters->cp_limit_decoding = NO_LIMITATION; + + parameters->decod_format = -1; + parameters->cod_format = -1; + parameters->flags = 0; +/* UniPG>> */ +#ifdef USE_JPWL + parameters->jpwl_correct = OPJ_FALSE; + parameters->jpwl_exp_comps = JPWL_EXPECTED_COMPONENTS; + parameters->jpwl_max_tiles = JPWL_MAXIMUM_TILES; +#endif /* USE_JPWL */ +/* <codec_format) { + case CODEC_J2K: + case CODEC_JPT: + j2k_setup_decoder((opj_j2k_t*)dinfo->j2k_handle, parameters); + break; + case CODEC_JP2: + jp2_setup_decoder((opj_jp2_t*)dinfo->jp2_handle, parameters); + break; + case CODEC_UNKNOWN: + default: + break; + } + } +} + +opj_image_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio) { + return opj_decode_with_info(dinfo, cio, NULL); +} + +opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + if(dinfo && cio) { + switch(dinfo->codec_format) { + case CODEC_J2K: + return j2k_decode((opj_j2k_t*)dinfo->j2k_handle, cio, cstr_info); + case CODEC_JPT: + return j2k_decode_jpt_stream((opj_j2k_t*)dinfo->j2k_handle, cio, cstr_info); + case CODEC_JP2: + return opj_jp2_decode((opj_jp2_t*)dinfo->jp2_handle, cio, cstr_info); + case CODEC_UNKNOWN: + default: + break; + } + } + return NULL; +} + +opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format) { + opj_cinfo_t *cinfo = (opj_cinfo_t*)opj_calloc(1, sizeof(opj_cinfo_t)); + if(!cinfo) return NULL; + cinfo->is_decompressor = OPJ_FALSE; + switch(format) { + case CODEC_J2K: + /* get a J2K coder handle */ + cinfo->j2k_handle = (void*)j2k_create_compress((opj_common_ptr)cinfo); + if(!cinfo->j2k_handle) { + opj_free(cinfo); + return NULL; + } + break; + case CODEC_JP2: + /* get a JP2 coder handle */ + cinfo->jp2_handle = (void*)jp2_create_compress((opj_common_ptr)cinfo); + if(!cinfo->jp2_handle) { + opj_free(cinfo); + return NULL; + } + break; + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + opj_free(cinfo); + return NULL; + } + + cinfo->codec_format = format; + + return cinfo; +} + +void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo) { + if(cinfo) { + /* destroy the codec */ + switch(cinfo->codec_format) { + case CODEC_J2K: + j2k_destroy_compress((opj_j2k_t*)cinfo->j2k_handle); + break; + case CODEC_JP2: + jp2_destroy_compress((opj_jp2_t*)cinfo->jp2_handle); + break; + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + break; + } + /* destroy the decompressor */ + opj_free(cinfo); + } +} + +void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_cparameters_t)); + /* default coding parameters */ + parameters->cp_cinema = OFF; + parameters->max_comp_size = 0; + parameters->numresolution = 6; + parameters->cp_rsiz = STD_RSIZ; + parameters->cblockw_init = 64; + parameters->cblockh_init = 64; + parameters->prog_order = LRCP; + parameters->roi_compno = -1; /* no ROI */ + parameters->subsampling_dx = 1; + parameters->subsampling_dy = 1; + parameters->tp_on = 0; + parameters->decod_format = -1; + parameters->cod_format = -1; + parameters->tcp_rates[0] = 0; + parameters->tcp_numlayers = 0; + parameters->cp_disto_alloc = 0; + parameters->cp_fixed_alloc = 0; + parameters->cp_fixed_quality = 0; + parameters->jpip_on = OPJ_FALSE; +/* UniPG>> */ +#ifdef USE_JPWL + parameters->jpwl_epc_on = OPJ_FALSE; + parameters->jpwl_hprot_MH = -1; /* -1 means unassigned */ + { + int i; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + parameters->jpwl_hprot_TPH_tileno[i] = -1; /* unassigned */ + parameters->jpwl_hprot_TPH[i] = 0; /* absent */ + } + }; + { + int i; + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + parameters->jpwl_pprot_tileno[i] = -1; /* unassigned */ + parameters->jpwl_pprot_packno[i] = -1; /* unassigned */ + parameters->jpwl_pprot[i] = 0; /* absent */ + } + }; + parameters->jpwl_sens_size = 0; /* 0 means no ESD */ + parameters->jpwl_sens_addr = 0; /* 0 means auto */ + parameters->jpwl_sens_range = 0; /* 0 means packet */ + parameters->jpwl_sens_MH = -1; /* -1 means unassigned */ + { + int i; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + parameters->jpwl_sens_TPH_tileno[i] = -1; /* unassigned */ + parameters->jpwl_sens_TPH[i] = -1; /* absent */ + } + }; +#endif /* USE_JPWL */ +/* <codec_format) { + case CODEC_J2K: + j2k_setup_encoder((opj_j2k_t*)cinfo->j2k_handle, parameters, image); + break; + case CODEC_JP2: + jp2_setup_encoder((opj_jp2_t*)cinfo->jp2_handle, parameters, image); + break; + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + break; + } + } +} + +opj_bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index) { + if (index != NULL) + opj_event_msg((opj_common_ptr)cinfo, EVT_WARNING, "Set index to NULL when calling the opj_encode function.\n" + "To extract the index, use the opj_encode_with_info() function.\n" + "No index will be generated during this encoding\n"); + return opj_encode_with_info(cinfo, cio, image, NULL); +} + +opj_bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + if(cinfo && cio && image) { + switch(cinfo->codec_format) { + case CODEC_J2K: + return j2k_encode((opj_j2k_t*)cinfo->j2k_handle, cio, image, cstr_info); + case CODEC_JP2: + return opj_jp2_encode((opj_jp2_t*)cinfo->jp2_handle, cio, image, cstr_info); + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + break; + } + } + return OPJ_FALSE; +} + +void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) { + if (cstr_info) { + int tileno; + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + opj_tile_info_t *tile_info = &cstr_info->tile[tileno]; + opj_free(tile_info->thresh); + opj_free(tile_info->packet); + opj_free(tile_info->tp); + opj_free(tile_info->marker); + } + opj_free(cstr_info->tile); + opj_free(cstr_info->marker); + opj_free(cstr_info->numdecompos); + } +} diff --git a/openjpeg-dotnet/libopenjpeg/openjpeg.h b/openjpeg-dotnet/libopenjpeg/openjpeg.h new file mode 100644 index 0000000..53e9fac --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/openjpeg.h @@ -0,0 +1,910 @@ + /* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef OPENJPEG_H +#define OPENJPEG_H + + +/* +========================================================== + Compiler directives +========================================================== +*/ + +#if defined(OPJ_STATIC) || !defined(_WIN32) +#define OPJ_API +#define OPJ_CALLCONV +#else +#define OPJ_CALLCONV __stdcall +/* +The following ifdef block is the standard way of creating macros which make exporting +from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS +symbol defined on the command line. this symbol should not be defined on any project +that uses this DLL. This way any other project whose source files include this file see +OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols +defined with this macro as being exported. +*/ +#if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) +#define OPJ_API __declspec(dllexport) +#else +#define OPJ_API __declspec(dllimport) +#endif /* OPJ_EXPORTS */ +#endif /* !OPJ_STATIC || !_WIN32 */ + +typedef int opj_bool; +#define OPJ_TRUE 1 +#define OPJ_FALSE 0 + +/* Avoid compile-time warning because parameter is not used */ +#define OPJ_ARG_NOT_USED(x) (void)(x) +/* +========================================================== + Useful constant definitions +========================================================== +*/ + +#define OPJ_PATH_LEN 4096 /**< Maximum allowed size for filenames */ + +#define J2K_MAXRLVLS 33 /**< Number of maximum resolution level authorized */ +#define J2K_MAXBANDS (3*J2K_MAXRLVLS-2) /**< Number of maximum sub-band linked to number of resolution level */ + +/* UniPG>> */ +#define JPWL_MAX_NO_TILESPECS 16 /**< Maximum number of tile parts expected by JPWL: increase at your will */ +#define JPWL_MAX_NO_PACKSPECS 16 /**< Maximum number of packet parts expected by JPWL: increase at your will */ +#define JPWL_MAX_NO_MARKERS 512 /**< Maximum number of JPWL markers: increase at your will */ +#define JPWL_PRIVATEINDEX_NAME "jpwl_index_privatefilename" /**< index file name used when JPWL is on */ +#define JPWL_EXPECTED_COMPONENTS 3 /**< Expect this number of components, so you'll find better the first EPB */ +#define JPWL_MAXIMUM_TILES 8192 /**< Expect this maximum number of tiles, to avoid some crashes */ +#define JPWL_MAXIMUM_HAMMING 2 /**< Expect this maximum number of bit errors in marker id's */ +#define JPWL_MAXIMUM_EPB_ROOM 65450 /**< Expect this maximum number of bytes for composition of EPBs */ +/* < +
  • Error messages +
  • Warning messages +
  • Debugging messages + +*/ +typedef struct opj_event_mgr { + /** Error message callback if available, NULL otherwise */ + opj_msg_callback error_handler; + /** Warning message callback if available, NULL otherwise */ + opj_msg_callback warning_handler; + /** Debug message callback if available, NULL otherwise */ + opj_msg_callback info_handler; +} opj_event_mgr_t; + + +/* +========================================================== + codec typedef definitions +========================================================== +*/ + +/** +Progression order changes +*/ +typedef struct opj_poc { + /** Resolution num start, Component num start, given by POC */ + int resno0, compno0; + /** Layer num end,Resolution num end, Component num end, given by POC */ + int layno1, resno1, compno1; + /** Layer num start,Precinct num start, Precinct num end */ + int layno0, precno0, precno1; + /** Progression order enum*/ + OPJ_PROG_ORDER prg1,prg; + /** Progression order string*/ + char progorder[5]; + /** Tile number */ + int tile; + /** Start and end values for Tile width and height*/ + int tx0,tx1,ty0,ty1; + /** Start value, initialised in pi_initialise_encode*/ + int layS, resS, compS, prcS; + /** End value, initialised in pi_initialise_encode */ + int layE, resE, compE, prcE; + /** Start and end values of Tile width and height, initialised in pi_initialise_encode*/ + int txS,txE,tyS,tyE,dx,dy; + /** Temporary values for Tile parts, initialised in pi_create_encode */ + int lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t; +} opj_poc_t; + +/** +Compression parameters +*/ +typedef struct opj_cparameters { + /** size of tile: tile_size_on = false (not in argument) or = true (in argument) */ + opj_bool tile_size_on; + /** XTOsiz */ + int cp_tx0; + /** YTOsiz */ + int cp_ty0; + /** XTsiz */ + int cp_tdx; + /** YTsiz */ + int cp_tdy; + /** allocation by rate/distortion */ + int cp_disto_alloc; + /** allocation by fixed layer */ + int cp_fixed_alloc; + /** add fixed_quality */ + int cp_fixed_quality; + /** fixed layer */ + int *cp_matrice; + /** comment for coding */ + char *cp_comment; + /** csty : coding style */ + int csty; + /** progression order (default LRCP) */ + OPJ_PROG_ORDER prog_order; + /** progression order changes */ + opj_poc_t POC[32]; + /** number of progression order changes (POC), default to 0 */ + int numpocs; + /** number of layers */ + int tcp_numlayers; + /** rates of layers */ + float tcp_rates[100]; + /** different psnr for successive layers */ + float tcp_distoratio[100]; + /** number of resolutions */ + int numresolution; + /** initial code block width, default to 64 */ + int cblockw_init; + /** initial code block height, default to 64 */ + int cblockh_init; + /** mode switch (cblk_style) */ + int mode; + /** 1 : use the irreversible DWT 9-7, 0 : use lossless compression (default) */ + int irreversible; + /** region of interest: affected component in [0..3], -1 means no ROI */ + int roi_compno; + /** region of interest: upshift value */ + int roi_shift; + /* number of precinct size specifications */ + int res_spec; + /** initial precinct width */ + int prcw_init[J2K_MAXRLVLS]; + /** initial precinct height */ + int prch_init[J2K_MAXRLVLS]; + + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** DEPRECATED. Index generation is now handeld with the opj_encode_with_info() function. Set to NULL */ + int index_on; + /** DEPRECATED. Index generation is now handeld with the opj_encode_with_info() function. Set to NULL */ + char index[OPJ_PATH_LEN]; + /** subimage encoding: origin image offset in x direction */ + int image_offset_x0; + /** subimage encoding: origin image offset in y direction */ + int image_offset_y0; + /** subsampling value for dx */ + int subsampling_dx; + /** subsampling value for dy */ + int subsampling_dy; + /** input file format 0: PGX, 1: PxM, 2: BMP 3:TIF*/ + int decod_format; + /** output file format 0: J2K, 1: JP2, 2: JPT */ + int cod_format; + /*@}*/ + +/* UniPG>> */ + /**@name JPWL encoding parameters */ + /*@{*/ + /** enables writing of EPC in MH, thus activating JPWL */ + opj_bool jpwl_epc_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int jpwl_hprot_MH; + /** tile number of header protection specification (>=0) */ + int jpwl_hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int jpwl_hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int jpwl_pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int jpwl_pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int jpwl_pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0=no/1/2 bytes) */ + int jpwl_sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int jpwl_sens_addr; + /** sensitivity range (0-3) */ + int jpwl_sens_range; + /** sensitivity method for MH (-1=no,0-7) */ + int jpwl_sens_MH; + /** tile number of sensitivity specification (>=0) */ + int jpwl_sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1=no,0-7) */ + int jpwl_sens_TPH[JPWL_MAX_NO_TILESPECS]; + /*@}*/ +/* <> */ + /**@name JPWL decoding parameters */ + /*@{*/ + /** activates the JPWL correction capabilities */ + opj_bool jpwl_correct; + /** expected number of components */ + int jpwl_exp_comps; + /** maximum number of tiles */ + int jpwl_max_tiles; + /*@}*/ +/* <> */ +/** +Marker structure +*/ +typedef struct opj_marker_info_t { + /** marker type */ + unsigned short int type; + /** position in codestream */ + int pos; + /** length, marker val included */ + int len; +} opj_marker_info_t; +/* <> */ + /** number of markers */ + int marknum; + /** list of markers */ + opj_marker_info_t *marker; + /** actual size of markers array */ + int maxmarknum; +/* <cp. +@param dinfo decompressor handle +@param parameters decompression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 codestream +@param dinfo decompressor handle +@param cio Input buffer stream +@return Returns a decoded image if successful, returns NULL otherwise +*/ +OPJ_API opj_image_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio); + +/** +Decode an image from a JPEG-2000 codestream and extract the codestream information +@param dinfo decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if needed afterwards, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +OPJ_API opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a J2K/JP2 compression structure +@param format Coder to select +@return Returns a handle to a compressor if successful, returns NULL otherwise +*/ +OPJ_API opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format); +/** +Destroy a compressor handle +@param cinfo compressor handle to destroy +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo); +/** +Set encoding parameters to default values, that means : +
      +
    • Lossless +
    • 1 tile +
    • Size of precinct : 2^15 x 2^15 (means 1 precinct) +
    • Size of code-block : 64 x 64 +
    • Number of resolutions: 6 +
    • No SOP marker in the codestream +
    • No EPH marker in the codestream +
    • No sub-sampling in x or y direction +
    • No mode switch activated +
    • Progression order: LRCP +
    • No index file +
    • No ROI upshifted +
    • No offset of the origin of the image +
    • No offset of the origin of the tiles +
    • Reversible DWT 5-3 +
    +@param parameters Compression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters); +/** +Setup the encoder parameters using the current image and using user parameters. +@param cinfo Compressor handle +@param parameters Compression parameters +@param image Input filled image +*/ +OPJ_API void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image); +/** +Encode an image into a JPEG-2000 codestream +3@param cinfo compressor handle +@param cio Output buffer stream +@param image Image to encode +@param index Depreacted -> Set to NULL. To extract index, used opj_encode_wci() +@return Returns true if successful, returns false otherwise +*/ +OPJ_API opj_bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index); +/** +Encode an image into a JPEG-2000 codestream and extract the codestream information +@param cinfo compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if needed afterwards, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +OPJ_API opj_bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +/** +Destroy Codestream information after compression or decompression +@param cstr_info Codestream information structure +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info); + + +#ifdef __cplusplus +} +#endif + +#endif /* OPENJPEG_H */ diff --git a/openjpeg-dotnet/libopenjpeg/opj_config.h b/openjpeg-dotnet/libopenjpeg/opj_config.h new file mode 100644 index 0000000..53e1c0b --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/opj_config.h @@ -0,0 +1,117 @@ +/* opj_config.h. Generated from opj_config.h.in by configure. */ +/* opj_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* define to 1 if you have lcms version 1.x */ +/* #undef HAVE_LIBLCMS1 */ + +/* define to 1 if you have lcms version 2.x */ +/* #undef HAVE_LIBLCMS2 */ + +/* define to 1 if you have libpng */ +#define HAVE_LIBPNG 1 + +/* define to 1 if you have libtiff */ +#define HAVE_LIBTIFF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "openjpeg" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "openjpeg@googlegroups.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "OpenJPEG" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "OpenJPEG 1.5.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "openjpeg" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.openjpeg.org" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.5.0" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* define to 1 if you use jpip */ +/* #undef USE_JPIP */ + +/* define to 1 if you use jpip server */ +/* #undef USE_JPIP_SERVER */ + +/* define to 1 if you use mj2 */ +/* #undef USE_MJ2 */ + +/* Version number of package */ +#define VERSION "1.5.0" + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif diff --git a/openjpeg-dotnet/libopenjpeg/opj_includes.h b/openjpeg-dotnet/libopenjpeg/opj_includes.h new file mode 100644 index 0000000..2b5866a --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/opj_includes.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef OPJ_INCLUDES_H +#define OPJ_INCLUDES_H + +/* + ========================================================== + Standard includes used by the library + ========================================================== +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + ========================================================== + OpenJPEG interface + ========================================================== + */ +#include "openjpeg.h" + +/* + ========================================================== + OpenJPEG modules + ========================================================== +*/ + +/* Ignore GCC attributes if this is not GCC */ +#ifndef __GNUC__ + #define __attribute__(x) /* __attribute__(x) */ +#endif + +/* +The inline keyword is supported by C99 but not by C90. +Most compilers implement their own version of this keyword ... +*/ +#ifndef INLINE + #if defined(_MSC_VER) + #define INLINE __forceinline + #elif defined(__GNUC__) + #define INLINE __inline__ + #elif defined(__MWERKS__) + #define INLINE inline + #else + /* add other compilers here ... */ + #define INLINE + #endif /* defined() */ +#endif /* INLINE */ + +/* Are restricted pointers available? (C99) */ +#if (__STDC_VERSION__ != 199901L) + /* Not a C99 compiler */ + #ifdef __GNUC__ + #define restrict __restrict__ + #else + #define restrict /* restrict */ + #endif +#endif + +/* MSVC and Borland C do not have lrintf */ +#if defined(_MSC_VER) || defined(__BORLANDC__) +static INLINE long lrintf(float f){ +#ifdef _M_X64 + return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); +#else + int i; + + _asm{ + fld f + fistp i + }; + + return i; +#endif +} +#endif + +#include "j2k_lib.h" +#include "opj_malloc.h" +#include "event.h" +#include "bio.h" +#include "cio.h" + +#include "image.h" +#include "j2k.h" +#include "jp2.h" +#include "jpt.h" + +#include "mqc.h" +#include "raw.h" +#include "bio.h" +#include "tgt.h" +#include "pi.h" +#include "tcd.h" +#include "t1.h" +#include "dwt.h" +#include "t2.h" +#include "mct.h" +#include "int.h" +#include "fix.h" + +#include "cidx_manager.h" +#include "indexbox_manager.h" + +/* JPWL>> */ +#ifdef USE_JPWL +#include "./jpwl/jpwl.h" +#endif /* USE_JPWL */ +/* < + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __OPJ_MALLOC_H +#define __OPJ_MALLOC_H +/** +@file opj_malloc.h +@brief Internal functions + +The functions in opj_malloc.h are internal utilities used for memory management. +*/ + +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Allocate an uninitialized memory block +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#ifdef ALLOC_PERF_OPT +void * OPJ_CALLCONV opj_malloc(size_t size); +#else +#define opj_malloc(size) malloc(size) +#endif + +/** +Allocate a memory block with elements initialized to 0 +@param num Blocks to allocate +@param size Bytes per block to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#ifdef ALLOC_PERF_OPT +void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements); +#else +#define opj_calloc(num, size) calloc(num, size) +#endif + +/** +Allocate memory aligned to a 16 byte boundry +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */ +#ifdef _WIN32 + /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */ + #ifdef __GNUC__ + #include + #define HAVE_MM_MALLOC + #else /* MSVC, Intel C++ */ + #include + #ifdef _mm_malloc + #define HAVE_MM_MALLOC + #endif + #endif +#else /* Not _WIN32 */ + #if defined(__sun) + #define HAVE_MEMALIGN + /* Linux x86_64 and OSX always align allocations to 16 bytes */ + #elif !defined(__amd64__) && !defined(__APPLE__) + #define HAVE_MEMALIGN + #include + #endif +#endif + +#define opj_aligned_malloc(size) malloc(size) +#define opj_aligned_free(m) free(m) + +#ifdef HAVE_MM_MALLOC + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) _mm_malloc(size, 16) + #undef opj_aligned_free + #define opj_aligned_free(m) _mm_free(m) +#endif + +#ifdef HAVE_MEMALIGN + extern void* memalign(size_t, size_t); + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) memalign(16, (size)) + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +#ifdef HAVE_POSIX_MEMALIGN + #undef opj_aligned_malloc + extern int posix_memalign(void**, size_t, size_t); + + static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){ + void* mem = NULL; + posix_memalign(&mem, 16, size); + return mem; + } + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +#ifdef ALLOC_PERF_OPT + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) opj_malloc(size) + #undef opj_aligned_free + #define opj_aligned_free(m) opj_free(m) +#endif + +/** +Reallocate memory blocks. +@param m Pointer to previously allocated memory block +@param s New size in bytes +@return Returns a void pointer to the reallocated (and possibly moved) memory block +*/ +#ifdef ALLOC_PERF_OPT +void * OPJ_CALLCONV opj_realloc(void * m, size_t s); +#else +#define opj_realloc(m, s) realloc(m, s) +#endif + +/** +Deallocates or frees a memory block. +@param m Previously allocated memory block to be freed +*/ +#ifdef ALLOC_PERF_OPT +void OPJ_CALLCONV opj_free(void * m); +#else +#define opj_free(m) free(m) +#endif + +#ifdef __GNUC__ +#pragma GCC poison malloc calloc realloc free +#endif + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __OPJ_MALLOC_H */ + diff --git a/openjpeg-dotnet/libopenjpeg/phix_manager.c b/openjpeg-dotnet/libopenjpeg/phix_manager.c new file mode 100644 index 0000000..60a0281 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/phix_manager.c @@ -0,0 +1,170 @@ +/* + * $Id: phix_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $ + * + * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2011, Professor Benoit Macq + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +/*! \file + * \brief Modification of jpip.c from 2KAN indexer + */ + +#include +#include +#include "opj_includes.h" + +/* + * Write faix box of phix + * + * @param[in] coff offset of j2k codestream + * @param[in] compno component number + * @param[in] cstr_info codestream information + * @param[in] EPHused true if if EPH option used + * @param[in] j2klen length of j2k codestream + * @param[in] cio file output handle + * @return length of faix box + */ +int write_phixfaix( int coff, int compno, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio); + +int write_phix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio) +{ + int len, lenp=0, compno, i; + opj_jp2_box_t *box; + + box = (opj_jp2_box_t *)opj_calloc( cstr_info.numcomps, sizeof(opj_jp2_box_t)); + + for( i=0;i<2;i++){ + if (i) cio_seek( cio, lenp); + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_PHIX, 4); /* PHIX */ + + write_manf( i, cstr_info.numcomps, box, cio); + + for( compno=0; compno pow( 2, 32)){ + size_of_coding = 8; + version = 1; + } + else{ + size_of_coding = 4; + version = 0; + } + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_FAIX, 4); /* FAIX */ + cio_write( cio, version,1); /* Version 0 = 4 bytes */ + + nmax = 0; + for( i=0; i<=cstr_info.numdecompos[compno]; i++) + nmax += cstr_info.tile[0].ph[i] * cstr_info.tile[0].pw[i] * cstr_info.numlayers; + + cio_write( cio, nmax, size_of_coding); /* NMAX */ + cio_write( cio, cstr_info.tw*cstr_info.th, size_of_coding); /* M */ + + for( tileno=0; tilenopw[resno]*tile_Idx->ph[resno]; + for( precno=0; precnopacket[ ((layno*numOfres+resno)*cstr_info.numcomps+compno)*numOfprec+precno]; + break; + case RLCP: + packet = tile_Idx->packet[ ((resno*numOflayers+layno)*cstr_info.numcomps+compno)*numOfprec+precno]; + break; + case RPCL: + packet = tile_Idx->packet[ ((resno*numOfprec+precno)*cstr_info.numcomps+compno)*numOflayers+layno]; + break; + case PCRL: + packet = tile_Idx->packet[ ((precno*cstr_info.numcomps+compno)*numOfres+resno)*numOflayers + layno]; + break; + case CPRL: + packet = tile_Idx->packet[ ((compno*numOfprec+precno)*numOfres+resno)*numOflayers + layno]; + break; + default: + fprintf( stderr, "failed to ppix indexing\n"); + } + + cio_write( cio, packet.start_pos-coff, size_of_coding); /* start position */ + cio_write( cio, packet.end_ph_pos-packet.start_pos+1, size_of_coding); /* length */ + + num_packet++; + } + } + } + + /* PADDING */ + while( num_packet < nmax){ + cio_write( cio, 0, size_of_coding); /* start position */ + cio_write( cio, 0, size_of_coding); /* length */ + num_packet++; + } + } + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); + + return len; +} diff --git a/openjpeg-dotnet/libopenjpeg/pi.c b/openjpeg-dotnet/libopenjpeg/pi.c new file mode 100644 index 0000000..e8e33bf --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/pi.c @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Get next packet in layer-resolution-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static opj_bool pi_next_lrcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-layer-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static opj_bool pi_next_rlcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-precinct-component-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static opj_bool pi_next_rpcl(opj_pi_iterator_t * pi); +/** +Get next packet in precinct-component-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static opj_bool pi_next_pcrl(opj_pi_iterator_t * pi); +/** +Get next packet in component-precinct-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static opj_bool pi_next_cprl(opj_pi_iterator_t * pi); + +/*@}*/ + +/*@}*/ + +/* +========================================================== + local functions +========================================================== +*/ + +static opj_bool pi_next_lrcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; + pi->resno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + if (!pi->tp_on){ + pi->poc.precno1 = res->pw * res->ph; + } + for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return OPJ_TRUE; + } +LABEL_SKIP:; + } + } + } + } + + return OPJ_FALSE; +} + +static opj_bool pi_next_rlcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + if(!pi->tp_on){ + pi->poc.precno1 = res->pw * res->ph; + } + for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return OPJ_TRUE; + } +LABEL_SKIP:; + } + } + } + } + + return OPJ_FALSE; +} + +static opj_bool pi_next_rpcl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + goto LABEL_SKIP; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } +if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + int levelno; + int trx0, try0; + int trx1, try1; + int rpx, rpy; + int prci, prcj; + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return OPJ_TRUE; + } +LABEL_SKIP:; + } + } + } + } + } + + return OPJ_FALSE; +} + +static opj_bool pi_next_pcrl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } + if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + int levelno; + int trx0, try0; + int trx1, try1; + int rpx, rpy; + int prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return OPJ_TRUE; + } +LABEL_SKIP:; + } + } + } + } + } + + return OPJ_FALSE; +} + +static opj_bool pi_next_cprl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + int resno; + comp = &pi->comps[pi->compno]; + pi->dx = 0; + pi->dy = 0; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + int levelno; + int trx0, try0; + int trx1, try1; + int rpx, rpy; + int prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return OPJ_TRUE; + } +LABEL_SKIP:; + } + } + } + } + } + + return OPJ_FALSE; +} + +/* +========================================================== + Packet iterator interface +========================================================== +*/ + +opj_pi_iterator_t *pi_create_decode(opj_image_t *image, opj_cp_t *cp, int tileno) { + int p, q; + int compno, resno, pino; + opj_pi_iterator_t *pi = NULL; + opj_tcp_t *tcp = NULL; + opj_tccp_t *tccp = NULL; + + tcp = &cp->tcps[tileno]; + + pi = (opj_pi_iterator_t*) opj_calloc((tcp->numpocs + 1), sizeof(opj_pi_iterator_t)); + if(!pi) { + /* TODO: throw an error */ + return NULL; + } + + for (pino = 0; pino < tcp->numpocs + 1; pino++) { /* change */ + int maxres = 0; + int maxprec = 0; + p = tileno % cp->tw; + q = tileno / cp->tw; + + pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + pi[pino].numcomps = image->numcomps; + + pi[pino].comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); + if(!pi[pino].comps) { + /* TODO: throw an error */ + pi_destroy(pi, cp, tileno); + return NULL; + } + + for (compno = 0; compno < pi->numcomps; compno++) { + int tcx0, tcy0, tcx1, tcy1; + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + tccp = &tcp->tccps[compno]; + comp->dx = image->comps[compno].dx; + comp->dy = image->comps[compno].dy; + comp->numresolutions = tccp->numresolutions; + + comp->resolutions = (opj_pi_resolution_t*) opj_calloc(comp->numresolutions, sizeof(opj_pi_resolution_t)); + if(!comp->resolutions) { + /* TODO: throw an error */ + pi_destroy(pi, cp, tileno); + return NULL; + } + + tcx0 = int_ceildiv(pi->tx0, comp->dx); + tcy0 = int_ceildiv(pi->ty0, comp->dy); + tcx1 = int_ceildiv(pi->tx1, comp->dx); + tcy1 = int_ceildiv(pi->ty1, comp->dy); + if (comp->numresolutions > maxres) { + maxres = comp->numresolutions; + } + + for (resno = 0; resno < comp->numresolutions; resno++) { + int levelno; + int rx0, ry0, rx1, ry1; + int px0, py0, px1, py1; + opj_pi_resolution_t *res = &comp->resolutions[resno]; + if (tccp->csty & J2K_CCP_CSTY_PRT) { + res->pdx = tccp->prcw[resno]; + res->pdy = tccp->prch[resno]; + } else { + res->pdx = 15; + res->pdy = 15; + } + levelno = comp->numresolutions - 1 - resno; + rx0 = int_ceildivpow2(tcx0, levelno); + ry0 = int_ceildivpow2(tcy0, levelno); + rx1 = int_ceildivpow2(tcx1, levelno); + ry1 = int_ceildivpow2(tcy1, levelno); + px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; + py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; + px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; + py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; + res->pw = (rx0==rx1)?0:((px1 - px0) >> res->pdx); + res->ph = (ry0==ry1)?0:((py1 - py0) >> res->pdy); + + if (res->pw*res->ph > maxprec) { + maxprec = res->pw*res->ph; + } + + } + } + + tccp = &tcp->tccps[0]; + pi[pino].step_p = 1; + pi[pino].step_c = maxprec * pi[pino].step_p; + pi[pino].step_r = image->numcomps * pi[pino].step_c; + pi[pino].step_l = maxres * pi[pino].step_r; + + if (pino == 0) { + pi[pino].include = (short int*) opj_calloc(image->numcomps * maxres * tcp->numlayers * maxprec, sizeof(short int)); + if(!pi[pino].include) { + /* TODO: throw an error */ + pi_destroy(pi, cp, tileno); + return NULL; + } + } + else { + pi[pino].include = pi[pino - 1].include; + } + + if (tcp->POC == 0) { + pi[pino].first = 1; + pi[pino].poc.resno0 = 0; + pi[pino].poc.compno0 = 0; + pi[pino].poc.layno1 = tcp->numlayers; + pi[pino].poc.resno1 = maxres; + pi[pino].poc.compno1 = image->numcomps; + pi[pino].poc.prg = tcp->prg; + } else { + pi[pino].first = 1; + pi[pino].poc.resno0 = tcp->pocs[pino].resno0; + pi[pino].poc.compno0 = tcp->pocs[pino].compno0; + pi[pino].poc.layno1 = tcp->pocs[pino].layno1; + pi[pino].poc.resno1 = tcp->pocs[pino].resno1; + pi[pino].poc.compno1 = tcp->pocs[pino].compno1; + pi[pino].poc.prg = tcp->pocs[pino].prg; + } + pi[pino].poc.layno0 = 0; + pi[pino].poc.precno0 = 0; + pi[pino].poc.precno1 = maxprec; + + } + + return pi; +} + + +opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int tileno, J2K_T2_MODE t2_mode){ + int p, q, pino; + int compno, resno; + int maxres = 0; + int maxprec = 0; + opj_pi_iterator_t *pi = NULL; + opj_tcp_t *tcp = NULL; + opj_tccp_t *tccp = NULL; + + tcp = &cp->tcps[tileno]; + + pi = (opj_pi_iterator_t*) opj_calloc((tcp->numpocs + 1), sizeof(opj_pi_iterator_t)); + if(!pi) { return NULL;} + pi->tp_on = cp->tp_on; + + for(pino = 0;pino < tcp->numpocs+1 ; pino ++){ + p = tileno % cp->tw; + q = tileno / cp->tw; + + pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + pi[pino].numcomps = image->numcomps; + + pi[pino].comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); + if(!pi[pino].comps) { + pi_destroy(pi, cp, tileno); + return NULL; + } + + for (compno = 0; compno < pi[pino].numcomps; compno++) { + int tcx0, tcy0, tcx1, tcy1; + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + tccp = &tcp->tccps[compno]; + comp->dx = image->comps[compno].dx; + comp->dy = image->comps[compno].dy; + comp->numresolutions = tccp->numresolutions; + + comp->resolutions = (opj_pi_resolution_t*) opj_malloc(comp->numresolutions * sizeof(opj_pi_resolution_t)); + if(!comp->resolutions) { + pi_destroy(pi, cp, tileno); + return NULL; + } + + tcx0 = int_ceildiv(pi[pino].tx0, comp->dx); + tcy0 = int_ceildiv(pi[pino].ty0, comp->dy); + tcx1 = int_ceildiv(pi[pino].tx1, comp->dx); + tcy1 = int_ceildiv(pi[pino].ty1, comp->dy); + if (comp->numresolutions > maxres) { + maxres = comp->numresolutions; + } + + for (resno = 0; resno < comp->numresolutions; resno++) { + int levelno; + int rx0, ry0, rx1, ry1; + int px0, py0, px1, py1; + opj_pi_resolution_t *res = &comp->resolutions[resno]; + if (tccp->csty & J2K_CCP_CSTY_PRT) { + res->pdx = tccp->prcw[resno]; + res->pdy = tccp->prch[resno]; + } else { + res->pdx = 15; + res->pdy = 15; + } + levelno = comp->numresolutions - 1 - resno; + rx0 = int_ceildivpow2(tcx0, levelno); + ry0 = int_ceildivpow2(tcy0, levelno); + rx1 = int_ceildivpow2(tcx1, levelno); + ry1 = int_ceildivpow2(tcy1, levelno); + px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; + py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; + px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; + py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; + res->pw = (rx0==rx1)?0:((px1 - px0) >> res->pdx); + res->ph = (ry0==ry1)?0:((py1 - py0) >> res->pdy); + + if (res->pw*res->ph > maxprec) { + maxprec = res->pw * res->ph; + } + } + } + + tccp = &tcp->tccps[0]; + pi[pino].step_p = 1; + pi[pino].step_c = maxprec * pi[pino].step_p; + pi[pino].step_r = image->numcomps * pi[pino].step_c; + pi[pino].step_l = maxres * pi[pino].step_r; + + for (compno = 0; compno < pi->numcomps; compno++) { + opj_pi_comp_t *comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + opj_pi_resolution_t *res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi[pino].dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi[pino].dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + + if (pino == 0) { + pi[pino].include = (short int*) opj_calloc(tcp->numlayers * pi[pino].step_l, sizeof(short int)); + if(!pi[pino].include) { + pi_destroy(pi, cp, tileno); + return NULL; + } + } + else { + pi[pino].include = pi[pino - 1].include; + } + + /* Generation of boundaries for each prog flag*/ + if(tcp->POC && ( cp->cinema || ((!cp->cinema) && (t2_mode == FINAL_PASS)))){ + tcp->pocs[pino].compS= tcp->pocs[pino].compno0; + tcp->pocs[pino].compE= tcp->pocs[pino].compno1; + tcp->pocs[pino].resS = tcp->pocs[pino].resno0; + tcp->pocs[pino].resE = tcp->pocs[pino].resno1; + tcp->pocs[pino].layE = tcp->pocs[pino].layno1; + tcp->pocs[pino].prg = tcp->pocs[pino].prg1; + if (pino > 0) + tcp->pocs[pino].layS = (tcp->pocs[pino].layE > tcp->pocs[pino - 1].layE) ? tcp->pocs[pino - 1].layE : 0; + }else { + tcp->pocs[pino].compS= 0; + tcp->pocs[pino].compE= image->numcomps; + tcp->pocs[pino].resS = 0; + tcp->pocs[pino].resE = maxres; + tcp->pocs[pino].layS = 0; + tcp->pocs[pino].layE = tcp->numlayers; + tcp->pocs[pino].prg = tcp->prg; + } + tcp->pocs[pino].prcS = 0; + tcp->pocs[pino].prcE = maxprec;; + tcp->pocs[pino].txS = pi[pino].tx0; + tcp->pocs[pino].txE = pi[pino].tx1; + tcp->pocs[pino].tyS = pi[pino].ty0; + tcp->pocs[pino].tyE = pi[pino].ty1; + tcp->pocs[pino].dx = pi[pino].dx; + tcp->pocs[pino].dy = pi[pino].dy; + } + return pi; + } + + + +void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno) { + int compno, pino; + opj_tcp_t *tcp = &cp->tcps[tileno]; + if(pi) { + for (pino = 0; pino < tcp->numpocs + 1; pino++) { + if(pi[pino].comps) { + for (compno = 0; compno < pi->numcomps; compno++) { + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + if(comp->resolutions) { + opj_free(comp->resolutions); + } + } + opj_free(pi[pino].comps); + } + } + if(pi->include) { + opj_free(pi->include); + } + opj_free(pi); + } +} + +opj_bool pi_next(opj_pi_iterator_t * pi) { + switch (pi->poc.prg) { + case LRCP: + return pi_next_lrcp(pi); + case RLCP: + return pi_next_rlcp(pi); + case RPCL: + return pi_next_rpcl(pi); + case PCRL: + return pi_next_pcrl(pi); + case CPRL: + return pi_next_cprl(pi); + case PROG_UNKNOWN: + return OPJ_FALSE; + } + + return OPJ_FALSE; +} + +opj_bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp){ + char prog[4]; + int i; + int incr_top=1,resetX=0; + opj_tcp_t *tcps =&cp->tcps[tileno]; + opj_poc_t *tcp= &tcps->pocs[pino]; + + pi[pino].first = 1; + pi[pino].poc.prg = tcp->prg; + + switch(tcp->prg){ + case CPRL: strncpy(prog, "CPRL",4); + break; + case LRCP: strncpy(prog, "LRCP",4); + break; + case PCRL: strncpy(prog, "PCRL",4); + break; + case RLCP: strncpy(prog, "RLCP",4); + break; + case RPCL: strncpy(prog, "RPCL",4); + break; + case PROG_UNKNOWN: + return OPJ_TRUE; + } + + if(!(cp->tp_on && ((!cp->cinema && (t2_mode == FINAL_PASS)) || cp->cinema))){ + pi[pino].poc.resno0 = tcp->resS; + pi[pino].poc.resno1 = tcp->resE; + pi[pino].poc.compno0 = tcp->compS; + pi[pino].poc.compno1 = tcp->compE; + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + pi[pino].poc.tx0 = tcp->txS; + pi[pino].poc.ty0 = tcp->tyS; + pi[pino].poc.tx1 = tcp->txE; + pi[pino].poc.ty1 = tcp->tyE; + }else { + if( tpnum < cur_totnum_tp){ + for(i=3;i>=0;i--){ + switch(prog[i]){ + case 'C': + if (i > tppos){ + pi[pino].poc.compno0 = tcp->compS; + pi[pino].poc.compno1 = tcp->compE; + }else{ + if (tpnum == 0){ + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->comp_t ==tcp->compE){ + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=1; + }else{ + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.compno0 = tcp->comp_t-1; + pi[pino].poc.compno1 = tcp->comp_t; + } + } + } + break; + + case 'R': + if (i > tppos){ + pi[pino].poc.resno0 = tcp->resS; + pi[pino].poc.resno1 = tcp->resE; + }else{ + if (tpnum == 0){ + tcp->res_t = tcp->resS; + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->res_t==tcp->resE){ + tcp->res_t = tcp->resS; + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + incr_top=1; + }else{ + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.resno0 = tcp->res_t - 1; + pi[pino].poc.resno1 = tcp->res_t; + } + } + } + break; + + case 'L': + if (i > tppos){ + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + }else{ + if (tpnum == 0){ + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->lay_t == tcp->layE){ + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + incr_top=1; + }else{ + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.layno0 = tcp->lay_t - 1; + pi[pino].poc.layno1 = tcp->lay_t; + } + } + } + break; + + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + if (i > tppos){ + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + }else{ + if (tpnum == 0){ + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->prc_t == tcp->prcE){ + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + incr_top=1; + }else{ + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.precno0 = tcp->prc_t - 1; + pi[pino].poc.precno1 = tcp->prc_t; + } + } + } + break; + default: + if (i > tppos){ + pi[pino].poc.tx0 = tcp->txS; + pi[pino].poc.ty0 = tcp->tyS; + pi[pino].poc.tx1 = tcp->txE; + pi[pino].poc.ty1 = tcp->tyE; + }else{ + if (tpnum == 0){ + tcp->tx0_t = tcp->txS; + tcp->ty0_t = tcp->tyS; + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->tx0_t = pi[pino].poc.tx1; + tcp->ty0_t = pi[pino].poc.ty1; + }else{ + if (incr_top == 1){ + if(tcp->tx0_t >= tcp->txE){ + if(tcp->ty0_t >= tcp->tyE){ + tcp->ty0_t = tcp->tyS; + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=1;resetX=1; + }else{ + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=0;resetX=1; + } + if(resetX==1){ + tcp->tx0_t = tcp->txS; + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx- (tcp->tx0_t % tcp->dx); + tcp->tx0_t = pi[pino].poc.tx1; + } + }else{ + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx- (tcp->tx0_t % tcp->dx); + tcp->tx0_t = pi[pino].poc.tx1; + pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); + pi[pino].poc.ty1 = tcp->ty0_t ; + incr_top=0; + } + }else{ + pi[pino].poc.tx0 = tcp->tx0_t - tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.tx1 = tcp->tx0_t ; + pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); + pi[pino].poc.ty1 = tcp->ty0_t ; + } + } + } + break; + } + break; + } + } + } + } + return OPJ_FALSE; +} + diff --git a/openjpeg-dotnet/libopenjpeg/pi.h b/openjpeg-dotnet/libopenjpeg/pi.h new file mode 100644 index 0000000..cf9135f --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/pi.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __PI_H +#define __PI_H +/** +@file pi.h +@brief Implementation of a packet iterator (PI) + +The functions in PI.C have for goal to realize a packet iterator that permits to get the next +packet following the progression order and change of it. The functions in PI.C are used +by some function in T2.C. +*/ + +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ + +/** +FIXME: documentation +*/ +typedef struct opj_pi_resolution { + int pdx, pdy; + int pw, ph; +} opj_pi_resolution_t; + +/** +FIXME: documentation +*/ +typedef struct opj_pi_comp { + int dx, dy; + /** number of resolution levels */ + int numresolutions; + opj_pi_resolution_t *resolutions; +} opj_pi_comp_t; + +/** +Packet iterator +*/ +typedef struct opj_pi_iterator { + /** Enabling Tile part generation*/ + char tp_on; + /** precise if the packet has been already used (usefull for progression order change) */ + short int *include; + /** layer step used to localize the packet in the include vector */ + int step_l; + /** resolution step used to localize the packet in the include vector */ + int step_r; + /** component step used to localize the packet in the include vector */ + int step_c; + /** precinct step used to localize the packet in the include vector */ + int step_p; + /** component that identify the packet */ + int compno; + /** resolution that identify the packet */ + int resno; + /** precinct that identify the packet */ + int precno; + /** layer that identify the packet */ + int layno; + /** 0 if the first packet */ + int first; + /** progression order change information */ + opj_poc_t poc; + /** number of components in the image */ + int numcomps; + /** Components*/ + opj_pi_comp_t *comps; + int tx0, ty0, tx1, ty1; + int x, y, dx, dy; +} opj_pi_iterator_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a packet iterator for Encoder +@param image Raw image for which the packets will be listed +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +@return Returns a packet iterator that points to the first packet of the tile +@see pi_destroy +*/ +opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int tileno,J2K_T2_MODE t2_mode); +/** +Modify the packet iterator for enabling tile part generation +@param pi Handle to the packet iterator generated in pi_initialise_encode +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@param pino Iterator index for pi +@param tpnum Tile part number of the current tile +@param tppos The position of the tile part flag in the progression order +@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +@param cur_totnum_tp The total number of tile parts in the current tile +@return Returns true if an error is detected +*/ +opj_bool pi_create_encode(opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp); +/** +Create a packet iterator for Decoder +@param image Raw image for which the packets will be listed +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@return Returns a packet iterator that points to the first packet of the tile +@see pi_destroy +*/ +opj_pi_iterator_t *pi_create_decode(opj_image_t * image, opj_cp_t * cp, int tileno); + +/** +Destroy a packet iterator +@param pi Previously created packet iterator +@param cp Coding parameters +@param tileno Number that identifies the tile for which the packets were listed +@see pi_create +*/ +void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno); + +/** +Modify the packet iterator to point to the next packet +@param pi Packet iterator to modify +@return Returns false if pi pointed to the last packet or else returns true +*/ +opj_bool pi_next(opj_pi_iterator_t * pi); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __PI_H */ diff --git a/openjpeg-dotnet/libopenjpeg/ppix_manager.c b/openjpeg-dotnet/libopenjpeg/ppix_manager.c new file mode 100644 index 0000000..58d324c --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/ppix_manager.c @@ -0,0 +1,173 @@ +/* + * $Id: ppix_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $ + * + * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2011, Professor Benoit Macq + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +/*! \file + * \brief Modification of jpip.c from 2KAN indexer + */ + +#include +#include +#include +#include "opj_includes.h" + +/* + * Write faix box of ppix + * + * @param[in] coff offset of j2k codestream + * @param[in] compno component number + * @param[in] cstr_info codestream information + * @param[in] EPHused true if if EPH option used + * @param[in] j2klen length of j2k codestream + * @param[in] cio file output handle + * @return length of faix box + */ +int write_ppixfaix( int coff, int compno, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio); + +int write_ppix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio) +{ + int len, lenp, compno, i; + opj_jp2_box_t *box; + + /* printf("cstr_info.packno %d\n", cstr_info.packno); //NMAX? */ + + lenp = -1; + box = (opj_jp2_box_t *)opj_calloc( cstr_info.numcomps, sizeof(opj_jp2_box_t)); + + for (i=0;i<2;i++){ + if (i) cio_seek( cio, lenp); + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_PPIX, 4); /* PPIX */ + + write_manf( i, cstr_info.numcomps, box, cio); + + for (compno=0; compno pow( 2, 32)){ + size_of_coding = 8; + version = 1; + } + else{ + size_of_coding = 4; + version = 0; + } + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_FAIX, 4); /* FAIX */ + cio_write( cio, version, 1); /* Version 0 = 4 bytes */ + + nmax = 0; + for( i=0; i<=cstr_info.numdecompos[compno]; i++) + nmax += cstr_info.tile[0].ph[i] * cstr_info.tile[0].pw[i] * cstr_info.numlayers; + + cio_write( cio, nmax, size_of_coding); /* NMAX */ + cio_write( cio, cstr_info.tw*cstr_info.th, size_of_coding); /* M */ + + for( tileno=0; tilenopw[resno]*tile_Idx->ph[resno]; + for( precno=0; precnopacket[ ((layno*numOfres+resno)*cstr_info.numcomps+compno)*numOfprec+precno]; + break; + case RLCP: + packet = tile_Idx->packet[ ((resno*numOflayers+layno)*cstr_info.numcomps+compno)*numOfprec+precno]; + break; + case RPCL: + packet = tile_Idx->packet[ ((resno*numOfprec+precno)*cstr_info.numcomps+compno)*numOflayers+layno]; + break; + case PCRL: + packet = tile_Idx->packet[ ((precno*cstr_info.numcomps+compno)*numOfres+resno)*numOflayers + layno]; + break; + case CPRL: + packet = tile_Idx->packet[ ((compno*numOfprec+precno)*numOfres+resno)*numOflayers + layno]; + break; + default: + fprintf( stderr, "failed to ppix indexing\n"); + } + + cio_write( cio, packet.start_pos-coff, size_of_coding); /* start position */ + cio_write( cio, packet.end_pos-packet.start_pos+1, size_of_coding); /* length */ + + num_packet++; + } + } + } + + while( num_packet < nmax){ /* PADDING */ + cio_write( cio, 0, size_of_coding); /* start position */ + cio_write( cio, 0, size_of_coding); /* length */ + num_packet++; + } + } + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); + + return len; +} diff --git a/openjpeg-dotnet/libopenjpeg/raw.c b/openjpeg-dotnet/libopenjpeg/raw.c new file mode 100644 index 0000000..3d231bf --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/raw.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/* +========================================================== + local functions +========================================================== +*/ + + +/* +========================================================== + RAW encoding interface +========================================================== +*/ + +opj_raw_t* raw_create(void) { + opj_raw_t *raw = (opj_raw_t*)opj_malloc(sizeof(opj_raw_t)); + return raw; +} + +void raw_destroy(opj_raw_t *raw) { + if(raw) { + opj_free(raw); + } +} + +int raw_numbytes(opj_raw_t *raw) { + return raw->bp - raw->start; +} + +void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len) { + raw->start = bp; + raw->lenmax = len; + raw->len = 0; + raw->c = 0; + raw->ct = 0; +} + +int raw_decode(opj_raw_t *raw) { + int d; + if (raw->ct == 0) { + raw->ct = 8; + if (raw->len == raw->lenmax) { + raw->c = 0xff; + } else { + if (raw->c == 0xff) { + raw->ct = 7; + } + raw->c = *(raw->start + raw->len); + raw->len++; + } + } + raw->ct--; + d = (raw->c >> raw->ct) & 0x01; + + return d; +} + diff --git a/openjpeg-dotnet/libopenjpeg/raw.h b/openjpeg-dotnet/libopenjpeg/raw.h new file mode 100644 index 0000000..3c4b372 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/raw.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __RAW_H +#define __RAW_H +/** +@file raw.h +@brief Implementation of operations for raw encoding (RAW) + +The functions in RAW.C have for goal to realize the operation of raw encoding linked +with the corresponding mode switch. +*/ + +/** @defgroup RAW RAW - Implementation of operations for raw encoding */ +/*@{*/ + +/** +RAW encoding operations +*/ +typedef struct opj_raw { + /** temporary buffer where bits are coded or decoded */ + unsigned char c; + /** number of bits already read or free to write */ + unsigned int ct; + /** maximum length to decode */ + unsigned int lenmax; + /** length decoded */ + unsigned int len; + /** pointer to the current position in the buffer */ + unsigned char *bp; + /** pointer to the start of the buffer */ + unsigned char *start; + /** pointer to the end of the buffer */ + unsigned char *end; +} opj_raw_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new RAW handle +@return Returns a new RAW handle if successful, returns NULL otherwise +*/ +opj_raw_t* raw_create(void); +/** +Destroy a previously created RAW handle +@param raw RAW handle to destroy +*/ +void raw_destroy(opj_raw_t *raw); +/** +Return the number of bytes written/read since initialisation +@param raw RAW handle to destroy +@return Returns the number of bytes already encoded +*/ +int raw_numbytes(opj_raw_t *raw); +/** +Initialize the decoder +@param raw RAW handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len); +/** +Decode a symbol using raw-decoder. Cfr p.506 TAUBMAN +@param raw RAW handle +@return Returns the decoded symbol (0 or 1) +*/ +int raw_decode(opj_raw_t *raw); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __RAW_H */ diff --git a/openjpeg-dotnet/libopenjpeg/t1.c b/openjpeg-dotnet/libopenjpeg/t1.c new file mode 100644 index 0000000..4777204 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/t1.c @@ -0,0 +1,1584 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" +#include "t1_luts.h" + +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static INLINE char t1_getctxno_zc(int f, int orient); +static char t1_getctxno_sc(int f); +static INLINE int t1_getctxno_mag(int f); +static char t1_getspb(int f); +static short t1_getnmsedec_sig(int x, int bitpos); +static short t1_getnmsedec_ref(int x, int bitpos); +static void t1_updateflags(flag_t *flagsp, int s, int stride); +/** +Encode significant pass +*/ +static void t1_enc_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + char type, + int vsc); +/** +Decode significant pass +*/ +static INLINE void t1_dec_sigpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc); +static INLINE void t1_dec_sigpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf); +static INLINE void t1_dec_sigpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc); +/** +Encode significant pass +*/ +static void t1_enc_sigpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + char type, + int cblksty); +/** +Decode significant pass +*/ +static void t1_dec_sigpass_raw( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty); +static void t1_dec_sigpass_mqc( + opj_t1_t *t1, + int bpno, + int orient); +static void t1_dec_sigpass_mqc_vsc( + opj_t1_t *t1, + int bpno, + int orient); +/** +Encode refinement pass +*/ +static void t1_enc_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int bpno, + int one, + int *nmsedec, + char type, + int vsc); +/** +Decode refinement pass +*/ +static INLINE void t1_dec_refpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc); +static INLINE void t1_dec_refpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf); +static INLINE void t1_dec_refpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc); + +/** +Encode refinement pass +*/ +static void t1_enc_refpass( + opj_t1_t *t1, + int bpno, + int *nmsedec, + char type, + int cblksty); +/** +Decode refinement pass +*/ +static void t1_dec_refpass_raw( + opj_t1_t *t1, + int bpno, + int cblksty); +static void t1_dec_refpass_mqc( + opj_t1_t *t1, + int bpno); +static void t1_dec_refpass_mqc_vsc( + opj_t1_t *t1, + int bpno); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + int partial, + int vsc); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass_step_partial( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf); +static void t1_dec_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf); +static void t1_dec_clnpass_step_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int partial, + int vsc); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + int cblksty); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty); +static double t1_getwmsedec( + int nmsedec, + int compno, + int level, + int orient, + int bpno, + int qmfbid, + double stepsize, + int numcomps, + int mct); +/** +Encode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param compno Component number +@param level +@param qmfbid +@param stepsize +@param cblksty Code-block style +@param numcomps +@param mct +@param tile +*/ +static void t1_encode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_enc_t* cblk, + int orient, + int compno, + int level, + int qmfbid, + double stepsize, + int cblksty, + int numcomps, + int mct, + opj_tcd_tile_t * tile); +/** +Decode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param roishift Region of interest shifting value +@param cblksty Code-block style +*/ +static void t1_decode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_dec_t* cblk, + int orient, + int roishift, + int cblksty); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +static char t1_getctxno_zc(int f, int orient) { + return lut_ctxno_zc[(orient << 8) | (f & T1_SIG_OTH)]; +} + +static char t1_getctxno_sc(int f) { + return lut_ctxno_sc[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static int t1_getctxno_mag(int f) { + int tmp1 = (f & T1_SIG_OTH) ? T1_CTXNO_MAG + 1 : T1_CTXNO_MAG; + int tmp2 = (f & T1_REFINE) ? T1_CTXNO_MAG + 2 : tmp1; + return (tmp2); +} + +static char t1_getspb(int f) { + return lut_spb[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static short t1_getnmsedec_sig(int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return lut_nmsedec_sig[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static short t1_getnmsedec_ref(int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return lut_nmsedec_ref[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return lut_nmsedec_ref0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static void t1_updateflags(flag_t *flagsp, int s, int stride) { + flag_t *np = flagsp - stride; + flag_t *sp = flagsp + stride; + + static const flag_t mod[] = { + T1_SIG_S, T1_SIG_S|T1_SGN_S, + T1_SIG_E, T1_SIG_E|T1_SGN_E, + T1_SIG_W, T1_SIG_W|T1_SGN_W, + T1_SIG_N, T1_SIG_N|T1_SGN_N + }; + + np[-1] |= T1_SIG_SE; + np[0] |= mod[s]; + np[1] |= T1_SIG_SW; + + flagsp[-1] |= mod[s+2]; + flagsp[0] |= T1_SIG; + flagsp[1] |= mod[s+4]; + + sp[-1] |= T1_SIG_NE; + sp[0] |= mod[s+6]; + sp[1] |= T1_SIG_NW; +} + +static void t1_enc_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + char type, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + v = int_abs(*datap) & one ? 1 : 0; + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v); + } + if (v) { + v = *datap < 0 ? 1 : 0; + *nmsedec += t1_getnmsedec_sig(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v ^ t1_getspb(flag)); + } + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} + +static INLINE void t1_dec_sigpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc) +{ + int v, flag; + opj_raw_t *raw = t1->raw; /* RAW component */ + + OPJ_ARG_NOT_USED(orient); + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + if (raw_decode(raw)) { + v = raw_decode(raw); /* ESSAI */ + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_sigpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = *flagsp; + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_sigpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_sigpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + char type, + int cblksty) +{ + int i, j, k, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_sigpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + bpno, + one, + nmsedec, + type, + vsc); + } + } + } +} + +static void t1_dec_sigpass_raw( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty) +{ + int i, j, k, one, half, oneplushalf, vsc; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_sigpass_step_raw( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_sigpass_mqc( + opj_t1_t *t1, + int bpno, + int orient) +{ + int i, j, k, one, half, oneplushalf; + int *data1 = t1->data; + flag_t *flags1 = &t1->flags[1]; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < (t1->h & ~3); k += 4) { + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + data1 += t1->w << 2; + flags1 += t1->flags_stride << 2; + } + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + for (j = k; j < t1->h; ++j) { + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_sigpass_mqc_vsc( + opj_t1_t *t1, + int bpno, + int orient) +{ + int i, j, k, one, half, oneplushalf, vsc; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = (j == k + 3 || j == t1->h - 1) ? 1 : 0; + t1_dec_sigpass_step_mqc_vsc( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int bpno, + int one, + int *nmsedec, + char type, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + *nmsedec += t1_getnmsedec_ref(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + v = int_abs(*datap) & one ? 1 : 0; + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v); + } + *flagsp |= T1_REFINE; + } +} + +static INLINE void t1_dec_refpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc) +{ + int v, t, flag; + + opj_raw_t *raw = t1->raw; /* RAW component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + v = raw_decode(raw); + t = v ? poshalf : neghalf; + *datap += *datap < 0 ? -t : t; + *flagsp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_refpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf) +{ + int v, t, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = *flagsp; + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + v = mqc_decode(mqc); + t = v ? poshalf : neghalf; + *datap += *datap < 0 ? -t : t; + *flagsp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_refpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc) +{ + int v, t, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + v = mqc_decode(mqc); + t = v ? poshalf : neghalf; + *datap += *datap < 0 ? -t : t; + *flagsp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass( + opj_t1_t *t1, + int bpno, + int *nmsedec, + char type, + int cblksty) +{ + int i, j, k, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_refpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + bpno, + one, + nmsedec, + type, + vsc); + } + } + } +} + +static void t1_dec_refpass_raw( + opj_t1_t *t1, + int bpno, + int cblksty) +{ + int i, j, k, one, poshalf, neghalf; + int vsc; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_refpass_step_raw( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + poshalf, + neghalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_refpass_mqc( + opj_t1_t *t1, + int bpno) +{ + int i, j, k, one, poshalf, neghalf; + int *data1 = t1->data; + flag_t *flags1 = &t1->flags[1]; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (k = 0; k < (t1->h & ~3); k += 4) { + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + } + data1 += t1->w << 2; + flags1 += t1->flags_stride << 2; + } + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + for (j = k; j < t1->h; ++j) { + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_refpass_mqc_vsc( + opj_t1_t *t1, + int bpno) +{ + int i, j, k, one, poshalf, neghalf; + int vsc; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_refpass_step_mqc_vsc( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + poshalf, + neghalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + int partial, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(*flagsp & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + v = int_abs(*datap) & one ? 1 : 0; + mqc_encode(mqc, v); + if (v) { +LABEL_PARTIAL: + *nmsedec += t1_getnmsedec_sig(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = *datap < 0 ? 1 : 0; + mqc_encode(mqc, v ^ t1_getspb(flag)); + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} + +static void t1_dec_clnpass_step_partial( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf) +{ + int v, flag; + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + OPJ_ARG_NOT_USED(orient); + + flag = *flagsp; + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + *flagsp &= ~T1_VISIT; +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = *flagsp; + if (!(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_clnpass_step_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int partial, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { +LABEL_PARTIAL: + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} + +static void t1_enc_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + int cblksty) +{ + int i, j, k, one, agg, runlen, vsc; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + if (k + 3 < t1->h) { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (MACRO_t1_flags(1 + k + 3,1 + i) + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } + } else { + agg = 0; + } + if (agg) { + for (runlen = 0; runlen < 4; ++runlen) { + if (int_abs(t1->data[((k + runlen)*t1->w) + i]) & one) + break; + } + mqc_setcurctx(mqc, T1_CTXNO_AGG); + mqc_encode(mqc, runlen != 4); + if (runlen == 4) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + mqc_encode(mqc, runlen >> 1); + mqc_encode(mqc, runlen & 1); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_clnpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + bpno, + one, + nmsedec, + agg && (j == k + runlen), + vsc); + } + } + } +} + +static void t1_dec_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty) +{ + int i, j, k, one, half, oneplushalf, agg, runlen, vsc; + int segsym = cblksty & J2K_CCP_CBLKSTY_SEGSYM; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + if (k + 3 < t1->h) { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (MACRO_t1_flags(1 + k + 3,1 + i) + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = 0; + } + if (agg) { + mqc_setcurctx(mqc, T1_CTXNO_AGG); + if (!mqc_decode(mqc)) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + runlen = mqc_decode(mqc); + runlen = (runlen << 1) | mqc_decode(mqc); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + vsc = (j == k + 3 || j == t1->h - 1) ? 1 : 0; + t1_dec_clnpass_step_vsc( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + agg && (j == k + runlen), + vsc); + } + } + } + } else { + int *data1 = t1->data; + flag_t *flags1 = &t1->flags[1]; + for (k = 0; k < (t1->h & ~3); k += 4) { + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + if (agg) { + mqc_setcurctx(mqc, T1_CTXNO_AGG); + if (!mqc_decode(mqc)) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + runlen = mqc_decode(mqc); + runlen = (runlen << 1) | mqc_decode(mqc); + flags2 += runlen * t1->flags_stride; + data2 += runlen * t1->w; + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + flags2 += t1->flags_stride; + if (agg && (j == k + runlen)) { + t1_dec_clnpass_step_partial(t1, flags2, data2, orient, oneplushalf); + } else { + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + } + data2 += t1->w; + } + } else { + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + } + data1 += t1->w << 2; + flags1 += t1->flags_stride << 2; + } + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + for (j = k; j < t1->h; ++j) { + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + } + } + + if (segsym) { + int v = 0; + mqc_setcurctx(mqc, T1_CTXNO_UNI); + v = mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + /* + if (v!=0xa) { + opj_event_msg(t1->cinfo, EVT_WARNING, "Bad segmentation symbol %x\n", v); + } + */ + } +} /* VSC and BYPASS by Antonin */ + + +/** mod fixed_quality */ +static double t1_getwmsedec( + int nmsedec, + int compno, + int level, + int orient, + int bpno, + int qmfbid, + double stepsize, + int numcomps, + int mct) +{ + double w1, w2, wmsedec; + if (qmfbid == 1) { + w1 = (mct && numcomps==3) ? mct_getnorm(compno) : 1.0; + w2 = dwt_getnorm(level, orient); + } else { /* if (qmfbid == 0) */ + w1 = (mct && numcomps==3) ? mct_getnorm_real(compno) : 1.0; + w2 = dwt_getnorm_real(level, orient); + } + wmsedec = w1 * w2 * stepsize * (1 << bpno); + wmsedec *= wmsedec * nmsedec / 8192.0; + + return wmsedec; +} + +static opj_bool allocate_buffers( + opj_t1_t *t1, + int w, + int h) +{ + int datasize=w * h; + int flagssize; + + if(datasize > t1->datasize){ + opj_aligned_free(t1->data); + t1->data = (int*) opj_aligned_malloc(datasize * sizeof(int)); + if(!t1->data){ + return OPJ_FALSE; + } + t1->datasize=datasize; + } + memset(t1->data,0,datasize * sizeof(int)); + + t1->flags_stride=w+2; + flagssize=t1->flags_stride * (h+2); + + if(flagssize > t1->flagssize){ + opj_aligned_free(t1->flags); + t1->flags = (flag_t*) opj_aligned_malloc(flagssize * sizeof(flag_t)); + if(!t1->flags){ + return OPJ_FALSE; + } + t1->flagssize=flagssize; + } + memset(t1->flags,0,flagssize * sizeof(flag_t)); + + t1->w=w; + t1->h=h; + + return OPJ_TRUE; +} + +/** mod fixed_quality */ +static void t1_encode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_enc_t* cblk, + int orient, + int compno, + int level, + int qmfbid, + double stepsize, + int cblksty, + int numcomps, + int mct, + opj_tcd_tile_t * tile) +{ + double cumwmsedec = 0.0; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + int passno, bpno, passtype; + int nmsedec = 0; + int i, max; + char type = T1_TYPE_MQ; + double tempwmsedec; + + max = 0; + for (i = 0; i < t1->w * t1->h; ++i) { + int tmp = abs(t1->data[i]); + max = int_max(max, tmp); + } + + cblk->numbps = max ? (int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS : 0; + + bpno = cblk->numbps - 1; + passtype = 2; + + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + mqc_init_enc(mqc, cblk->data); + + for (passno = 0; bpno >= 0; ++passno) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + int correction = 3; + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + + switch (passtype) { + case 0: + t1_enc_sigpass(t1, bpno, orient, &nmsedec, type, cblksty); + break; + case 1: + t1_enc_refpass(t1, bpno, &nmsedec, type, cblksty); + break; + case 2: + t1_enc_clnpass(t1, bpno, orient, &nmsedec, cblksty); + /* code switch SEGMARK (i.e. SEGSYM) */ + if (cblksty & J2K_CCP_CBLKSTY_SEGSYM) + mqc_segmark_enc(mqc); + break; + } + + /* fixed_quality */ + tempwmsedec = t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps, mct); + cumwmsedec += tempwmsedec; + tile->distotile += tempwmsedec; + + /* Code switch "RESTART" (i.e. TERMALL) */ + if ((cblksty & J2K_CCP_CBLKSTY_TERMALL) && !((passtype == 2) && (bpno - 1 < 0))) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + if (((bpno < (cblk->numbps - 4) && (passtype > 0)) + || ((bpno == (cblk->numbps - 4)) && (passtype == 2))) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + pass->term = 0; + } + } + + if (++passtype == 3) { + passtype = 0; + bpno--; + } + + if (pass->term && bpno > 0) { + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + if (type == T1_TYPE_RAW) + mqc_bypass_init_enc(mqc); + else + mqc_restart_init_enc(mqc); + } + + pass->distortiondec = cumwmsedec; + pass->rate = mqc_numbytes(mqc) + correction; /* FIXME */ + + /* Code-switch "RESET" */ + if (cblksty & J2K_CCP_CBLKSTY_RESET) + mqc_reset_enc(mqc); + } + + /* Code switch "ERTERM" (i.e. PTERM) */ + if (cblksty & J2K_CCP_CBLKSTY_PTERM) + mqc_erterm_enc(mqc); + else /* Default coding */ if (!(cblksty & J2K_CCP_CBLKSTY_LAZY)) + mqc_flush(mqc); + + cblk->totalpasses = passno; + + for (passno = 0; passnototalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (pass->rate > mqc_numbytes(mqc)) + pass->rate = mqc_numbytes(mqc); + /*Preventing generation of FF as last data byte of a pass*/ + if((pass->rate>1) && (cblk->data[pass->rate - 1] == 0xFF)){ + pass->rate--; + } + pass->len = pass->rate - (passno == 0 ? 0 : cblk->passes[passno - 1].rate); + } +} + +static void t1_decode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_dec_t* cblk, + int orient, + int roishift, + int cblksty) +{ + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + int bpno, passtype; + int segno, passno; + char type = T1_TYPE_MQ; /* BYPASS mode */ + + if(!allocate_buffers( + t1, + cblk->x1 - cblk->x0, + cblk->y1 - cblk->y0)) + { + return; + } + + bpno = roishift + cblk->numbps - 1; + passtype = 2; + + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + + for (segno = 0; segno < cblk->numsegs; ++segno) { + opj_tcd_seg_t *seg = &cblk->segs[segno]; + + /* BYPASS mode */ + type = ((bpno <= (cblk->numbps - 1) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + /* FIXME: slviewer gets here with a null pointer. Why? Partially downloaded and/or corrupt textures? */ + if(seg->data == NULL){ + continue; + } + if (type == T1_TYPE_RAW) { + raw_init_dec(raw, (*seg->data) + seg->dataindex, seg->len); + } else { + mqc_init_dec(mqc, (*seg->data) + seg->dataindex, seg->len); + } + + for (passno = 0; passno < seg->numpasses; ++passno) { + switch (passtype) { + case 0: + if (type == T1_TYPE_RAW) { + t1_dec_sigpass_raw(t1, bpno+1, orient, cblksty); + } else { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + t1_dec_sigpass_mqc_vsc(t1, bpno+1, orient); + } else { + t1_dec_sigpass_mqc(t1, bpno+1, orient); + } + } + break; + case 1: + if (type == T1_TYPE_RAW) { + t1_dec_refpass_raw(t1, bpno+1, cblksty); + } else { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + t1_dec_refpass_mqc_vsc(t1, bpno+1); + } else { + t1_dec_refpass_mqc(t1, bpno+1); + } + } + break; + case 2: + t1_dec_clnpass(t1, bpno+1, orient, cblksty); + break; + } + + if ((cblksty & J2K_CCP_CBLKSTY_RESET) && type == T1_TYPE_MQ) { + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + } + if (++passtype == 3) { + passtype = 0; + bpno--; + } + } + } +} + +/* ----------------------------------------------------------------------- */ + +opj_t1_t* t1_create(opj_common_ptr cinfo) { + opj_t1_t *t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); + if(!t1) + return NULL; + + t1->cinfo = cinfo; + /* create MQC and RAW handles */ + t1->mqc = mqc_create(); + t1->raw = raw_create(); + + t1->data=NULL; + t1->flags=NULL; + t1->datasize=0; + t1->flagssize=0; + + return t1; +} + +void t1_destroy(opj_t1_t *t1) { + if(t1) { + /* destroy MQC and RAW handles */ + mqc_destroy(t1->mqc); + raw_destroy(t1->raw); + opj_aligned_free(t1->data); + opj_aligned_free(t1->flags); + opj_free(t1); + } +} + +void t1_encode_cblks( + opj_t1_t *t1, + opj_tcd_tile_t *tile, + opj_tcp_t *tcp) +{ + int compno, resno, bandno, precno, cblkno; + + tile->distotile = 0; /* fixed_quality */ + + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + opj_tccp_t* tccp = &tcp->tccps[compno]; + int tile_w = tilec->x1 - tilec->x0; + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* restrict band = &res->bands[bandno]; + int bandconst = 8192 * 8192 / ((int) floor(band->stepsize * 8192)); + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + int* restrict datap; + int* restrict tiledp; + int cblk_w; + int cblk_h; + int i, j; + + int x = cblk->x0 - band->x0; + int y = cblk->y0 - band->y0; + if (band->bandno & 1) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (band->bandno & 2) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + + if(!allocate_buffers( + t1, + cblk->x1 - cblk->x0, + cblk->y1 - cblk->y0)) + { + return; + } + + datap=t1->data; + cblk_w = t1->w; + cblk_h = t1->h; + + tiledp=&tilec->data[(y * tile_w) + x]; + if (tccp->qmfbid == 1) { + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int tmp = tiledp[(j * tile_w) + i]; + datap[(j * cblk_w) + i] = tmp << T1_NMSEDEC_FRACBITS; + } + } + } else { /* if (tccp->qmfbid == 0) */ + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int tmp = tiledp[(j * tile_w) + i]; + datap[(j * cblk_w) + i] = + fix_mul( + tmp, + bandconst) >> (11 - T1_NMSEDEC_FRACBITS); + } + } + } + + t1_encode_cblk( + t1, + cblk, + band->bandno, + compno, + tilec->numresolutions - 1 - resno, + tccp->qmfbid, + band->stepsize, + tccp->cblksty, + tile->numcomps, + tcp->mct, + tile); + + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ +} + +void t1_decode_cblks( + opj_t1_t* t1, + opj_tcd_tilecomp_t* tilec, + opj_tccp_t* tccp) +{ + int resno, bandno, precno, cblkno; + + int tile_w = tilec->x1 - tilec->x0; + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_t* res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* restrict band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t* precinct = &band->precincts[precno]; + + for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { + opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; + int* restrict datap; + int cblk_w, cblk_h; + int x, y; + int i, j; + + t1_decode_cblk( + t1, + cblk, + band->bandno, + tccp->roishift, + tccp->cblksty); + + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + if (band->bandno & 1) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (band->bandno & 2) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + + datap=t1->data; + cblk_w = t1->w; + cblk_h = t1->h; + + if (tccp->roishift) { + int thresh = 1 << tccp->roishift; + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int val = datap[(j * cblk_w) + i]; + int mag = abs(val); + if (mag >= thresh) { + mag >>= tccp->roishift; + datap[(j * cblk_w) + i] = val < 0 ? -mag : mag; + } + } + } + } + + if (tccp->qmfbid == 1) { + int* restrict tiledp = &tilec->data[(y * tile_w) + x]; + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int tmp = datap[(j * cblk_w) + i]; + ((int*)tiledp)[(j * tile_w) + i] = tmp / 2; + } + } + } else { /* if (tccp->qmfbid == 0) */ + float* restrict tiledp = (float*) &tilec->data[(y * tile_w) + x]; + for (j = 0; j < cblk_h; ++j) { + float* restrict tiledp2 = tiledp; + for (i = 0; i < cblk_w; ++i) { + float tmp = *datap * band->stepsize; + *tiledp2 = tmp; + datap++; + tiledp2++; + } + tiledp += tile_w; + } + } + opj_free(cblk->data); + opj_free(cblk->segs); + } /* cblkno */ + opj_free(precinct->cblks.dec); + } /* precno */ + } /* bandno */ + } /* resno */ +} + diff --git a/openjpeg-dotnet/libopenjpeg/t1.h b/openjpeg-dotnet/libopenjpeg/t1.h new file mode 100644 index 0000000..572ec88 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/t1.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __T1_H +#define __T1_H +/** +@file t1.h +@brief Implementation of the tier-1 coding (coding of code-block coefficients) (T1) + +The functions in T1.C have for goal to realize the tier-1 coding operation. The functions +in T1.C are used by some function in TCD.C. +*/ + +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/* ----------------------------------------------------------------------- */ +#define T1_NMSEDEC_BITS 7 + +#define T1_SIG_NE 0x0001 /**< Context orientation : North-East direction */ +#define T1_SIG_SE 0x0002 /**< Context orientation : South-East direction */ +#define T1_SIG_SW 0x0004 /**< Context orientation : South-West direction */ +#define T1_SIG_NW 0x0008 /**< Context orientation : North-West direction */ +#define T1_SIG_N 0x0010 /**< Context orientation : North direction */ +#define T1_SIG_E 0x0020 /**< Context orientation : East direction */ +#define T1_SIG_S 0x0040 /**< Context orientation : South direction */ +#define T1_SIG_W 0x0080 /**< Context orientation : West direction */ +#define T1_SIG_OTH (T1_SIG_N|T1_SIG_NE|T1_SIG_E|T1_SIG_SE|T1_SIG_S|T1_SIG_SW|T1_SIG_W|T1_SIG_NW) +#define T1_SIG_PRIM (T1_SIG_N|T1_SIG_E|T1_SIG_S|T1_SIG_W) + +#define T1_SGN_N 0x0100 +#define T1_SGN_E 0x0200 +#define T1_SGN_S 0x0400 +#define T1_SGN_W 0x0800 +#define T1_SGN (T1_SGN_N|T1_SGN_E|T1_SGN_S|T1_SGN_W) + +#define T1_SIG 0x1000 +#define T1_REFINE 0x2000 +#define T1_VISIT 0x4000 + +#define T1_NUMCTXS_ZC 9 +#define T1_NUMCTXS_SC 5 +#define T1_NUMCTXS_MAG 3 +#define T1_NUMCTXS_AGG 1 +#define T1_NUMCTXS_UNI 1 + +#define T1_CTXNO_ZC 0 +#define T1_CTXNO_SC (T1_CTXNO_ZC+T1_NUMCTXS_ZC) +#define T1_CTXNO_MAG (T1_CTXNO_SC+T1_NUMCTXS_SC) +#define T1_CTXNO_AGG (T1_CTXNO_MAG+T1_NUMCTXS_MAG) +#define T1_CTXNO_UNI (T1_CTXNO_AGG+T1_NUMCTXS_AGG) +#define T1_NUMCTXS (T1_CTXNO_UNI+T1_NUMCTXS_UNI) + +#define T1_NMSEDEC_FRACBITS (T1_NMSEDEC_BITS-1) + +#define T1_TYPE_MQ 0 /**< Normal coding using entropy coder */ +#define T1_TYPE_RAW 1 /**< No encoding the information is store under raw format in codestream (mode switch RAW)*/ + +/* ----------------------------------------------------------------------- */ + +typedef short flag_t; + +/** +Tier-1 coding (coding of code-block coefficients) +*/ +typedef struct opj_t1 { + /** codec context */ + opj_common_ptr cinfo; + + /** MQC component */ + opj_mqc_t *mqc; + /** RAW component */ + opj_raw_t *raw; + + int *data; + flag_t *flags; + int w; + int h; + int datasize; + int flagssize; + int flags_stride; +} opj_t1_t; + +#define MACRO_t1_flags(x,y) t1->flags[((x)*(t1->flags_stride))+(y)] + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new T1 handle +and initialize the look-up tables of the Tier-1 coder/decoder +@return Returns a new T1 handle if successful, returns NULL otherwise +@see t1_init_luts +*/ +opj_t1_t* t1_create(opj_common_ptr cinfo); +/** +Destroy a previously created T1 handle +@param t1 T1 handle to destroy +*/ +void t1_destroy(opj_t1_t *t1); +/** +Encode the code-blocks of a tile +@param t1 T1 handle +@param tile The tile to encode +@param tcp Tile coding parameters +*/ +void t1_encode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); +/** +Decode the code-blocks of a tile +@param t1 T1 handle +@param tilec The tile to decode +@param tccp Tile coding parameters +*/ +void t1_decode_cblks(opj_t1_t* t1, opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T1_H */ diff --git a/openjpeg-dotnet/libopenjpeg/t1_generate_luts.c b/openjpeg-dotnet/libopenjpeg/t1_generate_luts.c new file mode 100644 index 0000000..3988041 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/t1_generate_luts.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" +#include + +static int t1_init_ctxno_zc(int f, int orient) { + int h, v, d, n, t, hv; + n = 0; + h = ((f & T1_SIG_W) != 0) + ((f & T1_SIG_E) != 0); + v = ((f & T1_SIG_N) != 0) + ((f & T1_SIG_S) != 0); + d = ((f & T1_SIG_NW) != 0) + ((f & T1_SIG_NE) != 0) + ((f & T1_SIG_SE) != 0) + ((f & T1_SIG_SW) != 0); + + switch (orient) { + case 2: + t = h; + h = v; + v = t; + case 0: + case 1: + if (!h) { + if (!v) { + if (!d) + n = 0; + else if (d == 1) + n = 1; + else + n = 2; + } else if (v == 1) { + n = 3; + } else { + n = 4; + } + } else if (h == 1) { + if (!v) { + if (!d) + n = 5; + else + n = 6; + } else { + n = 7; + } + } else + n = 8; + break; + case 3: + hv = h + v; + if (!d) { + if (!hv) { + n = 0; + } else if (hv == 1) { + n = 1; + } else { + n = 2; + } + } else if (d == 1) { + if (!hv) { + n = 3; + } else if (hv == 1) { + n = 4; + } else { + n = 5; + } + } else if (d == 2) { + if (!hv) { + n = 6; + } else { + n = 7; + } + } else { + n = 8; + } + break; + } + + return (T1_CTXNO_ZC + n); +} + +static int t1_init_ctxno_sc(int f) { + int hc, vc, n; + n = 0; + + hc = int_min(((f & (T1_SIG_E | T1_SGN_E)) == + T1_SIG_E) + ((f & (T1_SIG_W | T1_SGN_W)) == T1_SIG_W), + 1) - int_min(((f & (T1_SIG_E | T1_SGN_E)) == + (T1_SIG_E | T1_SGN_E)) + + ((f & (T1_SIG_W | T1_SGN_W)) == + (T1_SIG_W | T1_SGN_W)), 1); + + vc = int_min(((f & (T1_SIG_N | T1_SGN_N)) == + T1_SIG_N) + ((f & (T1_SIG_S | T1_SGN_S)) == T1_SIG_S), + 1) - int_min(((f & (T1_SIG_N | T1_SGN_N)) == + (T1_SIG_N | T1_SGN_N)) + + ((f & (T1_SIG_S | T1_SGN_S)) == + (T1_SIG_S | T1_SGN_S)), 1); + + if (hc < 0) { + hc = -hc; + vc = -vc; + } + if (!hc) { + if (vc == -1) + n = 1; + else if (!vc) + n = 0; + else + n = 1; + } else if (hc == 1) { + if (vc == -1) + n = 2; + else if (!vc) + n = 3; + else + n = 4; + } + + return (T1_CTXNO_SC + n); +} + +static int t1_init_spb(int f) { + int hc, vc, n; + + hc = int_min(((f & (T1_SIG_E | T1_SGN_E)) == + T1_SIG_E) + ((f & (T1_SIG_W | T1_SGN_W)) == T1_SIG_W), + 1) - int_min(((f & (T1_SIG_E | T1_SGN_E)) == + (T1_SIG_E | T1_SGN_E)) + + ((f & (T1_SIG_W | T1_SGN_W)) == + (T1_SIG_W | T1_SGN_W)), 1); + + vc = int_min(((f & (T1_SIG_N | T1_SGN_N)) == + T1_SIG_N) + ((f & (T1_SIG_S | T1_SGN_S)) == T1_SIG_S), + 1) - int_min(((f & (T1_SIG_N | T1_SGN_N)) == + (T1_SIG_N | T1_SGN_N)) + + ((f & (T1_SIG_S | T1_SGN_S)) == + (T1_SIG_S | T1_SGN_S)), 1); + + if (!hc && !vc) + n = 0; + else + n = (!(hc > 0 || (!hc && vc > 0))); + + return n; +} + +void dump_array16(int array[],int size){ + int i; + --size; + for (i = 0; i < size; ++i) { + printf("0x%04x, ", array[i]); + if(!((i+1)&0x7)) + printf("\n "); + } + printf("0x%04x\n};\n\n", array[size]); +} + +int main(){ + int i, j; + double u, v, t; + + int lut_ctxno_zc[1024]; + int lut_nmsedec_sig[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS]; + + printf("/* This file was automatically generated by t1_generate_luts.c */\n\n"); + + // lut_ctxno_zc + for (j = 0; j < 4; ++j) { + for (i = 0; i < 256; ++i) { + int orient = j; + if (orient == 2) { + orient = 1; + } else if (orient == 1) { + orient = 2; + } + lut_ctxno_zc[(orient << 8) | i] = t1_init_ctxno_zc(i, j); + } + } + + printf("static char lut_ctxno_zc[1024] = {\n "); + for (i = 0; i < 1023; ++i) { + printf("%i, ", lut_ctxno_zc[i]); + if(!((i+1)&0x1f)) + printf("\n "); + } + printf("%i\n};\n\n", lut_ctxno_zc[1023]); + + // lut_ctxno_sc + printf("static char lut_ctxno_sc[256] = {\n "); + for (i = 0; i < 255; ++i) { + printf("0x%x, ", t1_init_ctxno_sc(i << 4)); + if(!((i+1)&0xf)) + printf("\n "); + } + printf("0x%x\n};\n\n", t1_init_ctxno_sc(255 << 4)); + + // lut_spb + printf("static char lut_spb[256] = {\n "); + for (i = 0; i < 255; ++i) { + printf("%i, ", t1_init_spb(i << 4)); + if(!((i+1)&0x1f)) + printf("\n "); + } + printf("%i\n};\n\n", t1_init_spb(255 << 4)); + + /* FIXME FIXME FIXME */ + /* fprintf(stdout,"nmsedec luts:\n"); */ + for (i = 0; i < (1 << T1_NMSEDEC_BITS); ++i) { + t = i / pow(2, T1_NMSEDEC_FRACBITS); + u = t; + v = t - 1.5; + lut_nmsedec_sig[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + lut_nmsedec_sig0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + u = t - 1.0; + if (i & (1 << (T1_NMSEDEC_BITS - 1))) { + v = t - 1.5; + } else { + v = t - 0.5; + } + lut_nmsedec_ref[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + lut_nmsedec_ref0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + } + + printf("static short lut_nmsedec_sig[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_sig, 1 << T1_NMSEDEC_BITS); + + printf("static short lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_sig0, 1 << T1_NMSEDEC_BITS); + + printf("static short lut_nmsedec_ref[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_ref, 1 << T1_NMSEDEC_BITS); + + printf("static short lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_ref0, 1 << T1_NMSEDEC_BITS); + + return 0; +} diff --git a/openjpeg-dotnet/libopenjpeg/t1_luts.h b/openjpeg-dotnet/libopenjpeg/t1_luts.h new file mode 100644 index 0000000..e5e33f6 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/t1_luts.h @@ -0,0 +1,143 @@ +/* This file was automatically generated by t1_generate_luts.c */ + +static char lut_ctxno_zc[1024] = { + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 3, 3, 6, 3, 6, 6, 8, 3, 6, 6, 8, 6, 8, 8, 8, 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8 +}; + +static char lut_ctxno_sc[256] = { + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xb, 0xc, 0xb, 0xd, 0xc, 0xd, 0xc, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd, 0x9, 0xa, 0xd, 0xd, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xb, 0x9, 0xa, 0xd, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xd, 0xc, 0xd, 0xb, 0xc, 0xb, 0xc, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xb, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xd, 0x9, 0xa, 0xb, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xb, 0x9, 0xa, 0xb, 0xb, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xb, 0x9, 0xa, 0xb, 0xb, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xd, 0x9, 0xa, 0xb, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xb, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xd, 0xc, 0xd, 0xb, 0xc, 0xb, 0xc, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xb, 0x9, 0xa, 0xd, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd, 0x9, 0xa, 0xd, 0xd, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xb, 0xc, 0xb, 0xd, 0xc, 0xd, 0xc, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd +}; + +static char lut_spb[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static short lut_nmsedec_sig[1 << T1_NMSEDEC_BITS] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0180, 0x0300, 0x0480, 0x0600, 0x0780, 0x0900, 0x0a80, + 0x0c00, 0x0d80, 0x0f00, 0x1080, 0x1200, 0x1380, 0x1500, 0x1680, + 0x1800, 0x1980, 0x1b00, 0x1c80, 0x1e00, 0x1f80, 0x2100, 0x2280, + 0x2400, 0x2580, 0x2700, 0x2880, 0x2a00, 0x2b80, 0x2d00, 0x2e80, + 0x3000, 0x3180, 0x3300, 0x3480, 0x3600, 0x3780, 0x3900, 0x3a80, + 0x3c00, 0x3d80, 0x3f00, 0x4080, 0x4200, 0x4380, 0x4500, 0x4680, + 0x4800, 0x4980, 0x4b00, 0x4c80, 0x4e00, 0x4f80, 0x5100, 0x5280, + 0x5400, 0x5580, 0x5700, 0x5880, 0x5a00, 0x5b80, 0x5d00, 0x5e80, + 0x6000, 0x6180, 0x6300, 0x6480, 0x6600, 0x6780, 0x6900, 0x6a80, + 0x6c00, 0x6d80, 0x6f00, 0x7080, 0x7200, 0x7380, 0x7500, 0x7680 +}; + +static short lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0100, 0x0100, 0x0100, 0x0180, 0x0180, 0x0200, + 0x0200, 0x0280, 0x0280, 0x0300, 0x0300, 0x0380, 0x0400, 0x0400, + 0x0480, 0x0500, 0x0580, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b80, 0x0c00, + 0x0c80, 0x0d00, 0x0e00, 0x0e80, 0x0f00, 0x1000, 0x1080, 0x1180, + 0x1200, 0x1300, 0x1380, 0x1480, 0x1500, 0x1600, 0x1700, 0x1780, + 0x1880, 0x1980, 0x1a80, 0x1b00, 0x1c00, 0x1d00, 0x1e00, 0x1f00, + 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2680, 0x2780, + 0x2880, 0x2980, 0x2b00, 0x2c00, 0x2d00, 0x2e80, 0x2f80, 0x3100, + 0x3200, 0x3380, 0x3480, 0x3600, 0x3700, 0x3880, 0x3a00, 0x3b00, + 0x3c80, 0x3e00, 0x3f80, 0x4080, 0x4200, 0x4380, 0x4500, 0x4680, + 0x4800, 0x4980, 0x4b00, 0x4c80, 0x4e00, 0x4f80, 0x5180, 0x5300, + 0x5480, 0x5600, 0x5800, 0x5980, 0x5b00, 0x5d00, 0x5e80, 0x6080, + 0x6200, 0x6400, 0x6580, 0x6780, 0x6900, 0x6b00, 0x6d00, 0x6e80, + 0x7080, 0x7280, 0x7480, 0x7600, 0x7800, 0x7a00, 0x7c00, 0x7e00 +}; + +static short lut_nmsedec_ref[1 << T1_NMSEDEC_BITS] = { + 0x1800, 0x1780, 0x1700, 0x1680, 0x1600, 0x1580, 0x1500, 0x1480, + 0x1400, 0x1380, 0x1300, 0x1280, 0x1200, 0x1180, 0x1100, 0x1080, + 0x1000, 0x0f80, 0x0f00, 0x0e80, 0x0e00, 0x0d80, 0x0d00, 0x0c80, + 0x0c00, 0x0b80, 0x0b00, 0x0a80, 0x0a00, 0x0980, 0x0900, 0x0880, + 0x0800, 0x0780, 0x0700, 0x0680, 0x0600, 0x0580, 0x0500, 0x0480, + 0x0400, 0x0380, 0x0300, 0x0280, 0x0200, 0x0180, 0x0100, 0x0080, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, + 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b00, 0x0b80, + 0x0c00, 0x0c80, 0x0d00, 0x0d80, 0x0e00, 0x0e80, 0x0f00, 0x0f80, + 0x1000, 0x1080, 0x1100, 0x1180, 0x1200, 0x1280, 0x1300, 0x1380, + 0x1400, 0x1480, 0x1500, 0x1580, 0x1600, 0x1680, 0x1700, 0x1780 +}; + +static short lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS] = { + 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x1b00, 0x1a80, 0x1980, + 0x1880, 0x1780, 0x1700, 0x1600, 0x1500, 0x1480, 0x1380, 0x1300, + 0x1200, 0x1180, 0x1080, 0x1000, 0x0f00, 0x0e80, 0x0e00, 0x0d00, + 0x0c80, 0x0c00, 0x0b80, 0x0a80, 0x0a00, 0x0980, 0x0900, 0x0880, + 0x0800, 0x0780, 0x0700, 0x0680, 0x0600, 0x0580, 0x0580, 0x0500, + 0x0480, 0x0400, 0x0400, 0x0380, 0x0300, 0x0300, 0x0280, 0x0280, + 0x0200, 0x0200, 0x0180, 0x0180, 0x0100, 0x0100, 0x0100, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0100, 0x0100, 0x0100, 0x0180, 0x0180, 0x0200, + 0x0200, 0x0280, 0x0280, 0x0300, 0x0300, 0x0380, 0x0400, 0x0400, + 0x0480, 0x0500, 0x0580, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b80, 0x0c00, + 0x0c80, 0x0d00, 0x0e00, 0x0e80, 0x0f00, 0x1000, 0x1080, 0x1180, + 0x1200, 0x1300, 0x1380, 0x1480, 0x1500, 0x1600, 0x1700, 0x1780, + 0x1880, 0x1980, 0x1a80, 0x1b00, 0x1c00, 0x1d00, 0x1e00, 0x1f00 +}; + diff --git a/openjpeg-dotnet/libopenjpeg/t2.c b/openjpeg-dotnet/libopenjpeg/t2.c new file mode 100644 index 0000000..232a543 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/t2.c @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static void t2_putcommacode(opj_bio_t *bio, int n); +static int t2_getcommacode(opj_bio_t *bio); +/** +Variable length code for signalling delta Zil (truncation point) +@param bio Bit Input/Output component +@param n delta Zil +*/ +static void t2_putnumpasses(opj_bio_t *bio, int n); +static int t2_getnumpasses(opj_bio_t *bio); +/** +Encode a packet of a tile to a destination buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param dest Destination buffer +@param len Length of the destination buffer +@param cstr_info Codestream information structure +@param tileno Number of the tile encoded +@return +*/ +static int t2_encode_packet(opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi, unsigned char *dest, int len, opj_codestream_info_t *cstr_info, int tileno); +/** +@param cblk +@param index +@param cblksty +@param first +*/ +static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first); +/** +Decode a packet of a tile from a source buffer +@param t2 T2 handle +@param src Source buffer +@param len Length of the source buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param pack_info Packet information +@return +*/ +static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile, + opj_tcp_t *tcp, opj_pi_iterator_t *pi, opj_packet_info_t *pack_info); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +/* #define RESTART 0x04 */ + +static void t2_putcommacode(opj_bio_t *bio, int n) { + while (--n >= 0) { + bio_write(bio, 1, 1); + } + bio_write(bio, 0, 1); +} + +static int t2_getcommacode(opj_bio_t *bio) { + int n; + for (n = 0; bio_read(bio, 1); n++) { + ; + } + return n; +} + +static void t2_putnumpasses(opj_bio_t *bio, int n) { + if (n == 1) { + bio_write(bio, 0, 1); + } else if (n == 2) { + bio_write(bio, 2, 2); + } else if (n <= 5) { + bio_write(bio, 0xc | (n - 3), 4); + } else if (n <= 36) { + bio_write(bio, 0x1e0 | (n - 6), 9); + } else if (n <= 164) { + bio_write(bio, 0xff80 | (n - 37), 16); + } +} + +static int t2_getnumpasses(opj_bio_t *bio) { + int n; + if (!bio_read(bio, 1)) + return 1; + if (!bio_read(bio, 1)) + return 2; + if ((n = bio_read(bio, 2)) != 3) + return (3 + n); + if ((n = bio_read(bio, 5)) != 31) + return (6 + n); + return (37 + bio_read(bio, 7)); +} + +static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_iterator_t *pi, unsigned char *dest, int length, opj_codestream_info_t *cstr_info, int tileno) { + int bandno, cblkno; + unsigned char *c = dest; + + int compno = pi->compno; /* component value */ + int resno = pi->resno; /* resolution level value */ + int precno = pi->precno; /* precinct value */ + int layno = pi->layno; /* quality layer value */ + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + opj_bio_t *bio = NULL; /* BIO component */ + + /* */ + if (tcp->csty & J2K_CP_CSTY_SOP) { + c[0] = 255; + c[1] = 145; + c[2] = 0; + c[3] = 4; + c[4] = (unsigned char)((tile->packno % 65536) / 256); + c[5] = (unsigned char)((tile->packno % 65536) % 256); + c += 6; + } + /* */ + + if (!layno) { + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + cblk->numpasses = 0; + tgt_setvalue(prc->imsbtree, cblkno, band->numbps - cblk->numbps); + } + } + } + + bio = bio_create(); + bio_init_enc(bio, c, length); + bio_write(bio, 1, 1); /* Empty header bit */ + + /* Writing Packet header */ + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if (!cblk->numpasses && layer->numpasses) { + tgt_setvalue(prc->incltree, cblkno, layno); + } + } + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + int increment = 0; + int nump = 0; + int len = 0, passno; + /* cblk inclusion bits */ + if (!cblk->numpasses) { + tgt_encode(bio, prc->incltree, cblkno, layno + 1); + } else { + bio_write(bio, layer->numpasses != 0, 1); + } + /* if cblk not included, go to the next cblk */ + if (!layer->numpasses) { + continue; + } + /* if first instance of cblk --> zero bit-planes information */ + if (!cblk->numpasses) { + cblk->numlenbits = 3; + tgt_encode(bio, prc->imsbtree, cblkno, 999); + } + /* number of coding passes included */ + t2_putnumpasses(bio, layer->numpasses); + + /* computation of the increase of the length indicator and insertion in the header */ + for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + nump++; + len += pass->len; + if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + increment = int_max(increment, int_floorlog2(len) + 1 - (cblk->numlenbits + int_floorlog2(nump))); + len = 0; + nump = 0; + } + } + t2_putcommacode(bio, increment); + + /* computation of the new Length indicator */ + cblk->numlenbits += increment; + + /* insertion of the codeword segment length */ + for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + nump++; + len += pass->len; + if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + bio_write(bio, len, cblk->numlenbits + int_floorlog2(nump)); + len = 0; + nump = 0; + } + } + } + } + + if (bio_flush(bio)) { + bio_destroy(bio); + return -999; /* modified to eliminate longjmp !! */ + } + + c += bio_numbytes(bio); + bio_destroy(bio); + + /* */ + if (tcp->csty & J2K_CP_CSTY_EPH) { + c[0] = 255; + c[1] = 146; + c += 2; + } + /* */ + + /* << INDEX */ + /* End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value */ + if(cstr_info && cstr_info->index_write) { + opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; + info_PK->end_ph_pos = (int)(c - dest); + } + /* INDEX >> */ + + /* Writing the packet body */ + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if (!layer->numpasses) { + continue; + } + if (c + layer->len > dest + length) { + return -999; + } + + memcpy(c, layer->data, layer->len); + cblk->numpasses += layer->numpasses; + c += layer->len; + /* << INDEX */ + if(cstr_info && cstr_info->index_write) { + opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; + info_PK->disto += layer->disto; + if (cstr_info->D_max < info_PK->disto) { + cstr_info->D_max = info_PK->disto; + } + } + /* INDEX >> */ + } + } + + return (c - dest); +} + +static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first) { + opj_tcd_seg_t* seg; + cblk->segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, (index + 1) * sizeof(opj_tcd_seg_t)); + seg = &cblk->segs[index]; + seg->data = NULL; + seg->dataindex = 0; + seg->numpasses = 0; + seg->len = 0; + if (cblksty & J2K_CCP_CBLKSTY_TERMALL) { + seg->maxpasses = 1; + } + else if (cblksty & J2K_CCP_CBLKSTY_LAZY) { + if (first) { + seg->maxpasses = 10; + } else { + seg->maxpasses = (((seg - 1)->maxpasses == 1) || ((seg - 1)->maxpasses == 10)) ? 2 : 1; + } + } else { + seg->maxpasses = 109; + } +} + +static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile, + opj_tcp_t *tcp, opj_pi_iterator_t *pi, opj_packet_info_t *pack_info) { + int bandno, cblkno; + unsigned char *c = src; + + opj_cp_t *cp = t2->cp; + + int compno = pi->compno; /* component value */ + int resno = pi->resno; /* resolution level value */ + int precno = pi->precno; /* precinct value */ + int layno = pi->layno; /* quality layer value */ + + opj_tcd_resolution_t* res = &tile->comps[compno].resolutions[resno]; + + unsigned char *hd = NULL; + int present; + + opj_bio_t *bio = NULL; /* BIO component */ + + if (layno == 0) { + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + cblk->numsegs = 0; + } + } + } + + /* SOP markers */ + + if (tcp->csty & J2K_CP_CSTY_SOP) { + if ((*c) != 0xff || (*(c + 1) != 0x91)) { + opj_event_msg(t2->cinfo, EVT_WARNING, "Expected SOP marker\n"); + } else { + c += 6; + } + + /** TODO : check the Nsop value */ + } + + /* + When the marker PPT/PPM is used the packet header are store in PPT/PPM marker + This part deal with this caracteristic + step 1: Read packet header in the saved structure + step 2: Return to codestream for decoding + */ + + bio = bio_create(); + + if (cp->ppm == 1) { /* PPM */ + hd = cp->ppm_data; + bio_init_dec(bio, hd, cp->ppm_len); + } else if (tcp->ppt == 1) { /* PPT */ + hd = tcp->ppt_data; + bio_init_dec(bio, hd, tcp->ppt_len); + } else { /* Normal Case */ + hd = c; + bio_init_dec(bio, hd, src+len-hd); + } + + present = bio_read(bio, 1); + + if (!present) { + bio_inalign(bio); + hd += bio_numbytes(bio); + bio_destroy(bio); + + /* EPH markers */ + + if (tcp->csty & J2K_CP_CSTY_EPH) { + if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { + printf("Error : expected EPH marker\n"); + } else { + hd += 2; + } + } + + /* << INDEX */ + /* End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value*/ + if(pack_info) { + pack_info->end_ph_pos = (int)(c - src); + } + /* INDEX >> */ + + if (cp->ppm == 1) { /* PPM case */ + cp->ppm_len += cp->ppm_data-hd; + cp->ppm_data = hd; + return (c - src); + } + if (tcp->ppt == 1) { /* PPT case */ + tcp->ppt_len+=tcp->ppt_data-hd; + tcp->ppt_data = hd; + return (c - src); + } + + return (hd - src); + } + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int included, increment, n, segno; + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + /* if cblk not yet included before --> inclusion tagtree */ + if (!cblk->numsegs) { + included = tgt_decode(bio, prc->incltree, cblkno, layno + 1); + /* else one bit */ + } else { + included = bio_read(bio, 1); + } + /* if cblk not included */ + if (!included) { + cblk->numnewpasses = 0; + continue; + } + /* if cblk not yet included --> zero-bitplane tagtree */ + if (!cblk->numsegs) { + int i, numimsbs; + for (i = 0; !tgt_decode(bio, prc->imsbtree, cblkno, i); i++) { + ; + } + numimsbs = i - 1; + cblk->numbps = band->numbps - numimsbs; + cblk->numlenbits = 3; + } + /* number of coding passes */ + cblk->numnewpasses = t2_getnumpasses(bio); + increment = t2_getcommacode(bio); + /* length indicator increment */ + cblk->numlenbits += increment; + segno = 0; + if (!cblk->numsegs) { + t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 1); + } else { + segno = cblk->numsegs - 1; + if (cblk->segs[segno].numpasses == cblk->segs[segno].maxpasses) { + ++segno; + t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0); + } + } + n = cblk->numnewpasses; + + do { + cblk->segs[segno].numnewpasses = int_min(cblk->segs[segno].maxpasses - cblk->segs[segno].numpasses, n); + cblk->segs[segno].newlen = bio_read(bio, cblk->numlenbits + int_floorlog2(cblk->segs[segno].numnewpasses)); + n -= cblk->segs[segno].numnewpasses; + if (n > 0) { + ++segno; + t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0); + } + } while (n > 0); + } + } + + if (bio_inalign(bio)) { + bio_destroy(bio); + return -999; + } + + hd += bio_numbytes(bio); + bio_destroy(bio); + + /* EPH markers */ + if (tcp->csty & J2K_CP_CSTY_EPH) { + if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { + opj_event_msg(t2->cinfo, EVT_ERROR, "Expected EPH marker\n"); + return -999; + } else { + hd += 2; + } + } + + /* << INDEX */ + /* End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value*/ + if(pack_info) { + pack_info->end_ph_pos = (int)(hd - src); + } + /* INDEX >> */ + + if (cp->ppm==1) { + cp->ppm_len+=cp->ppm_data-hd; + cp->ppm_data = hd; + } else if (tcp->ppt == 1) { + tcp->ppt_len+=tcp->ppt_data-hd; + tcp->ppt_data = hd; + } else { + c=hd; + } + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + opj_tcd_seg_t *seg = NULL; + if (!cblk->numnewpasses) + continue; + if (!cblk->numsegs) { + seg = &cblk->segs[0]; + cblk->numsegs++; + cblk->len = 0; + } else { + seg = &cblk->segs[cblk->numsegs - 1]; + if (seg->numpasses == seg->maxpasses) { + seg++; + cblk->numsegs++; + } + } + + do { + if (c + seg->newlen > src + len) { + return -999; + } + +#ifdef USE_JPWL + /* we need here a j2k handle to verify if making a check to + the validity of cblocks parameters is selected from user (-W) */ + + /* let's check that we are not exceeding */ + if ((cblk->len + seg->newlen) > 8192) { + opj_event_msg(t2->cinfo, EVT_WARNING, + "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + seg->newlen, cblkno, precno, bandno, resno, compno); + if (!JPWL_ASSUME) { + opj_event_msg(t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return -999; + } + seg->newlen = 8192 - cblk->len; + opj_event_msg(t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", seg->newlen); + break; + }; + +#endif /* USE_JPWL */ + + cblk->data = (unsigned char*) opj_realloc(cblk->data, (cblk->len + seg->newlen) * sizeof(unsigned char)); + memcpy(cblk->data + cblk->len, c, seg->newlen); + if (seg->numpasses == 0) { + seg->data = &cblk->data; + seg->dataindex = cblk->len; + } + c += seg->newlen; + cblk->len += seg->newlen; + seg->len += seg->newlen; + seg->numpasses += seg->numnewpasses; + cblk->numnewpasses -= seg->numnewpasses; + if (cblk->numnewpasses > 0) { + seg++; + cblk->numsegs++; + } + } while (cblk->numnewpasses > 0); + } + } + + return (c - src); +} + +/* ----------------------------------------------------------------------- */ + +int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_codestream_info_t *cstr_info,int tpnum, int tppos,int pino, J2K_T2_MODE t2_mode, int cur_totnum_tp){ + unsigned char *c = dest; + int e = 0; + int compno; + opj_pi_iterator_t *pi = NULL; + int poc; + opj_image_t *image = t2->image; + opj_cp_t *cp = t2->cp; + opj_tcp_t *tcp = &cp->tcps[tileno]; + int pocno = cp->cinema == CINEMA4K_24? 2: 1; + int maxcomp = cp->max_comp_size > 0 ? image->numcomps : 1; + + pi = pi_initialise_encode(image, cp, tileno, t2_mode); + if(!pi) { + /* TODO: throw an error */ + return -999; + } + + if(t2_mode == THRESH_CALC ){ /* Calculating threshold */ + for(compno = 0; compno < maxcomp; compno++ ){ + for(poc = 0; poc < pocno ; poc++){ + int comp_len = 0; + int tpnum = compno; + if (pi_create_encode(pi, cp,tileno,poc,tpnum,tppos,t2_mode,cur_totnum_tp)) { + opj_event_msg(t2->cinfo, EVT_ERROR, "Error initializing Packet Iterator\n"); + pi_destroy(pi, cp, tileno); + return -999; + } + while (pi_next(&pi[poc])) { + if (pi[poc].layno < maxlayers) { + e = t2_encode_packet(tile, &cp->tcps[tileno], &pi[poc], c, dest + len - c, cstr_info, tileno); + comp_len = comp_len + e; + if (e == -999) { + break; + } else { + c += e; + } + } + } + if (e == -999) break; + if (cp->max_comp_size){ + if (comp_len > cp->max_comp_size){ + e = -999; + break; + } + } + } + if (e == -999) break; + } + }else{ /* t2_mode == FINAL_PASS */ + pi_create_encode(pi, cp,tileno,pino,tpnum,tppos,t2_mode,cur_totnum_tp); + while (pi_next(&pi[pino])) { + if (pi[pino].layno < maxlayers) { + e = t2_encode_packet(tile, &cp->tcps[tileno], &pi[pino], c, dest + len - c, cstr_info, tileno); + if (e == -999) { + break; + } else { + c += e; + } + /* INDEX >> */ + if(cstr_info) { + if(cstr_info->index_write) { + opj_tile_info_t *info_TL = &cstr_info->tile[tileno]; + opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno]; + if (!cstr_info->packno) { + info_PK->start_pos = info_TL->end_header + 1; + } else { + info_PK->start_pos = ((cp->tp_on | tcp->POC)&& info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + e - 1; + info_PK->end_ph_pos += info_PK->start_pos - 1; /* End of packet header which now only represents the distance + // to start of packet is incremented by value of start of packet*/ + } + + cstr_info->packno++; + } + /* << INDEX */ + tile->packno++; + } + } + } + + pi_destroy(pi, cp, tileno); + + if (e == -999) { + return e; + } + + return (c - dest); +} + +int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile, opj_codestream_info_t *cstr_info) { + unsigned char *c = src; + opj_pi_iterator_t *pi; + int pino, e = 0; + int n = 0, curtp = 0; + int tp_start_packno; + + opj_image_t *image = t2->image; + opj_cp_t *cp = t2->cp; + + /* create a packet iterator */ + pi = pi_create_decode(image, cp, tileno); + if(!pi) { + /* TODO: throw an error */ + return -999; + } + + tp_start_packno = 0; + + for (pino = 0; pino <= cp->tcps[tileno].numpocs; pino++) { + while (pi_next(&pi[pino])) { + if ((cp->layer==0) || (cp->layer>=((pi[pino].layno)+1))) { + opj_packet_info_t *pack_info; + if (cstr_info) + pack_info = &cstr_info->tile[tileno].packet[cstr_info->packno]; + else + pack_info = NULL; + e = t2_decode_packet(t2, c, src + len - c, tile, &cp->tcps[tileno], &pi[pino], pack_info); + } else { + e = 0; + } + if(e == -999) return -999; + /* progression in resolution */ + image->comps[pi[pino].compno].resno_decoded = + (e > 0) ? + int_max(pi[pino].resno, image->comps[pi[pino].compno].resno_decoded) + : image->comps[pi[pino].compno].resno_decoded; + n++; + + /* INDEX >> */ + if(cstr_info) { + opj_tile_info_t *info_TL = &cstr_info->tile[tileno]; + opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno]; + if (!cstr_info->packno) { + info_PK->start_pos = info_TL->end_header + 1; + } else if (info_TL->packet[cstr_info->packno-1].end_pos >= (int)cstr_info->tile[tileno].tp[curtp].tp_end_pos){ /* New tile part*/ + info_TL->tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; /* Number of packets in previous tile-part*/ + info_TL->tp[curtp].tp_start_pack = tp_start_packno; + tp_start_packno = cstr_info->packno; + curtp++; + info_PK->start_pos = cstr_info->tile[tileno].tp[curtp].tp_end_header+1; + } else { + info_PK->start_pos = (cp->tp_on && info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + e - 1; + info_PK->end_ph_pos += info_PK->start_pos - 1; /* End of packet header which now only represents the distance + // to start of packet is incremented by value of start of packet*/ + cstr_info->packno++; + } + /* << INDEX */ + + if (e == -999) { /* ADD */ + break; + } else { + c += e; + } + } + } + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[tileno].tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; /* Number of packets in last tile-part*/ + cstr_info->tile[tileno].tp[curtp].tp_start_pack = tp_start_packno; + } + /* << INDEX */ + + /* don't forget to release pi */ + pi_destroy(pi, cp, tileno); + + if (e == -999) { + return e; + } + + return (c - src); +} + +/* ----------------------------------------------------------------------- */ + +opj_t2_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp) { + /* create the tcd structure */ + opj_t2_t *t2 = (opj_t2_t*)opj_malloc(sizeof(opj_t2_t)); + if(!t2) return NULL; + t2->cinfo = cinfo; + t2->image = image; + t2->cp = cp; + + return t2; +} + +void t2_destroy(opj_t2_t *t2) { + if(t2) { + opj_free(t2); + } +} + + + + + diff --git a/openjpeg-dotnet/libopenjpeg/t2.h b/openjpeg-dotnet/libopenjpeg/t2.h new file mode 100644 index 0000000..2151ba6 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/t2.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __T2_H +#define __T2_H +/** +@file t2.h +@brief Implementation of a tier-2 coding (packetization of code-block data) (T2) + +*/ + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** +Tier-2 coding +*/ +typedef struct opj_t2 { + /** codec context */ + opj_common_ptr cinfo; + + /** Encoding: pointer to the src image. Decoding: pointer to the dst image. */ + opj_image_t *image; + /** pointer to the image coding parameters */ + opj_cp_t *cp; +} opj_t2_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Encode the packets of a tile to a destination buffer +@param t2 T2 handle +@param tileno number of the tile encoded +@param tile the tile for which to write the packets +@param maxlayers maximum number of layers +@param dest the destination buffer +@param len the length of the destination buffer +@param cstr_info Codestream information structure +@param tpnum Tile part number of the current tile +@param tppos The position of the tile part flag in the progression order +@param pino +@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +@param cur_totnum_tp The total number of tile parts in the current tile +*/ +int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_codestream_info_t *cstr_info,int tpnum, int tppos,int pino,J2K_T2_MODE t2_mode,int cur_totnum_tp); +/** +Decode the packets of a tile from a source buffer +@param t2 T2 handle +@param src the source buffer +@param len length of the source buffer +@param tileno number that identifies the tile for which to decode the packets +@param tile tile for which to decode the packets +@param cstr_info Codestream information structure + */ +int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile, opj_codestream_info_t *cstr_info); + +/** +Create a T2 handle +@param cinfo Codec context info +@param image Source or destination image +@param cp Image coding parameters +@return Returns a new T2 handle if successful, returns NULL otherwise +*/ +opj_t2_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp); +/** +Destroy a T2 handle +@param t2 T2 handle to destroy +*/ +void t2_destroy(opj_t2_t *t2); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T2_H */ diff --git a/openjpeg-dotnet/libopenjpeg/tcd.c b/openjpeg-dotnet/libopenjpeg/tcd.c new file mode 100644 index 0000000..18cdbc7 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/tcd.c @@ -0,0 +1,1524 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { + int tileno, compno, resno, bandno, precno;/*, cblkno;*/ + + fprintf(fd, "image {\n"); + fprintf(fd, " tw=%d, th=%d x0=%d x1=%d y0=%d y1=%d\n", + img->tw, img->th, tcd->image->x0, tcd->image->x1, tcd->image->y0, tcd->image->y1); + + for (tileno = 0; tileno < img->th * img->tw; tileno++) { + opj_tcd_tile_t *tile = &tcd->tcd_image->tiles[tileno]; + fprintf(fd, " tile {\n"); + fprintf(fd, " x0=%d, y0=%d, x1=%d, y1=%d, numcomps=%d\n", + tile->x0, tile->y0, tile->x1, tile->y1, tile->numcomps); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + fprintf(fd, " tilec {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, numresolutions=%d\n", + tilec->x0, tilec->y0, tilec->x1, tilec->y1, tilec->numresolutions); + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + fprintf(fd, "\n res {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, pw=%d, ph=%d, numbands=%d\n", + res->x0, res->y0, res->x1, res->y1, res->pw, res->ph, res->numbands); + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + fprintf(fd, " band {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, stepsize=%f, numbps=%d\n", + band->x0, band->y0, band->x1, band->y1, band->stepsize, band->numbps); + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prec = &band->precincts[precno]; + fprintf(fd, " prec {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, cw=%d, ch=%d\n", + prec->x0, prec->y0, prec->x1, prec->y1, prec->cw, prec->ch); + /* + for (cblkno = 0; cblkno < prec->cw * prec->ch; cblkno++) { + opj_tcd_cblk_t *cblk = &prec->cblks[cblkno]; + fprintf(fd, " cblk {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d\n", + cblk->x0, cblk->y0, cblk->x1, cblk->y1); + fprintf(fd, " }\n"); + } + */ + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +/* ----------------------------------------------------------------------- */ + +/** +Create a new TCD handle +*/ +opj_tcd_t* tcd_create(opj_common_ptr cinfo) { + /* create the tcd structure */ + opj_tcd_t *tcd = (opj_tcd_t*)opj_malloc(sizeof(opj_tcd_t)); + if(!tcd) return NULL; + tcd->cinfo = cinfo; + tcd->tcd_image = (opj_tcd_image_t*)opj_malloc(sizeof(opj_tcd_image_t)); + if(!tcd->tcd_image) { + opj_free(tcd); + return NULL; + } + + return tcd; +} + +/** +Destroy a previously created TCD handle +*/ +void tcd_destroy(opj_tcd_t *tcd) { + if(tcd) { + opj_free(tcd->tcd_image); + opj_free(tcd); + } +} + +/* ----------------------------------------------------------------------- */ + +void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno) { + int tileno, compno, resno, bandno, precno, cblkno; + + tcd->image = image; + tcd->cp = cp; + tcd->tcd_image->tw = cp->tw; + tcd->tcd_image->th = cp->th; + tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(sizeof(opj_tcd_tile_t)); + + for (tileno = 0; tileno < 1; tileno++) { + opj_tcp_t *tcp = &cp->tcps[curtileno]; + int j; + + /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + int p = curtileno % cp->tw; /* si numerotation matricielle .. */ + int q = curtileno / cp->tw; /* .. coordonnees de la tile (q,p) q pour ligne et p pour colonne */ + + /* opj_tcd_tile_t *tile=&tcd->tcd_image->tiles[tileno]; */ + opj_tcd_tile_t *tile = tcd->tcd_image->tiles; + + /* 4 borders of the tile rescale on the image if necessary */ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + tile->numcomps = image->numcomps; + /* tile->PPT=image->PPT; */ + + /* Modification of the RATE >> */ + for (j = 0; j < tcp->numlayers; j++) { + tcp->rates[j] = tcp->rates[j] ? + cp->tp_on ? + (((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec)) + /(tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy)) - (((tcd->cur_totnum_tp - 1) * 14 )/ tcp->numlayers) + : + ((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec))/ + (tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy) + : 0; + + if (tcp->rates[j]) { + if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { + tcp->rates[j] = tcp->rates[j - 1] + 20; + } else { + if (!j && tcp->rates[j] < 30) + tcp->rates[j] = 30; + } + + if(j == (tcp->numlayers-1)){ + tcp->rates[j] = tcp->rates[j]- 2; + } + } + } + /* << Modification of the RATE */ + + tile->comps = (opj_tcd_tilecomp_t *) opj_malloc(image->numcomps * sizeof(opj_tcd_tilecomp_t)); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + /* border of each tile component (global) */ + tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); + + tilec->data = (int *) opj_aligned_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * sizeof(int)); + tilec->numresolutions = tccp->numresolutions; + + tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(tilec->numresolutions * sizeof(opj_tcd_resolution_t)); + + for (resno = 0; resno < tilec->numresolutions; resno++) { + int pdx, pdy; + int levelno = tilec->numresolutions - 1 - resno; + int tlprcxstart, tlprcystart, brprcxend, brprcyend; + int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; + int cbgwidthexpn, cbgheightexpn; + int cblkwidthexpn, cblkheightexpn; + + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + /* border for each resolution level (global) */ + res->x0 = int_ceildivpow2(tilec->x0, levelno); + res->y0 = int_ceildivpow2(tilec->y0, levelno); + res->x1 = int_ceildivpow2(tilec->x1, levelno); + res->y1 = int_ceildivpow2(tilec->y1, levelno); + + res->numbands = resno == 0 ? 1 : 3; + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ + if (tccp->csty & J2K_CCP_CSTY_PRT) { + pdx = tccp->prcw[resno]; + pdy = tccp->prch[resno]; + } else { + pdx = 15; + pdy = 15; + } + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + + res->pw = (brprcxend - tlprcxstart) >> pdx; + res->ph = (brprcyend - tlprcystart) >> pdy; + + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + } + + cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); + cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); + + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b, i; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + opj_tcd_band_t *band = &res->bands[bandno]; + + band->bandno = resno == 0 ? 0 : bandno + 1; + x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; + + if (band->bandno == 0) { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0, levelno); + band->y0 = int_ceildivpow2(tilec->y0, levelno); + band->x1 = int_ceildivpow2(tilec->x1, levelno); + band->y1 = int_ceildivpow2(tilec->y1, levelno); + } else { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); + } + + ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; + gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); + numbps = image->comps[compno].prec + gain; + + band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + band->precincts = (opj_tcd_precinct_t *) opj_malloc(3 * res->pw * res->ph * sizeof(opj_tcd_precinct_t)); + + for (i = 0; i < res->pw * res->ph * 3; i++) { + band->precincts[i].imsbtree = NULL; + band->precincts[i].incltree = NULL; + band->precincts[i].cblks.enc = NULL; + } + + for (precno = 0; precno < res->pw * res->ph; precno++) { + int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + + int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; + + prc->cblks.enc = (opj_tcd_cblk_enc_t*) opj_calloc((prc->cw * prc->ch), sizeof(opj_tcd_cblk_enc_t)); + prc->incltree = tgt_create(prc->cw, prc->ch); + prc->imsbtree = tgt_create(prc->cw, prc->ch); + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char)); + /* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */ + cblk->data += 2; + cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t)); + cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t)); + } + } + } + } + } + } + + /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ +} + +void tcd_free_encode(opj_tcd_t *tcd) { + int tileno, compno, resno, bandno, precno, cblkno; + + for (tileno = 0; tileno < 1; tileno++) { + opj_tcd_tile_t *tile = tcd->tcd_image->tiles; + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if (prc->incltree != NULL) { + tgt_destroy(prc->incltree); + prc->incltree = NULL; + } + if (prc->imsbtree != NULL) { + tgt_destroy(prc->imsbtree); + prc->imsbtree = NULL; + } + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_free(prc->cblks.enc[cblkno].data - 2); + opj_free(prc->cblks.enc[cblkno].layers); + opj_free(prc->cblks.enc[cblkno].passes); + } + opj_free(prc->cblks.enc); + } /* for (precno */ + opj_free(band->precincts); + band->precincts = NULL; + } /* for (bandno */ + } /* for (resno */ + opj_free(tilec->resolutions); + tilec->resolutions = NULL; + } /* for (compno */ + opj_free(tile->comps); + tile->comps = NULL; + } /* for (tileno */ + opj_free(tcd->tcd_image->tiles); + tcd->tcd_image->tiles = NULL; +} + +void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno) { + int tileno, compno, resno, bandno, precno, cblkno; + + for (tileno = 0; tileno < 1; tileno++) { + opj_tcp_t *tcp = &cp->tcps[curtileno]; + int j; + /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + int p = curtileno % cp->tw; + int q = curtileno / cp->tw; + + opj_tcd_tile_t *tile = tcd->tcd_image->tiles; + + /* 4 borders of the tile rescale on the image if necessary */ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + + tile->numcomps = image->numcomps; + /* tile->PPT=image->PPT; */ + + /* Modification of the RATE >> */ + for (j = 0; j < tcp->numlayers; j++) { + tcp->rates[j] = tcp->rates[j] ? + cp->tp_on ? + (((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec)) + /(tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy)) - (((tcd->cur_totnum_tp - 1) * 14 )/ tcp->numlayers) + : + ((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec))/ + (tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy) + : 0; + + if (tcp->rates[j]) { + if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { + tcp->rates[j] = tcp->rates[j - 1] + 20; + } else { + if (!j && tcp->rates[j] < 30) + tcp->rates[j] = 30; + } + } + } + /* << Modification of the RATE */ + + /* tile->comps=(opj_tcd_tilecomp_t*)opj_realloc(tile->comps,image->numcomps*sizeof(opj_tcd_tilecomp_t)); */ + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + /* border of each tile component (global) */ + tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); + + tilec->data = (int *) opj_aligned_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * sizeof(int)); + tilec->numresolutions = tccp->numresolutions; + /* tilec->resolutions=(opj_tcd_resolution_t*)opj_realloc(tilec->resolutions,tilec->numresolutions*sizeof(opj_tcd_resolution_t)); */ + for (resno = 0; resno < tilec->numresolutions; resno++) { + int pdx, pdy; + + int levelno = tilec->numresolutions - 1 - resno; + int tlprcxstart, tlprcystart, brprcxend, brprcyend; + int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; + int cbgwidthexpn, cbgheightexpn; + int cblkwidthexpn, cblkheightexpn; + + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + /* border for each resolution level (global) */ + res->x0 = int_ceildivpow2(tilec->x0, levelno); + res->y0 = int_ceildivpow2(tilec->y0, levelno); + res->x1 = int_ceildivpow2(tilec->x1, levelno); + res->y1 = int_ceildivpow2(tilec->y1, levelno); + res->numbands = resno == 0 ? 1 : 3; + + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ + if (tccp->csty & J2K_CCP_CSTY_PRT) { + pdx = tccp->prcw[resno]; + pdy = tccp->prch[resno]; + } else { + pdx = 15; + pdy = 15; + } + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + + res->pw = (brprcxend - tlprcxstart) >> pdx; + res->ph = (brprcyend - tlprcystart) >> pdy; + + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + } + + cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); + cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); + + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + opj_tcd_band_t *band = &res->bands[bandno]; + + band->bandno = resno == 0 ? 0 : bandno + 1; + x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; + + if (band->bandno == 0) { + /* band border */ + band->x0 = int_ceildivpow2(tilec->x0, levelno); + band->y0 = int_ceildivpow2(tilec->y0, levelno); + band->x1 = int_ceildivpow2(tilec->x1, levelno); + band->y1 = int_ceildivpow2(tilec->y1, levelno); + } else { + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); + } + + ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; + gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); + numbps = image->comps[compno].prec + gain; + band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + for (precno = 0; precno < res->pw * res->ph; precno++) { + int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + + int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; + + opj_free(prc->cblks.enc); + prc->cblks.enc = (opj_tcd_cblk_enc_t*) opj_calloc(prc->cw * prc->ch, sizeof(opj_tcd_cblk_enc_t)); + + if (prc->incltree != NULL) { + tgt_destroy(prc->incltree); + } + if (prc->imsbtree != NULL) { + tgt_destroy(prc->imsbtree); + } + + prc->incltree = tgt_create(prc->cw, prc->ch); + prc->imsbtree = tgt_create(prc->cw, prc->ch); + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char)); + /* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */ + cblk->data += 2; + cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t)); + cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t)); + } + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + } /* tileno */ + + /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ +} + +void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp) { + int i, j, tileno, p, q; + unsigned int x0 = 0, y0 = 0, x1 = 0, y1 = 0, w, h; + + tcd->image = image; + tcd->tcd_image->tw = cp->tw; + tcd->tcd_image->th = cp->th; + tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tcd_tile_t)); + + /* + Allocate place to store the decoded data = final image + Place limited by the tile really present in the codestream + */ + + for (j = 0; j < cp->tileno_size; j++) { + opj_tcd_tile_t *tile; + + tileno = cp->tileno[j]; + tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); + tile->numcomps = image->numcomps; + tile->comps = (opj_tcd_tilecomp_t*) opj_calloc(image->numcomps, sizeof(opj_tcd_tilecomp_t)); + } + + for (i = 0; i < image->numcomps; i++) { + for (j = 0; j < cp->tileno_size; j++) { + opj_tcd_tile_t *tile; + opj_tcd_tilecomp_t *tilec; + + /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + + tileno = cp->tileno[j]; + + tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); + tilec = &tile->comps[i]; + + p = tileno % cp->tw; /* si numerotation matricielle .. */ + q = tileno / cp->tw; /* .. coordonnees de la tile (q,p) q pour ligne et p pour colonne */ + + /* 4 borders of the tile rescale on the image if necessary */ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + + tilec->x0 = int_ceildiv(tile->x0, image->comps[i].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[i].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[i].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[i].dy); + + x0 = j == 0 ? tilec->x0 : int_min(x0, (unsigned int) tilec->x0); + y0 = j == 0 ? tilec->y0 : int_min(y0, (unsigned int) tilec->y0); + x1 = j == 0 ? tilec->x1 : int_max(x1, (unsigned int) tilec->x1); + y1 = j == 0 ? tilec->y1 : int_max(y1, (unsigned int) tilec->y1); + } + + w = int_ceildivpow2(x1 - x0, image->comps[i].factor); + h = int_ceildivpow2(y1 - y0, image->comps[i].factor); + + image->comps[i].w = w; + image->comps[i].h = h; + image->comps[i].x0 = x0; + image->comps[i].y0 = y0; + } +} + +void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int tileno, opj_codestream_info_t *cstr_info) { + int compno, resno, bandno, precno, cblkno; + opj_tcp_t *tcp; + opj_tcd_tile_t *tile; + + OPJ_ARG_NOT_USED(cstr_info); + + tcd->cp = cp; + + tcp = &(cp->tcps[cp->tileno[tileno]]); + tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); + + tileno = cp->tileno[tileno]; + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + /* border of each tile component (global) */ + tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); + + tilec->numresolutions = tccp->numresolutions; + tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(tilec->numresolutions * sizeof(opj_tcd_resolution_t)); + + for (resno = 0; resno < tilec->numresolutions; resno++) { + int pdx, pdy; + int levelno = tilec->numresolutions - 1 - resno; + int tlprcxstart, tlprcystart, brprcxend, brprcyend; + int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; + int cbgwidthexpn, cbgheightexpn; + int cblkwidthexpn, cblkheightexpn; + + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + /* border for each resolution level (global) */ + res->x0 = int_ceildivpow2(tilec->x0, levelno); + res->y0 = int_ceildivpow2(tilec->y0, levelno); + res->x1 = int_ceildivpow2(tilec->x1, levelno); + res->y1 = int_ceildivpow2(tilec->y1, levelno); + res->numbands = resno == 0 ? 1 : 3; + + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ + if (tccp->csty & J2K_CCP_CSTY_PRT) { + pdx = tccp->prcw[resno]; + pdy = tccp->prch[resno]; + } else { + pdx = 15; + pdy = 15; + } + + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + + res->pw = (res->x0 == res->x1) ? 0 : ((brprcxend - tlprcxstart) >> pdx); + res->ph = (res->y0 == res->y1) ? 0 : ((brprcyend - tlprcystart) >> pdy); + + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + } + + cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); + cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); + + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + opj_tcd_band_t *band = &res->bands[bandno]; + band->bandno = resno == 0 ? 0 : bandno + 1; + x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; + + if (band->bandno == 0) { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0, levelno); + band->y0 = int_ceildivpow2(tilec->y0, levelno); + band->x1 = int_ceildivpow2(tilec->x1, levelno); + band->y1 = int_ceildivpow2(tilec->y1, levelno); + } else { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); + } + + ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; + gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); + numbps = image->comps[compno].prec + gain; + band->stepsize = (float)(((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)) * 0.5); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + band->precincts = (opj_tcd_precinct_t *) opj_malloc(res->pw * res->ph * sizeof(opj_tcd_precinct_t)); + + for (precno = 0; precno < res->pw * res->ph; precno++) { + int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + + opj_tcd_precinct_t *prc = &band->precincts[precno]; + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; + + prc->cblks.dec = (opj_tcd_cblk_dec_t*) opj_malloc(prc->cw * prc->ch * sizeof(opj_tcd_cblk_dec_t)); + + prc->incltree = tgt_create(prc->cw, prc->ch); + prc->imsbtree = tgt_create(prc->cw, prc->ch); + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + cblk->data = NULL; + cblk->segs = NULL; + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->numsegs = 0; + } + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ +} + +void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final) { + int compno, resno, bandno, precno, cblkno; + int value; /*, matrice[tcd_tcp->numlayers][tcd_tile->comps[0].numresolutions][3]; */ + int matrice[10][10][3]; + int i, j, k; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcp_t *tcd_tcp = tcd->tcp; + + /*matrice=(int*)opj_malloc(tcd_tcp->numlayers*tcd_tile->comps[0].numresolutions*3*sizeof(int)); */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (i = 0; i < tcd_tcp->numlayers; i++) { + for (j = 0; j < tilec->numresolutions; j++) { + for (k = 0; k < 3; k++) { + matrice[i][j][k] = + (int) (cp->matrice[i * tilec->numresolutions * 3 + j * 3 + k] + * (float) (tcd->image->comps[compno].prec / 16.0)); + } + } + } + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + int n; + int imsb = tcd->image->comps[compno].prec - cblk->numbps; /* number of bit-plan equal to zero */ + /* Correction of the matrix of coefficient to include the IMSB information */ + if (layno == 0) { + value = matrice[layno][resno][bandno]; + if (imsb >= value) { + value = 0; + } else { + value -= imsb; + } + } else { + value = matrice[layno][resno][bandno] - matrice[layno - 1][resno][bandno]; + if (imsb >= matrice[layno - 1][resno][bandno]) { + value -= (imsb - matrice[layno - 1][resno][bandno]); + if (value < 0) { + value = 0; + } + } + } + + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + + n = cblk->numpassesinlayers; + if (cblk->numpassesinlayers == 0) { + if (value != 0) { + n = 3 * value - 2 + cblk->numpassesinlayers; + } else { + n = cblk->numpassesinlayers; + } + } else { + n = 3 * value + cblk->numpassesinlayers; + } + + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) + continue; + + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + } + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +void tcd_rateallocate_fixed(opj_tcd_t *tcd) { + int layno; + for (layno = 0; layno < tcd->tcp->numlayers; layno++) { + tcd_makelayer_fixed(tcd, layno, 1); + } +} + +void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { + int compno, resno, bandno, precno, cblkno, passno; + + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + + tcd_tile->distolayer[layno] = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + + int n; + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + n = cblk->numpassesinlayers; + for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { + int dr; + double dd; + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (n == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = pass->distortiondec - cblk->passes[n - 1].distortiondec; + } + if (!dr) { + if (dd != 0) + n = passno + 1; + continue; + } + if (dd / dr >= thresh) + n = passno + 1; + } + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) { + layer->disto = 0; + continue; + } + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + layer->disto = cblk->passes[n - 1].distortiondec; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->disto = cblk->passes[n - 1].distortiondec - cblk->passes[cblk->numpassesinlayers - 1].distortiondec; + } + + tcd_tile->distolayer[layno] += layer->disto; /* fixed_quality */ + + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +opj_bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) { + int compno, resno, bandno, precno, cblkno, passno, layno; + double min, max; + double cumdisto[100]; /* fixed_quality */ + const double K = 1; /* 1.1; fixed_quality */ + double maxSE = 0; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcp_t *tcd_tcp = tcd->tcp; + + min = DBL_MAX; + max = 0; + + tcd_tile->numpix = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + tilec->numpix = 0; + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + + for (passno = 0; passno < cblk->totalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + int dr; + double dd, rdslope; + if (passno == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[passno - 1].rate; + dd = pass->distortiondec - cblk->passes[passno - 1].distortiondec; + } + if (dr == 0) { + continue; + } + rdslope = dd / dr; + if (rdslope < min) { + min = rdslope; + } + if (rdslope > max) { + max = rdslope; + } + } /* passno */ + + /* fixed_quality */ + tcd_tile->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + tilec->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + } /* cbklno */ + } /* precno */ + } /* bandno */ + } /* resno */ + + maxSE += (((double)(1 << tcd->image->comps[compno].prec) - 1.0) + * ((double)(1 << tcd->image->comps[compno].prec) -1.0)) + * ((double)(tilec->numpix)); + } /* compno */ + + /* index file */ + if(cstr_info) { + opj_tile_info_t *tile_info = &cstr_info->tile[tcd->tcd_tileno]; + tile_info->numpix = tcd_tile->numpix; + tile_info->distotile = tcd_tile->distotile; + tile_info->thresh = (double *) opj_malloc(tcd_tcp->numlayers * sizeof(double)); + } + + for (layno = 0; layno < tcd_tcp->numlayers; layno++) { + double lo = min; + double hi = max; + int success = 0; + int maxlen = tcd_tcp->rates[layno] ? int_min(((int) ceil(tcd_tcp->rates[layno])), len) : len; + double goodthresh = 0; + double stable_thresh = 0; + int i; + double distotarget; /* fixed_quality */ + + /* fixed_quality */ + distotarget = tcd_tile->distotile - ((K * maxSE) / pow((float)10, tcd_tcp->distoratio[layno] / 10)); + + /* Don't try to find an optimal threshold but rather take everything not included yet, if + -r xx,yy,zz,0 (disto_alloc == 1 and rates == 0) + -q xx,yy,zz,0 (fixed_quality == 1 and distoratio == 0) + ==> possible to have some lossy layers and the last layer for sure lossless */ + if ( ((cp->disto_alloc==1) && (tcd_tcp->rates[layno]>0)) || ((cp->fixed_quality==1) && (tcd_tcp->distoratio[layno]>0))) { + opj_t2_t *t2 = t2_create(tcd->cinfo, tcd->image, cp); + double thresh = 0; + + for (i = 0; i < 128; i++) { + int l = 0; + double distoachieved = 0; /* fixed_quality */ + thresh = (lo + hi) / 2; + + tcd_makelayer(tcd, layno, thresh, 0); + + if (cp->fixed_quality) { /* fixed_quality */ + if(cp->cinema){ + l = t2_encode_packets(t2,tcd->tcd_tileno, tcd_tile, layno + 1, dest, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC, tcd->cur_totnum_tp); + if (l == -999) { + lo = thresh; + continue; + }else{ + distoachieved = layno == 0 ? + tcd_tile->distolayer[0] : cumdisto[layno - 1] + tcd_tile->distolayer[layno]; + if (distoachieved < distotarget) { + hi=thresh; + stable_thresh = thresh; + continue; + }else{ + lo=thresh; + } + } + }else{ + distoachieved = (layno == 0) ? + tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + if (distoachieved < distotarget) { + hi = thresh; + stable_thresh = thresh; + continue; + } + lo = thresh; + } + } else { + l = t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC, tcd->cur_totnum_tp); + /* TODO: what to do with l ??? seek / tell ??? */ + /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ + if (l == -999) { + lo = thresh; + continue; + } + hi = thresh; + stable_thresh = thresh; + } + } + success = 1; + goodthresh = stable_thresh == 0? thresh : stable_thresh; + t2_destroy(t2); + } else { + success = 1; + goodthresh = min; + } + + if (!success) { + return OPJ_FALSE; + } + + if(cstr_info) { /* Threshold for Marcela Index */ + cstr_info->tile[tcd->tcd_tileno].thresh[layno] = goodthresh; + } + tcd_makelayer(tcd, layno, goodthresh, 1); + + /* fixed_quality */ + cumdisto[layno] = (layno == 0) ? tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + } + + return OPJ_TRUE; +} + +int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) { + int compno; + int l, i, numpacks = 0; + opj_tcd_tile_t *tile = NULL; + opj_tcp_t *tcd_tcp = NULL; + opj_cp_t *cp = NULL; + + opj_tcp_t *tcp = &tcd->cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[0]; + opj_image_t *image = tcd->image; + + opj_t1_t *t1 = NULL; /* T1 component */ + opj_t2_t *t2 = NULL; /* T2 component */ + + tcd->tcd_tileno = tileno; + tcd->tcd_tile = tcd->tcd_image->tiles; + tcd->tcp = &tcd->cp->tcps[tileno]; + + tile = tcd->tcd_tile; + tcd_tcp = tcd->tcp; + cp = tcd->cp; + + if(tcd->cur_tp_num == 0){ + tcd->encoding_time = opj_clock(); /* time needed to encode a tile */ + /* INDEX >> "Precinct_nb_X et Precinct_nb_Y" */ + if(cstr_info) { + opj_tcd_tilecomp_t *tilec_idx = &tile->comps[0]; /* based on component 0 */ + for (i = 0; i < tilec_idx->numresolutions; i++) { + opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[i]; + + cstr_info->tile[tileno].pw[i] = res_idx->pw; + cstr_info->tile[tileno].ph[i] = res_idx->ph; + + numpacks += res_idx->pw * res_idx->ph; + + cstr_info->tile[tileno].pdx[i] = tccp->prcw[i]; + cstr_info->tile[tileno].pdy[i] = tccp->prch[i]; + } + cstr_info->tile[tileno].packet = (opj_packet_info_t*) opj_calloc(cstr_info->numcomps * cstr_info->numlayers * numpacks, sizeof(opj_packet_info_t)); + } + /* << INDEX */ + + /*---------------TILE-------------------*/ + + for (compno = 0; compno < tile->numcomps; compno++) { + int x, y; + + int adjust = image->comps[compno].sgnd ? 0 : 1 << (image->comps[compno].prec - 1); + int offset_x = int_ceildiv(image->x0, image->comps[compno].dx); + int offset_y = int_ceildiv(image->y0, image->comps[compno].dy); + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + int tw = tilec->x1 - tilec->x0; + int w = int_ceildiv(image->x1 - image->x0, image->comps[compno].dx); + + /* extract tile data */ + + if (tcd_tcp->tccps[compno].qmfbid == 1) { + for (y = tilec->y0; y < tilec->y1; y++) { + /* start of the src tile scanline */ + int *data = &image->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w]; + /* start of the dst tile scanline */ + int *tile_data = &tilec->data[(y - tilec->y0) * tw]; + for (x = tilec->x0; x < tilec->x1; x++) { + *tile_data++ = *data++ - adjust; + } + } + } else if (tcd_tcp->tccps[compno].qmfbid == 0) { + for (y = tilec->y0; y < tilec->y1; y++) { + /* start of the src tile scanline */ + int *data = &image->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w]; + /* start of the dst tile scanline */ + int *tile_data = &tilec->data[(y - tilec->y0) * tw]; + for (x = tilec->x0; x < tilec->x1; x++) { + *tile_data++ = (*data++ - adjust) << 11; + } + + } + } + } + + /*----------------MCT-------------------*/ + if (tcd_tcp->mct) { + int samples = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0); + if (tcd_tcp->tccps[0].qmfbid == 0) { + mct_encode_real(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); + } else { + mct_encode(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); + } + } + + /*----------------DWT---------------------*/ + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + if (tcd_tcp->tccps[compno].qmfbid == 1) { + dwt_encode(tilec); + } else if (tcd_tcp->tccps[compno].qmfbid == 0) { + dwt_encode_real(tilec); + } + } + + /*------------------TIER1-----------------*/ + t1 = t1_create(tcd->cinfo); + t1_encode_cblks(t1, tile, tcd_tcp); + t1_destroy(t1); + + /*-----------RATE-ALLOCATE------------------*/ + + /* INDEX */ + if(cstr_info) { + cstr_info->index_write = 0; + } + if (cp->disto_alloc || cp->fixed_quality) { /* fixed_quality */ + /* Normal Rate/distortion allocation */ + tcd_rateallocate(tcd, dest, len, cstr_info); + } else { + /* Fixed layer allocation */ + tcd_rateallocate_fixed(tcd); + } + } + /*--------------TIER2------------------*/ + + /* INDEX */ + if(cstr_info) { + cstr_info->index_write = 1; + } + + t2 = t2_create(tcd->cinfo, image, cp); + l = t2_encode_packets(t2,tileno, tile, tcd_tcp->numlayers, dest, len, cstr_info,tcd->tp_num,tcd->tp_pos,tcd->cur_pino,FINAL_PASS,tcd->cur_totnum_tp); + t2_destroy(t2); + + /*---------------CLEAN-------------------*/ + + + if(tcd->cur_tp_num == tcd->cur_totnum_tp - 1){ + tcd->encoding_time = opj_clock() - tcd->encoding_time; + opj_event_msg(tcd->cinfo, EVT_INFO, "- tile encoded in %f s\n", tcd->encoding_time); + + /* cleaning memory */ + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_aligned_free(tilec->data); + } + } + + return l; +} + +opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info) { + int l; + int compno; + int eof = 0; + double tile_time, t1_time, dwt_time; + opj_tcd_tile_t *tile = NULL; + + opj_t1_t *t1 = NULL; /* T1 component */ + opj_t2_t *t2 = NULL; /* T2 component */ + + tcd->tcd_tileno = tileno; + tcd->tcd_tile = &(tcd->tcd_image->tiles[tileno]); + tcd->tcp = &(tcd->cp->tcps[tileno]); + tile = tcd->tcd_tile; + + tile_time = opj_clock(); /* time needed to decode a tile */ + opj_event_msg(tcd->cinfo, EVT_INFO, "tile %d of %d\n", tileno + 1, tcd->cp->tw * tcd->cp->th); + + /* INDEX >> */ + if(cstr_info) { + int resno, compno, numprec = 0; + for (compno = 0; compno < cstr_info->numcomps; compno++) { + opj_tcp_t *tcp = &tcd->cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_tcd_tilecomp_t *tilec_idx = &tile->comps[compno]; + for (resno = 0; resno < tilec_idx->numresolutions; resno++) { + opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[resno]; + cstr_info->tile[tileno].pw[resno] = res_idx->pw; + cstr_info->tile[tileno].ph[resno] = res_idx->ph; + numprec += res_idx->pw * res_idx->ph; + if (tccp->csty & J2K_CP_CSTY_PRT) { + cstr_info->tile[tileno].pdx[resno] = tccp->prcw[resno]; + cstr_info->tile[tileno].pdy[resno] = tccp->prch[resno]; + } + else { + cstr_info->tile[tileno].pdx[resno] = 15; + cstr_info->tile[tileno].pdy[resno] = 15; + } + } + } + cstr_info->tile[tileno].packet = (opj_packet_info_t *) opj_malloc(cstr_info->numlayers * numprec * sizeof(opj_packet_info_t)); + cstr_info->packno = 0; + } + /* << INDEX */ + + /*--------------TIER2------------------*/ + + t2 = t2_create(tcd->cinfo, tcd->image, tcd->cp); + l = t2_decode_packets(t2, src, len, tileno, tile, cstr_info); + t2_destroy(t2); + + if (l == -999) { + eof = 1; + opj_event_msg(tcd->cinfo, EVT_ERROR, "tcd_decode: incomplete bistream\n"); + } + + /*------------------TIER1-----------------*/ + + t1_time = opj_clock(); /* time needed to decode a tile */ + t1 = t1_create(tcd->cinfo); + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + /* The +3 is headroom required by the vectorized DWT */ + tilec->data = (int*) opj_aligned_malloc((((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0))+3) * sizeof(int)); + t1_decode_cblks(t1, tilec, &tcd->tcp->tccps[compno]); + } + t1_destroy(t1); + t1_time = opj_clock() - t1_time; + opj_event_msg(tcd->cinfo, EVT_INFO, "- tiers-1 took %f s\n", t1_time); + + /*----------------DWT---------------------*/ + + dwt_time = opj_clock(); /* time needed to decode a tile */ + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + int numres2decode; + + if (tcd->cp->reduce != 0) { + tcd->image->comps[compno].resno_decoded = + tile->comps[compno].numresolutions - tcd->cp->reduce - 1; + if (tcd->image->comps[compno].resno_decoded < 0) { + opj_event_msg(tcd->cinfo, EVT_ERROR, "Error decoding tile. The number of resolutions to remove [%d+1] is higher than the number " + " of resolutions in the original codestream [%d]\nModify the cp_reduce parameter.\n", tcd->cp->reduce, tile->comps[compno].numresolutions); + return OPJ_FALSE; + } + } + + numres2decode = tcd->image->comps[compno].resno_decoded + 1; + if(numres2decode > 0){ + if (tcd->tcp->tccps[compno].qmfbid == 1) { + dwt_decode(tilec, numres2decode); + } else { + dwt_decode_real(tilec, numres2decode); + } + } + } + dwt_time = opj_clock() - dwt_time; + opj_event_msg(tcd->cinfo, EVT_INFO, "- dwt took %f s\n", dwt_time); + + /*----------------MCT-------------------*/ + + if (tcd->tcp->mct) { + int n = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0); + + if (tile->numcomps >= 3 ){ + if (tcd->tcp->tccps[0].qmfbid == 1) { + mct_decode( + tile->comps[0].data, + tile->comps[1].data, + tile->comps[2].data, + n); + } else { + mct_decode_real( + (float*)tile->comps[0].data, + (float*)tile->comps[1].data, + (float*)tile->comps[2].data, + n); + } + } else{ + opj_event_msg(tcd->cinfo, EVT_WARNING,"Number of components (%d) is inconsistent with a MCT. Skip the MCT step.\n",tile->numcomps); + } + } + + /*---------------TILE-------------------*/ + + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + opj_image_comp_t* imagec = &tcd->image->comps[compno]; + opj_tcd_resolution_t* res = &tilec->resolutions[imagec->resno_decoded]; + int adjust = imagec->sgnd ? 0 : 1 << (imagec->prec - 1); + int min = imagec->sgnd ? -(1 << (imagec->prec - 1)) : 0; + int max = imagec->sgnd ? (1 << (imagec->prec - 1)) - 1 : (1 << imagec->prec) - 1; + + int tw = tilec->x1 - tilec->x0; + int w = imagec->w; + + int offset_x = int_ceildivpow2(imagec->x0, imagec->factor); + int offset_y = int_ceildivpow2(imagec->y0, imagec->factor); + + int i, j; + if(!imagec->data){ + imagec->data = (int*) opj_malloc(imagec->w * imagec->h * sizeof(int)); + } + if(tcd->tcp->tccps[compno].qmfbid == 1) { + for(j = res->y0; j < res->y1; ++j) { + for(i = res->x0; i < res->x1; ++i) { + int v = tilec->data[i - res->x0 + (j - res->y0) * tw]; + v += adjust; + imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max); + } + } + }else{ + for(j = res->y0; j < res->y1; ++j) { + for(i = res->x0; i < res->x1; ++i) { + float tmp = ((float*)tilec->data)[i - res->x0 + (j - res->y0) * tw]; + int v = lrintf(tmp); + v += adjust; + imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max); + } + } + } + opj_aligned_free(tilec->data); + } + + tile_time = opj_clock() - tile_time; /* time needed to decode a tile */ + opj_event_msg(tcd->cinfo, EVT_INFO, "- tile decoded in %f s\n", tile_time); + + if (eof) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +void tcd_free_decode(opj_tcd_t *tcd) { + opj_tcd_image_t *tcd_image = tcd->tcd_image; + opj_free(tcd_image->tiles); +} + +void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno) { + int compno,resno,bandno,precno; + + opj_tcd_image_t *tcd_image = tcd->tcd_image; + + opj_tcd_tile_t *tile = &tcd_image->tiles[tileno]; + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->ph * res->pw; precno++) { + opj_tcd_precinct_t *prec = &band->precincts[precno]; + if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree); + if (prec->incltree != NULL) tgt_destroy(prec->incltree); + } + opj_free(band->precincts); + } + } + opj_free(tilec->resolutions); + } + opj_free(tile->comps); +} + + + diff --git a/openjpeg-dotnet/libopenjpeg/tcd.h b/openjpeg-dotnet/libopenjpeg/tcd.h new file mode 100644 index 0000000..e3f93ad --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/tcd.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ +#ifndef __TCD_H +#define __TCD_H +/** +@file tcd.h +@brief Implementation of a tile coder/decoder (TCD) + +The functions in TCD.C have for goal to encode or decode each tile independently from +each other. The functions in TCD.C are used by some function in J2K.C. +*/ + +/** @defgroup TCD TCD - Implementation of a tile coder/decoder */ +/*@{*/ + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_seg { + unsigned char** data; + int dataindex; + int numpasses; + int len; + int maxpasses; + int numnewpasses; + int newlen; +} opj_tcd_seg_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_pass { + int rate; + double distortiondec; + int term, len; +} opj_tcd_pass_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_layer { + int numpasses; /* Number of passes in the layer */ + int len; /* len of information */ + double disto; /* add for index (Cfr. Marcela) */ + unsigned char *data; /* data */ +} opj_tcd_layer_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_cblk_enc { + unsigned char* data; /* Data */ + opj_tcd_layer_t* layers; /* layer information */ + opj_tcd_pass_t* passes; /* information about the passes */ + int x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + int numbps; + int numlenbits; + int numpasses; /* number of pass already done for the code-blocks */ + int numpassesinlayers; /* number of passes in the layer */ + int totalpasses; /* total number of passes */ +} opj_tcd_cblk_enc_t; + +typedef struct opj_tcd_cblk_dec { + unsigned char* data; /* Data */ + opj_tcd_seg_t* segs; /* segments informations */ + int x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + int numbps; + int numlenbits; + int len; /* length */ + int numnewpasses; /* number of pass added to the code-blocks */ + int numsegs; /* number of segments */ +} opj_tcd_cblk_dec_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_precinct { + int x0, y0, x1, y1; /* dimension of the precinct : left upper corner (x0, y0) right low corner (x1,y1) */ + int cw, ch; /* number of precinct in width and heigth */ + union{ /* code-blocks informations */ + opj_tcd_cblk_enc_t* enc; + opj_tcd_cblk_dec_t* dec; + } cblks; + opj_tgt_tree_t *incltree; /* inclusion tree */ + opj_tgt_tree_t *imsbtree; /* IMSB tree */ +} opj_tcd_precinct_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_band { + int x0, y0, x1, y1; /* dimension of the subband : left upper corner (x0, y0) right low corner (x1,y1) */ + int bandno; + opj_tcd_precinct_t *precincts; /* precinct information */ + int numbps; + float stepsize; +} opj_tcd_band_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_resolution { + int x0, y0, x1, y1; /* dimension of the resolution level : left upper corner (x0, y0) right low corner (x1,y1) */ + int pw, ph; + int numbands; /* number sub-band for the resolution level */ + opj_tcd_band_t bands[3]; /* subband information */ +} opj_tcd_resolution_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_tilecomp { + int x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ + int numresolutions; /* number of resolutions level */ + opj_tcd_resolution_t *resolutions; /* resolutions information */ + int *data; /* data of the component */ + int numpix; /* add fixed_quality */ +} opj_tcd_tilecomp_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_tile { + int x0, y0, x1, y1; /* dimension of the tile : left upper corner (x0, y0) right low corner (x1,y1) */ + int numcomps; /* number of components in tile */ + opj_tcd_tilecomp_t *comps; /* Components information */ + int numpix; /* add fixed_quality */ + double distotile; /* add fixed_quality */ + double distolayer[100]; /* add fixed_quality */ + /** packet number */ + int packno; +} opj_tcd_tile_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_image { + int tw, th; /* number of tiles in width and heigth */ + opj_tcd_tile_t *tiles; /* Tiles information */ +} opj_tcd_image_t; + +/** +Tile coder/decoder +*/ +typedef struct opj_tcd { + /** Position of the tilepart flag in Progression order*/ + int tp_pos; + /** Tile part number*/ + int tp_num; + /** Current tile part number*/ + int cur_tp_num; + /** Total number of tileparts of the current tile*/ + int cur_totnum_tp; + /** Current Packet iterator number */ + int cur_pino; + /** codec context */ + opj_common_ptr cinfo; + + /** info on each image tile */ + opj_tcd_image_t *tcd_image; + /** image */ + opj_image_t *image; + /** coding parameters */ + opj_cp_t *cp; + /** pointer to the current encoded/decoded tile */ + opj_tcd_tile_t *tcd_tile; + /** coding/decoding parameters common to all tiles */ + opj_tcp_t *tcp; + /** current encoded/decoded tile */ + int tcd_tileno; + /** Time taken to encode a tile*/ + double encoding_time; +} opj_tcd_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Dump the content of a tcd structure +*/ +void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t *img); +/** +Create a new TCD handle +@param cinfo Codec context info +@return Returns a new TCD handle if successful returns NULL otherwise +*/ +opj_tcd_t* tcd_create(opj_common_ptr cinfo); +/** +Destroy a previously created TCD handle +@param tcd TCD handle to destroy +*/ +void tcd_destroy(opj_tcd_t *tcd); +/** +Initialize the tile coder (allocate the memory) +@param tcd TCD handle +@param image Raw image +@param cp Coding parameters +@param curtileno Number that identifies the tile that will be encoded +*/ +void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno); +/** +Free the memory allocated for encoding +@param tcd TCD handle +*/ +void tcd_free_encode(opj_tcd_t *tcd); +/** +Initialize the tile coder (reuses the memory allocated by tcd_malloc_encode) +@param tcd TCD handle +@param image Raw image +@param cp Coding parameters +@param curtileno Number that identifies the tile that will be encoded +*/ +void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno); +/** +Initialize the tile decoder +@param tcd TCD handle +@param image Raw image +@param cp Coding parameters +*/ +void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp); +void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int tileno, opj_codestream_info_t *cstr_info); +void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final); +void tcd_rateallocate_fixed(opj_tcd_t *tcd); +void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final); +opj_bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info); +/** +Encode a tile from the raw image into a buffer +@param tcd TCD handle +@param tileno Number that identifies one of the tiles to be encoded +@param dest Destination buffer +@param len Length of destination buffer +@param cstr_info Codestream information structure +@return +*/ +int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_codestream_info_t *cstr_info); +/** +Decode a tile from a buffer into a raw image +@param tcd TCD handle +@param src Source buffer +@param len Length of source buffer +@param tileno Number that identifies one of the tiles to be decoded +@param cstr_info Codestream information structure +*/ +opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info); +/** +Free the memory allocated for decoding +@param tcd TCD handle +*/ +void tcd_free_decode(opj_tcd_t *tcd); +void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __TCD_H */ diff --git a/openjpeg-dotnet/libopenjpeg/tgt.c b/openjpeg-dotnet/libopenjpeg/tgt.c new file mode 100644 index 0000000..a5dbcd3 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/tgt.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "opj_includes.h" + +/* +========================================================== + Tag-tree coder interface +========================================================== +*/ + +opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv) { + int nplh[32]; + int nplv[32]; + opj_tgt_node_t *node = NULL; + opj_tgt_node_t *parentnode = NULL; + opj_tgt_node_t *parentnode0 = NULL; + opj_tgt_tree_t *tree = NULL; + int i, j, k; + int numlvls; + int n; + + tree = (opj_tgt_tree_t *) opj_malloc(sizeof(opj_tgt_tree_t)); + if(!tree) return NULL; + tree->numleafsh = numleafsh; + tree->numleafsv = numleafsv; + + numlvls = 0; + nplh[0] = numleafsh; + nplv[0] = numleafsv; + tree->numnodes = 0; + do { + n = nplh[numlvls] * nplv[numlvls]; + nplh[numlvls + 1] = (nplh[numlvls] + 1) / 2; + nplv[numlvls + 1] = (nplv[numlvls] + 1) / 2; + tree->numnodes += n; + ++numlvls; + } while (n > 1); + + /* ADD */ + if (tree->numnodes == 0) { + opj_free(tree); + return NULL; + } + + tree->nodes = (opj_tgt_node_t*) opj_calloc(tree->numnodes, sizeof(opj_tgt_node_t)); + if(!tree->nodes) { + opj_free(tree); + return NULL; + } + + node = tree->nodes; + parentnode = &tree->nodes[tree->numleafsh * tree->numleafsv]; + parentnode0 = parentnode; + + for (i = 0; i < numlvls - 1; ++i) { + for (j = 0; j < nplv[i]; ++j) { + k = nplh[i]; + while (--k >= 0) { + node->parent = parentnode; + ++node; + if (--k >= 0) { + node->parent = parentnode; + ++node; + } + ++parentnode; + } + if ((j & 1) || j == nplv[i] - 1) { + parentnode0 = parentnode; + } else { + parentnode = parentnode0; + parentnode0 += nplh[i]; + } + } + } + node->parent = 0; + + tgt_reset(tree); + + return tree; +} + +void tgt_destroy(opj_tgt_tree_t *tree) { + opj_free(tree->nodes); + opj_free(tree); +} + +void tgt_reset(opj_tgt_tree_t *tree) { + int i; + + if (NULL == tree) + return; + + for (i = 0; i < tree->numnodes; i++) { + tree->nodes[i].value = 999; + tree->nodes[i].low = 0; + tree->nodes[i].known = 0; + } +} + +void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value) { + opj_tgt_node_t *node; + node = &tree->nodes[leafno]; + while (node && node->value > value) { + node->value = value; + node = node->parent; + } +} + +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + int low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + + while (low < threshold) { + if (low >= node->value) { + if (!node->known) { + bio_write(bio, 1, 1); + node->known = 1; + } + break; + } + bio_write(bio, 0, 1); + ++low; + } + + node->low = low; + if (stkptr == stk) + break; + node = *--stkptr; + } +} + +int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + int low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + while (low < threshold && low < node->value) { + if (bio_read(bio, 1)) { + node->value = low; + } else { + ++low; + } + } + node->low = low; + if (stkptr == stk) { + break; + } + node = *--stkptr; + } + + return (node->value < threshold) ? 1 : 0; +} diff --git a/openjpeg-dotnet/libopenjpeg/tgt.h b/openjpeg-dotnet/libopenjpeg/tgt.h new file mode 100644 index 0000000..c08c8da --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/tgt.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef __TGT_H +#define __TGT_H +/** +@file tgt.h +@brief Implementation of a tag-tree coder (TGT) + +The functions in TGT.C have for goal to realize a tag-tree coder. The functions in TGT.C +are used by some function in T2.C. +*/ + +/** @defgroup TGT TGT - Implementation of a tag-tree coder */ +/*@{*/ + +/** +Tag node +*/ +typedef struct opj_tgt_node { + struct opj_tgt_node *parent; + int value; + int low; + int known; +} opj_tgt_node_t; + +/** +Tag tree +*/ +typedef struct opj_tgt_tree { + int numleafsh; + int numleafsv; + int numnodes; + opj_tgt_node_t *nodes; +} opj_tgt_tree_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a tag-tree +@param numleafsh Width of the array of leafs of the tree +@param numleafsv Height of the array of leafs of the tree +@return Returns a new tag-tree if successful, returns NULL otherwise +*/ +opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv); +/** +Destroy a tag-tree, liberating memory +@param tree Tag-tree to destroy +*/ +void tgt_destroy(opj_tgt_tree_t *tree); +/** +Reset a tag-tree (set all leaves to 0) +@param tree Tag-tree to reset +*/ +void tgt_reset(opj_tgt_tree_t *tree); +/** +Set the value of a leaf of a tag-tree +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to modify +@param value New value of the leaf +*/ +void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value); +/** +Encode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to encode +@param threshold Threshold to use when encoding value of the leaf +*/ +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); +/** +Decode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to decode +@param leafno Number that identifies the leaf to decode +@param threshold Threshold to use when decoding value of the leaf +@return Returns 1 if the node's value < threshold, returns 0 otherwise +*/ +int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __TGT_H */ diff --git a/openjpeg-dotnet/libopenjpeg/thix_manager.c b/openjpeg-dotnet/libopenjpeg/thix_manager.c new file mode 100644 index 0000000..aa55f21 --- /dev/null +++ b/openjpeg-dotnet/libopenjpeg/thix_manager.c @@ -0,0 +1,120 @@ +/* + * $Id: thix_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $ + * + * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2011, Professor Benoit Macq + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +/*! \file + * \brief Modification of jpip.c from 2KAN indexer + */ + +#include +#include +#include +#include "opj_includes.h" + +/* + * Write tile-part headers mhix box + * + * @param[in] coff offset of j2k codestream + * @param[in] cstr_info codestream information + * @param[in] tileno tile number + * @param[in] cio file output handle + * @return length of mhix box + */ +int write_tilemhix( int coff, opj_codestream_info_t cstr_info, int tileno, opj_cio_t *cio); + +int write_thix( int coff, opj_codestream_info_t cstr_info, opj_cio_t *cio) +{ + int len, lenp, i; + int tileno; + opj_jp2_box_t *box; + + lenp = 0; + box = (opj_jp2_box_t *)opj_calloc( cstr_info.tw*cstr_info.th, sizeof(opj_jp2_box_t)); + + for ( i = 0; i < 2 ; i++ ){ + if (i) + cio_seek( cio, lenp); + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_THIX, 4); /* THIX */ + write_manf( i, cstr_info.tw*cstr_info.th, box, cio); + + for (tileno = 0; tileno < cstr_info.tw*cstr_info.th; tileno++){ + box[tileno].length = write_tilemhix( coff, cstr_info, tileno, cio); + box[tileno].type = JPIP_MHIX; + } + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); + } + + opj_free(box); + + return len; +} + +int write_tilemhix( int coff, opj_codestream_info_t cstr_info, int tileno, opj_cio_t *cio) +{ + int i; + opj_tile_info_t tile; + opj_tp_info_t tp; + int len, lenp; + opj_marker_info_t *marker; + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_MHIX, 4); /* MHIX */ + + tile = cstr_info.tile[tileno]; + tp = tile.tp[0]; + + cio_write( cio, tp.tp_end_header-tp.tp_start_pos+1, 8); /* TLEN */ + + marker = cstr_info.tile[tileno].marker; + + for( i=0; i +#include "opj_includes.h" + +#define MAX(a,b) ((a)>(b)?(a):(b)) + + +/* + * Write faix box of tpix + * + * @param[in] coff offset of j2k codestream + * @param[in] compno component number + * @param[in] cstr_info codestream information + * @param[in] j2klen length of j2k codestream + * @param[in] cio file output handle + * @return length of faix box + */ +int write_tpixfaix( int coff, int compno, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio); + + +int write_tpix( int coff, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio) +{ + int len, lenp; + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_TPIX, 4); /* TPIX */ + + write_tpixfaix( coff, 0, cstr_info, j2klen, cio); + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); + + return len; +} + + +/* + * Get number of maximum tile parts per tile + * + * @param[in] cstr_info codestream information + * @return number of maximum tile parts per tile + */ +int get_num_max_tile_parts( opj_codestream_info_t cstr_info); + +int write_tpixfaix( int coff, int compno, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio) +{ + int len, lenp; + int i, j; + int Aux; + int num_max_tile_parts; + int size_of_coding; /* 4 or 8 */ + opj_tp_info_t tp; + int version; + + num_max_tile_parts = get_num_max_tile_parts( cstr_info); + + if( j2klen > pow( 2, 32)){ + size_of_coding = 8; + version = num_max_tile_parts == 1 ? 1:3; + } + else{ + size_of_coding = 4; + version = num_max_tile_parts == 1 ? 0:2; + } + + lenp = cio_tell( cio); + cio_skip( cio, 4); /* L [at the end] */ + cio_write( cio, JPIP_FAIX, 4); /* FAIX */ + cio_write( cio, version, 1); /* Version 0 = 4 bytes */ + + cio_write( cio, num_max_tile_parts, size_of_coding); /* NMAX */ + cio_write( cio, cstr_info.tw*cstr_info.th, size_of_coding); /* M */ + for (i = 0; i < cstr_info.tw*cstr_info.th; i++){ + for (j = 0; j < cstr_info.tile[i].num_tps; j++){ + tp = cstr_info.tile[i].tp[j]; + cio_write( cio, tp.tp_start_pos-coff, size_of_coding); /* start position */ + cio_write( cio, tp.tp_end_pos-tp.tp_start_pos+1, size_of_coding); /* length */ + if (version & 0x02){ + if( cstr_info.tile[i].num_tps == 1 && cstr_info.numdecompos[compno] > 1) + Aux = cstr_info.numdecompos[compno] + 1; + else + Aux = j + 1; + + cio_write( cio, Aux,4); + /*cio_write(img.tile[i].tile_parts[j].num_reso_AUX,4);*/ /* Aux_i,j : Auxiliary value */ + /* fprintf(stderr,"AUX value %d\n",Aux);*/ + } + /*cio_write(0,4);*/ + } + /* PADDING */ + while (j < num_max_tile_parts){ + cio_write( cio, 0, size_of_coding); /* start position */ + cio_write( cio, 0, size_of_coding); /* length */ + if (version & 0x02) + cio_write( cio, 0,4); /* Aux_i,j : Auxiliary value */ + j++; + } + } + + len = cio_tell( cio)-lenp; + cio_seek( cio, lenp); + cio_write( cio, len, 4); /* L */ + cio_seek( cio, lenp+len); + + return len; + +} + +int get_num_max_tile_parts( opj_codestream_info_t cstr_info) +{ + int num_max_tp = 0, i; + + for( i=0; i + + + Nancy + 1.2.0 + Andreas Håkansson, Steven Robbins and contributors + Andreas Håkansson, Steven Robbins and contributors + https://github.com/NancyFx/Nancy/blob/master/license.txt + http://nancyfx.org/ + http://nancyfx.org/nancy-nuget.png + false + Nancy is a lightweight web framework for the .Net platform, inspired by Sinatra. Nancy aim at delivering a low ceremony approach to building light, fast web applications. + Nancy is a lightweight web framework for the .Net platform, inspired by Sinatra. Nancy aim at delivering a low ceremony approach to building light, fast web applications. + Andreas Håkansson, Steven Robbins and contributors + en-US + Nancy + + \ No newline at end of file diff --git a/packages/Nancy.1.2.0/lib/net40/Nancy.dll b/packages/Nancy.1.2.0/lib/net40/Nancy.dll new file mode 100644 index 0000000..320536f Binary files /dev/null and b/packages/Nancy.1.2.0/lib/net40/Nancy.dll differ diff --git a/packages/Nancy.1.2.0/lib/net40/Nancy.xml b/packages/Nancy.1.2.0/lib/net40/Nancy.xml new file mode 100644 index 0000000..f4364d8 --- /dev/null +++ b/packages/Nancy.1.2.0/lib/net40/Nancy.xml @@ -0,0 +1,13246 @@ + + + + Nancy + + + + + Pipeline items to execute + + + + + Add an item to the start of the pipeline + + Item to add + + + + Add an item to the start of the pipeline + + Item to add + + + + Add an item to the start of the pipeline + + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Add an item to the start of the pipeline + + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Add an item to the end of the pipeline + + Item to add + + + + Add an item to the end of the pipeline + + Item to add + + + + Add an item to the end of the pipeline + + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Add an item to the end of the pipeline + + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Add an item to a specific place in the pipeline. + + Index to add at + Item to add + + + + Add an item to a specific place in the pipeline. + + Index to add at + Item to add + + + + Add an item to a specific place in the pipeline. + + Index to add at + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Add an item to a specific place in the pipeline. + + Index to add at + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Insert an item before a named item. + If the named item does not exist the item is inserted at the start of the pipeline. + + Name of the item to insert before + Item to insert + + + + Insert an item before a named item. + If the named item does not exist the item is inserted at the start of the pipeline. + + Name of the item to insert before + Item to insert + + + + Insert an item before a named item. + If the named item does not exist the item is inserted at the start of the pipeline. + + Name of the item to insert before + Item to insert + + + + Insert an item before a named item. + If the named item does not exist the item is inserted at the start of the pipeline. + + Name of the item to insert before + Item to insert + + + + Insert an item after a named item. + If the named item does not exist the item is inserted at the end of the pipeline. + + Name of the item to insert after + Item to insert + + + + Insert an item after a named item. + If the named item does not exist the item is inserted at the end of the pipeline. + + Name of the item to insert after + Item to insert + + + + Insert an item after a named item. + If the named item does not exist the item is inserted at the end of the pipeline. + + Name of the item to insert after + Item to insert + + + + Insert an item after a named item. + If the named item does not exist the item is inserted at the end of the pipeline. + + Name of the item to insert after + Item to insert + + + + Remove a named pipeline item + + Name + Index of item that was removed or -1 if nothing removed + + + + Wraps a sync delegate into it's async form + + Sync pipeline instance + Async pipeline instance + + + + Gets the current pipeline items + + + + + Gets the current pipeline item delegates + + + + + Scans the app domain for assemblies and types + + + + + Nancy core assembly + + + + + App domain type cache + + + + + App domain assemblies cache + + + + + Indicates whether the all Assemblies, that references a Nancy assembly, have already been loaded + + + + + The default assemblies for scanning. + Includes the nancy assembly and anything referencing a nancy assembly + + + + + Add assemblies to the list of assemblies to scan for Nancy types + + One or more assembly names + + + + Add assemblies to the list of assemblies to scan for Nancy types + + One of more assemblies + + + + Add predicates for determining which assemblies to scan for Nancy types + + One or more predicates + + + + Load assemblies from a the app domain base directory matching a given wildcard. + Assemblies will only be loaded if they aren't already in the appdomain. + + Wildcard to match the assemblies to load + + + + Load assemblies from a given directory matching a given wildcard. + Assemblies will only be loaded if they aren't already in the appdomain. + + Directory containing the assemblies + Wildcard to match the assemblies to load + + + + Refreshes the type cache if additional assemblies have been loaded. + Note: This is called automatically if assemblies are loaded using LoadAssemblies. + + + + + Updates the assembly cache from the appdomain + + + + + Loads any assembly that references a Nancy assembly. + + + + + Gets all types implementing a particular interface/base class + + Type to search for + An of types. + Will scan with . + + + + Gets all types implementing a particular interface/base class + + Type to search for + A value to determine which type set to scan in. + An of types. + + + + Gets all types implementing a particular interface/base class + + Type to search for + An of types. + Will scan with . + + + + Gets all types implementing a particular interface/base class + + Type to search for + A value to determine which type set to scan in. + An of types. + + + + Returns the directories containing dll files. It uses the default convention as stated by microsoft. + + + + + + Gets or sets a set of rules for which assemblies are scanned + Defaults to just assemblies that have references to nancy, and nancy + itself. + Each item in the enumerable is a delegate that takes the assembly and + returns true if it is to be included. Returning false doesn't mean it won't + be included as a true from another delegate will take precedence. + + + + + Gets app domain types. + + + + + Gets app domain types. + + + + + Provides a hook to perform registrations during application startup. + + + + + Provides a hook to perform registrations during application startup. + + + + + Gets the type registrations to register for this startup task + + + + + Gets the collection registrations to register for this startup task + + + + + Gets the instance registrations to register for this startup task + + + + + Provides a hook to execute code during request startup. + + + + + Perform any initialisation tasks + + Application pipelines + The current context + + + + Helper class for providing application registrations + + + + + Scans for the implementation of and registers it. + + Lifetime of the registration, defaults to singleton + The to scan for and register as. + + + + Scans for all implementations of and registers them. + + Lifetime of the registration, defaults to singleton + The to scan for and register as. + + + + Registers the types provided by the parameters + as . + + The to register as. + The types to register. + Lifetime of the registration, defaults to singleton + + + + Registers the type provided by the parameter + as . + + Lifetime of the registration, defaults to singleton + The to register as. + The to register as . + + + + Registers an instance as . + + The to register as. + The instance to register. + + + + Scans for a that implements . If found, then it + will be used for the registration, else it will use . + + Lifetime of the registration, defaults to singleton + The to register as. + The implementation of that will be use if no other implementation can be found. + + When scanning, it will exclude the assembly that the instance is defined in and it will also ignore + the type specified by . + + + + + Scans for an implementation of and registers it if found. If no implementation could + be found, it will retrieve an instance of using the provided , + which will be used in the registration. + + The to register as. + Factory that provides an instance of . + When scanning, it will exclude the assembly that the instance is defined in + + + + Scans for all implementations of . If no implementations could be found, then it + will register the types specified by . + + Lifetime of the registration, defaults to singleton + The to register as. + The types to register if non could be located while scanning. + + When scanning, it will exclude the assembly that the instance is defined in and it will also ignore + the types specified by . + + + + + Scans for all implementations of and registers them, followed by the + types defined by the parameter. + + The to register as. + The types to register last. + Lifetime of the registration, defaults to singleton + + When scanning, it will exclude the assembly that the instance is defined in and it will also ignore + the types specified by . + + + + + Gets the collection registrations to register for this startup task + + + + + Gets the instance registrations to register for this startup task + + + + + Gets the type registrations to register for this startup task + + + + + Exception that is raised from inside the type or one of + the inheriting types. + + + + + Initializes a new instance of the class, with + the provided . + + The message that describes the error. + + + + Initializes a new instance of the class, with + the provided and . + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Initializes a new instance of the class. + + The that holds the serialized object data about the exception being thrown. + The that contains contextual information about the source or destination. + + + + Represents a type to be registered multiple times into the + container to later be resolved using an IEnumerable{RegistrationType} + constructor dependency. + + + + + Base class for container registrations + + + + + Checks if all implementation types are assignable from the registration type, otherwise throws an exception. + + The implementation types. + One or more of the implementation types is not assignable from the registration type. + The property must be assigned before the method is invoked. + + + + Gets the lifetime of the registration + + + + + Registration type i.e. IMyInterface + + + + + Represents a type to be registered multiple times into the + container to later be resolved using an IEnumerable{RegistrationType} + constructor dependency. + + Registration type i.e. IMyInterface + Collection of implementation type i.e. MyClassThatImplementsIMyInterface + Lifetime to register the type as + + + + Collection of implementation type i.e. MyClassThatImplementsIMyInterface + + + + + Application startup task that attempts to locate a favicon. The startup will first scan all + folders in the path defined by the provided and if it cannot + find one, it will fall back and use the default favicon that is embedded in the Nancy.dll file. + + + + + Provides a hook to execute code during application startup. + + + + + Perform any initialisation tasks + + Application pipelines + + + + Initializes a new instance of the class, with the + provided instance. + + The that should be used to scan for a favicon. + + + + Perform any initialisation tasks + + Application pipelines + + + + Gets the default favicon + + A byte array, containing a favicon.ico file. + + + + + The pre-request hook + + + The PreRequest hook is called prior to processing a request. If a hook returns + a non-null response then processing is aborted and the response provided is + returned. + + + + + + + The post-request hook + + + The post-request hook is called after the response is created. It can be used + to rewrite the response or add/remove items from the context. + + + + + + + The error hook + + + The error hook is called if an exception is thrown at any time during the pipeline. + If no error hook exists a standard InternalServerError response is returned + + + + + + Represents an instance to be registered into the container + + + + + Initializes a new instance of the class. + + The registration type. + The implementation. + + + + Implementation object instance i.e. instance of MyClassThatImplementsIMyInterface + + + + + Represents the lifetime of a container registration + + + + + Transient lifetime - each request to the container for + the type will result in a new version being returned. + + + + + Singleton - each request to the container for the type + will result in the same instance being returned. + + + + + PerRequest - within the context of each request each request + for the type will result in the same instance being returned. + Different requests will have different versions. + + + + + Exception raised when the discovers more than one + implementation in the loaded assemblies. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The message that describes the error. + + + + Initializes a new instance of the class. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + + + + Initializes a new instance of the class. + + The provider types. + + + + Initializes a new instance of the class. + + The that holds the serialized object data about the exception being thrown. + The that contains contextual information about the source or destination. + + + + Stores the provider types. + + The provider types. + + + + Gets the provider types. + + + The provider types. + + + + + Returns a more friendly and informative message if the list of providers is available. + + + Message generated will be of the format: + + More than one IRootPathProvider was found: + Nancy.Tests.Functional.Tests.CustomRootPathProvider2 + Nancy.Tests.Functional.Tests.CustomRootPathProvider + and since we do not know which one you want to use, you need to override the RootPathProvider property on your bootstrapper and specify which one to use. Sorry for the inconvenience. + + + + + + Configuration class for Nancy's internals. + Contains implementation types/configuration for Nancy that usually + do not require overriding in "general use". + + + + + Default Nancy configuration with specific overloads + + Configuration builder for overriding the default configuration properties. + Nancy configuration instance + + + + Returns the configuration types as a TypeRegistration collection + + TypeRegistration collection representing the configuration types + + + + Returns the collection configuration types as a CollectionTypeRegistration collection + + CollectionTypeRegistration collection representing the configuration types + + + + Gets the Nancy default configuration + + + + + Gets a value indicating whether the configuration is valid. + + + + + Default implementation of the Nancy pipelines + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class and clones the hooks from + the provided instance. + + + + + + The pre-request hook + + + The PreRequest hook is called prior to processing a request. If a hook returns + a non-null response then processing is aborted and the response provided is + returned. + + + + + + + The post-request hook + + + The post-request hook is called after the response is created. It can be used + to rewrite the response or add/remove items from the context. + + + + + + + The error hook + + + The error hook is called if an exception is thrown at any time during the pipeline. + If no error hook exists a standard InternalServerError response is returned + + + + + + Determines which set of types that the should scan in. + + + + + All available types. + + + + + Only in types that are defined in the Nancy assembly. + + + + + Only types that are defined outside the Nancy assembly. + + + + + Only Namespaces that starts with 'Nancy' + + + + + Only Namespaces that does not start with Nancy + + + + + Collection of accept header coercions + + + + + Built in functions for coercing accept headers. + + + + + + Adds a default accept header if there isn't one. + + Current headers + Context + Modified headers or original if no modification required + + + + Replaces the accept header of stupid browsers that request XML instead + of HTML. + + Current headers + Context + Modified headers or original if no modification required + + + + Boosts the priority of HTML for browsers that ask for xml and html with the + same priority. + + Current headers + Context + Modified headers or original if no modification required + + + + Built in functions for determining current culture + + + + + + Checks to see if the Form has a CurrentCulture key. + + NancyContext + CultureInfo if found in Form otherwise null + + + + Checks to see if the first argument in the Path can be used to make a CultureInfo. + + NancyContext + CultureInfo if found in Path otherwise null + + + + Checks to see if the AcceptLanguage in the Headers can be used to make a CultureInfo. Uses highest weighted if multiple defined. + + NancyContext + CultureInfo if found in Headers otherwise null + + + + Checks to see if the Session has a CurrentCulture key + + NancyContext + CultureInfo if found in Session otherwise null + + + + Checks to see if the Cookies has a CurrentCulture key + + NancyContext + CultureInfo if found in Cookies otherwise null + + + + Uses the Thread.CurrentThread.CurrentCulture + + NancyContext + CultureInfo from CurrentThread + + + + Validates culture name + + Culture name eg\en-GB + True/False if valid culture + + + + Gets a set of all valid cultures + + + + + Collection class for static culture conventions + + + + + Creates a new instance of CultureConventions + + + + + + Wires up the default conventions for the accept header coercion + + + + + Provides Nancy convention defaults and validation + + + + + Initialise any conventions this class "owns" + + Convention object instance + + + + Asserts that the conventions that this class "owns" are valid + + Conventions object instance + Tuple containing true/false for valid/invalid, and any error messages + + + + Initialise culture conventions + + + + + + Determine if culture conventions are valid + + + + + + + Setup default conventions + + + + + + Defines the default static contents conventions. + + + + + Initialise any conventions this class "owns". + + Convention object instance. + + + + Asserts that the conventions that this class "owns" are valid + + Conventions object instance. + Tuple containing true/false for valid/invalid, and any error messages. + + + + Defines the default static contents conventions. + + + + + Initialise any conventions this class "owns". + + Convention object instance. + + + + Asserts that the conventions that this class "owns" are valid. + + Conventions object instance. + Tuple containing true/false for valid/invalid, and any error messages. + + + + Nancy configurable conventions + + + + + Discovered conventions + + + + + Initializes a new instance of the class. + + + + + Validates the conventions + + A tuple containing a flag indicating validity, and any error messages + + + + Gets the instance registrations for registering into the container + + Enumeration of InstanceRegistration types + + + + Locates all the default conventions and calls them in + turn to build up the default conventions. + + + + + Gets or sets the conventions for locating view templates + + + + + Gets or sets the conventions for locating and serving static content + + + + + Gets or sets the conventions for coercing accept headers from their source + values to the real values for content negotiation + + + + + + Gets or sets the conventions for determining request culture + + + + + Helper class for defining directory-based conventions for static contents. + + + + + Adds a directory-based convention for static convention. + + The path that should be matched with the request. + The path to where the content is stored in your application, relative to the root. If this is then it will be the same as . + A list of extensions that is valid for the conventions. If not supplied, all extensions are valid. + A instance for the requested static contents if it was found, otherwise . + + + + Adds a file-based convention for static convention. + + The file that should be matched with the request. + The file that should be served when the requested path is matched. + + + + Returns whether the given filename is contained within the content folder + + Content root path + Filename requested + True if contained within the content root, false otherwise + + + + Used to uniquely identify a request. Needed for when two Nancy applications want to serve up static content of the same + name from within the same AppDomain. + + + + + The path of the static content for which this response is being issued + + + + + The root folder path of the Nancy application for which this response will be issued + + + + + Nancy static convention helper + + + + + Extension method for NancyConventions + + conventions.MapStaticContent((File, Directory) => + { + File["/page.js"] = "page.js"; + Directory["/images"] = "images"; + }); + + + The conventions to add to. + The callback method allows you to describe the static content + + + + Collection class for static content conventions + + + + + Extension methods to adding static content conventions. + + + + + Adds a directory-based convention for static convention. + + The conventions to add to. + The path that should be matched with the request. + The path to where the content is stored in your application, relative to the root. If this is then it will be the same as . + A list of extensions that is valid for the conventions. If not supplied, all extensions are valid. + + + + Adds a directory-based convention for static convention. + + The conventions to add to. + The file that should be matched with the request. + The file that should be served when the requested path is matched. + + + + Nancy static directory convention helper + + + + + Creates a new instance of StaticDirectoryContent + + NancyConventions, to which static directories get added + + + + Adds a new static directory to the nancy conventions + + The route of the file + A list of extensions that is valid for the conventions. If not supplied, all extensions are valid + + + + Nancy static file convention helper + + + + + Creates a new instance of StaticFileContent + + NancyConventions, to which static files get added + + + + Adds a new static file to the nancy conventions + + The route of the file + + + + Determines current culture for context + + + + + Provides current culture for Nancy context + + + + + Determine current culture for NancyContext + + NancyContext + CultureInfo + + + + Creates a new instance of DefaultCultureService + + CultureConventions to use for determining culture + + + + Determine current culture for NancyContext + + NancyContext + CultureInfo + + + + The default implementation of the interface. + + + + + Defines the functionality of a factory. + + + + + Creates a new instance. + + The instance that should be used by the response formatter. + An instance. + + + + Initializes a new instance of the class, with the + provided . + + + + + + Creates a new instance. + + The instance that should be used by the response formatter. + An instance. + + + + Default implementation of . + + + + + Defines the functionality to retrieve the root folder path of the current Nancy application. + + + + + Helper interface used to hide the base members from the fluent API to make it much cleaner + in Visual Studio intellisense. + + Created by Daniel Cazzulino http://www.clariusconsulting.net/blogs/kzu/archive/2008/03/10/58301.aspx + + + + Hides the method. + + + + + Hides the method. + + + + + Hides the method. + + + + + Hides the method. + + + + + Returns the root folder path of the current Nancy application. + + A containing the path of the root folder. + + + + Returns the root folder path of the current Nancy application. + + A containing the path of the root folder. + + + + The default static content provider that uses + to determine what static content to serve. + + + + + Provides static content delivery + + + + + Gets the static content response, if possible. + + Current context + Response if serving content, null otherwise + + + + Initializes a new instance of the class, using the + provided and . + + The current root path provider. + The static content conventions. + + + + Gets the static content response, if possible. + + Current context + Response if serving content, null otherwise + + + + Default implementation of the interface. + + + + + Defines the functionality for creating an instance. + + + + + Creates an instance. + + A instance. + An instance. + + + + Creates an instance. + + A instance. + An instance. + + + + Default implementation of the interface. + + + + + Provides request trace logging. + Uses a delegate to write to the log, rather than creating strings regardless + of whether the log is enabled or not. + + + + + Write to the log + + Log writing delegate + + + + Creates a new instance of the class. + + + + + Write to the log + + Log writing delegate + + + + Returns a string that represents the current object. + + + A string that represents the current object. + + + + + Settings for the diagnostics dashboard + + + + + Initializes a new instance of the class, + using the cryptographic + configuration. + + + + + Initializes a new instance of the class, + using the cryptographic + configuration. + + The to use with diagnostics. + + + + Gets or sets the name of the cookie used by the diagnostics dashboard. + + The default is __ncd + + + + Gets or sets the cryptography config to use for securing the diagnostics dashboard + + + + + Gets or sets password for accessing the diagnostics screen. + This should be secure :-) + + + + + Gets or sets the path that the diagnostics dashboard will be accessible on. + + The default is /_Nancy. The path should always start with a forward slash. + + + + The number of minutes that expiry of the diagnostics dashboard will be extended each time it is used. + + The default is 15 minutes. + + + + Gets a value indicating whether the configuration is valid + + + + + Provides a thread safe, limited size, collection of objects + If the collection is full the oldest item gets removed. + + Type to store + + + + Creates a new instance of the ConcurrentLimitedCollection class + + Maximum size for the collection + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Adds an item to the collection. + If the collection is full, the oldest item is removed and the new item + is added to the end of the collection. + + Item to add + + + + Clear the collection + + + + + Implementation of the interface that does nothing. + + + + + Initialise diagnostics + + Application pipelines + + + + Initialise diagnostics + + Application pipelines + + + + Defines the functionality for tracing a request. + + + + + Gets or sets the generic item store. + + An instance containing the items. + + + + Gets or sets the information about the request. + + An instance. + + + + Gets or sets the information about the response. + + An instance. + + + + Gets the trace log. + + A instance. + + + + Implementation of that does not log anything. + + + + + Write to the log + + Log writing delegate + + + + Returns a string that represents the current object. + + + A string that represents the current object. + + + + + Stores request trace information about the request. + + + + + Implicitly casts a instance into a instance. + + A instance. + A instance. + + + + Gets or sets the content type of the request. + + A containing the content type. + + + + Gets or sets the headers of the request. + + A instance containing the headers. + + + + Gets the HTTP verb of the request. + + A containing the HTTP verb. + + + + Gets or sets the that was requested. + + + + + Stores request trace information about the response. + + + + + Implicitly casts a instance into a instance. + + A instance. + A instance. + + + + Gets or sets the content type of the response. + + A containing the content type. + + + + Gets or sets the headers of the response. + + A instance containing the headers. + + + + Gets or sets the of the response. + + + + + Gets or sets the of the response. + + A instance. + + + + A "disabled" static content provider - always returns null + so no content is served. + + + + + Gets the static content response, if possible. + + Current context + Response if serving content, null otherwise + + + + Here Be Dragons - Using an exception for flow control to hotwire route execution. + It can be useful to call a method inside a route definition and have that method + immediately return a response (such as for authentication). This exception is used + to allow that flow. + + + + + Initializes a new instance of the class. + + + The response. + + + The reason for the early exit. + + + + + Gets or sets the reason for the early exit + + + + + Gets or sets the response + + + + + Containing extensions for the property. + + + + + Adds a new to the validation results. + + A reference to the property. + The name of the property. + The validation error message. + A reference to the property. + + + + Extensions for RequestStream. + + + + + Gets the request body as a string. + + The request body stream. + The encoding to use, by default. + The request body as a . + + + + Containing extensions for the object. + + + + + Buffer size for copy operations + + + + + Copies the contents between two instances in an async fashion. + + The source stream to copy from. + The destination stream to copy to. + Delegate that should be invoked when the operation has completed. Will pass the source, destination and exception (if one was thrown) to the function. Can pass in . + + + + Containing extensions for the object. + + + + + Gets the path of the assembly that contains the provided type. + + The to look up the assembly path for. + A string containing the path of the assembly that contains the type. + + + + Checks if a type is an array or not + + The type to check. + if the type is an array, otherwise . + + + + Determines whether the is assignable from + taking into account generic definitions + + + Borrowed from: http://tmont.com/blargh/2011/3/determining-if-an-open-generic-type-isassignablefrom-a-type + + + + + Checks if a type is an collection or not + + The type to check. + if the type is an collection, otherwise . + + + + Checks if a type is enumerable or not + + The type to check. + if the type is an enumerable, otherwise . + + + + Determines if a type is numeric. Nullable numeric types are considered numeric. + + + Boolean is not considered numeric. + + + + + Default implementation of the interface. + + + + + Defines the functionality for request tracing. + + + + + Adds the , of the provided, to the trace log. + + The identifier of the trace. + A instance. + + + + Clears the trace log. + + + + + Creates a new trace session. + + A which represents the identifier of the new trace session. + + + + Gets all the available instances. + + + + + + Checks if the provided is valid or not. + + A representing the session to check. + if the session is valid, otherwise . + + + + Adds the , of the provided, to the trace log. + + The identifier of the trace. + A instance. + + + + Clears the trace log. + + + + + Creates a new trace session. + + A which represents the identifier of the new trace session. + + + + Gets all the available instances. + + + + + + Checks if the provided is valid or not. + + A representing the session to check. + if the session is valid, otherwise . + + + + Basic class containing the functionality for defining routes and actions in Nancy. + + + + + Nancy module base interface + Defines all the properties / behaviour needed by Nancy internally + + + + + The post-request hook + + The post-request hook is called after the response is created by the route execution. + It can be used to rewrite the response or add/remove items from the context. + + + + + The pre-request hook + + The PreRequest hook is called prior to executing a route. If any item in the + pre-request pipeline returns a response then the route is not executed and the + response is returned. + + + + + The error hook + + The error hook is called if an exception is thrown at any time during executing + the PreRequest hook, a route and the PostRequest hook. It can be used to set + the response and/or finish any ongoing tasks (close database session, etc). + + + + + Gets or sets the current Nancy context + A instance. + + + + An extension point for adding support for formatting response contents. + This property will always return because it acts as an extension point.Extension methods to this property should always return or one of the types that can implicitly be types into a . + + + + Gets or sets the model binder locator + + + + + Gets or sets the model validation result + + + + + Gets or sets the validator locator. + + + + + Gets or sets an instance that represents the current request. + An instance. + + + + The extension point for accessing the view engines in Nancy. + An instance.This is automatically set by Nancy at runtime. + + + + Get the root path of the routes in the current module. + A containing the root path of the module or if no root path should be used.All routes will be relative to this root path. + + + + Gets all declared routes by the module. + A instance, containing all instances declared by the module. + + + + Gets or sets the dynamic object used to locate text resources. + + + + + Renders a view from inside a route handler. + + A instance that is used to determine which view that should be rendered. + + + + Used to negotiate the content returned based on Accepts header. + + A instance that is used to negotiate the content returned. + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + A containing the root relative path that all paths in the module will be a subset of. + + + + Non-model specific data for rendering in the response + + + + + Gets for declaring actions for DELETE requests. + + A instance. + + + + Gets for declaring actions for GET requests. + + A instance. + + + + Gets for declaring actions for HEAD requests. + + A instance. + + + + Gets for declaring actions for OPTIONS requests. + + A instance. + + + + Gets for declaring actions for PATCH requests. + + A instance. + + + + Gets for declaring actions for POST requests. + + A instance. + + + + Gets for declaring actions for PUT requests. + + A instance. + + + + Get the root path of the routes in the current module. + + + A containing the root path of the module or + if no root path should be used.All routes will be relative to this root path. + + + + + Gets all declared routes by the module. + + A instance, containing all instances declared by the module. + This is automatically set by Nancy at runtime. + + + + Gets the current session. + + + + + Renders a view from inside a route handler. + + A instance that is used to determine which view that should be rendered. + + + + Used to negotiate the content returned based on Accepts header. + + A instance that is used to negotiate the content returned. + + + + Gets or sets the validator locator. + + This is automatically set by Nancy at runtime. + + + + Gets or sets an instance that represents the current request. + + An instance. + + + + The extension point for accessing the view engines in Nancy. + An instance. + This is automatically set by Nancy at runtime. + + + + The post-request hook + + The post-request hook is called after the response is created by the route execution. + It can be used to rewrite the response or add/remove items from the context. + + This is automatically set by Nancy at runtime. + + + + + + The pre-request hook + + + The PreRequest hook is called prior to executing a route. If any item in the + pre-request pipeline returns a response then the route is not executed and the + response is returned. + + This is automatically set by Nancy at runtime. + + + + + + The error hook + + + The error hook is called if an exception is thrown at any time during executing + the PreRequest hook, a route and the PostRequest hook. It can be used to set + the response and/or finish any ongoing tasks (close database session, etc). + + This is automatically set by Nancy at runtime. + + + + + Gets or sets the current Nancy context + + A instance. + This is automatically set by Nancy at runtime. + + + + An extension point for adding support for formatting response contents. + This property will always return because it acts as an extension point.Extension methods to this property should always return or one of the types that can implicitly be types into a . + + + + Gets or sets the model binder locator + + This is automatically set by Nancy at runtime. + + + + Gets or sets the model validation result + + This is automatically set by Nancy at runtime when you run validation. + + + + Helper class for configuring a route handler in a module. + + + + + Initializes a new instance of the class. + + The HTTP request method that the route should be available for. + The that the route is being configured for. + + + + Defines a Nancy route for the specified . + + A delegate that is used to invoke the route. + + + + Defines a Nancy route for the specified and . + + A delegate that is used to invoke the route. + + + + Defines an async route for the specified + + + + + Defines an async route for the specified and . + + + + + Defines a Nancy route for the specified and + + A delegate that is used to invoke the route. + + + + Defines a Nancy route for the specified , and + + A delegate that is used to invoke the route. + + + + Defines an async route for the specified and + + + + + Defines an async route for the specified , and + + + + + Defines the functionality to build a fully configured NancyModule instance. + + + + + Builds a fully configured instance, based upon the provided . + + The that should be configured. + The current request context. + A fully configured instance. + + + + Builds a fully configured instance, based upon the provided . + + The that should be configured. + The current request context. + A fully configured instance. + + + + Catalog of instances. + + + + + Get all NancyModule implementation instances - should be per-request lifetime + + The current context + An instance containing instances. + + + + Retrieves a specific implementation - should be per-request lifetime + + Module type + The current context + The instance + + + + Get all NancyModule implementation instances - should be per-request lifetime + + The current context + An instance containing instances. + + + + Retrieves a specific implementation - should be per-request lifetime + + Module type + The current context + The instance + + + + Wires up the diagnostics support at application startup. + + + + + Creates a new instance of the class. + + + + + + + + + + + + + + + + + Initialise diagnostics + + Application pipelines + + + + Renders diagnostics views from embedded resources. + + + + + Creates a new instance of the class. + + A instance. + + + + Renders the diagnostics view with the provided . + + The name of the view to render. + A of the rendered view. + + + + Renders the diagnostics view with the provided and . + + The name of the view to render. + The model that should be passed to the view engine during rendering. + A of the rendered view. + + + + Defines the functionality for resolving the requested view. + + + + + Locates a view based on the provided information. + + The name of the view to locate. + The model that will be used with the view. + A instance, containing information about the context for which the view is being located. + A instance if the view could be found, otherwise . + + + + Locates a view based on the provided information. + + The name of the view to locate. + The model that will be used with the view. + A instance, containing information about the context for which the view is being located. + A instance if the view could be found, otherwise . + + + + Used to return string values + + + + + Gets a translation based on the provided key. + + The key to look up the translation for. + The current instance. + + + + Helper class for caching related functions + + + + + Returns whether to return a not modified response, based on the etag and last modified date + of the resource, and the current nancy context + + Current resource etag, or null + Current resource last modified, or null + Current nancy context + True if not modified should be sent, false otherwise + + + + Add this attribute to an assembly to make sure + it is included in Nancy's assembly scanning. + + + Apply the attribute, typically in AssemblyInfo.(cs|fs|vb), as follows: + [assembly: IncludeInNancyAssemblyScanning] + + + + + Returns text from an implemented ITextResource + + + + + Initializes a new instance of the class. + + The that should be used by the TextResourceFinder + The that should be used by the TextResourceFinder + + + + Finds text resource + + GetMemberBinder with dynamic text key + Text item + Returns a value or a non existing value from the implementation + + + + Gets the that is being used to locate texts. + + An instance. + + + + Gets a translation based on the provided key. + + The key to look up the translation for. + + + + Configurations that controls the behavior of the binder at runtime. + + + + + Initializes a new instance of the class. + + + + + Binding configuration that permits that the binder overwrites non-default values. + + + + + Default binding configuration. + + + + + Gets or sets whether the binder should be happy once it has bound to the request body. In this case, + request and context parameters will not be bound to. If there is no body and this option is enabled, + no binding will take place at all. + + if the binder will stop once the body has been bound, otherwise . + + + + Gets or sets whether binding error should be ignored and the binder should continue with the next property. + + Setting this property to means that no will be thrown if an error occurs. + If the binder should ignore errors, otherwise . + + + + Gets or sets whether the binder is allowed to overwrite properties that does not have a default value. + + if the binder is allowed to overwrite non-default values, otherwise . + + + + Represents a bindable member of a type, which can be a property or a field. + + + + + Constructs a BindingMemberInfo instance for a property. + + The bindable property to represent. + + + + Constructs a BindingMemberInfo instance for a field. + + The bindable field to represent. + + + + Gets the value from a specified object associated with the property or field represented by this BindingMemberInfo. + + The object whose property or field should be retrieved. + The value for this BindingMemberInfo's property or field in the specified object. + + + + Sets the value from a specified object associated with the property or field represented by this BindingMemberInfo. + + The object whose property or field should be assigned. + The value to assign in the specified object to this BindingMemberInfo's property or field. + + + + + + + Compares two BindingMemberInfo's with eachother on their respective values rather then their reference + + the other BindingMemberInfo + true when they are equal and false otherwise + + + + + + + Returns an enumerable sequence of bindable properties for the specified type. + + The type to enumerate. + Bindable properties. + + + + Returns an enumerable sequence of bindable properties for the specified type. + + The type to enumerate. + Bindable properties. + + + + Gets a reference to the MemberInfo that this BindingMemberInfo represents. This can be a property or a field. + + + + + Gets the name of the property or field represented by this BindingMemberInfo. + + + + + Gets the data type of the property or field represented by this BindingMemberInfo. + + + + + Converter for datetime types + + + + + Provides a way to convert from the incoming string representation + of a type to the type itself. + + + + + Whether the converter can convert to the destination type + + Destination type + The current binding context + True if conversion supported, false otherwise + + + + Convert the string representation to the destination type + + Input string + Destination type + Current context + Converted object of the destination type + + + + Whether the converter can convert to the destination type + + Destination type + The current binding context + True if conversion supported, false otherwise + + + + Convert the string representation to the destination type + + Input string + Destination type + Current context + Converted object of the destination type + + + + Converter for numeric types + + + + + Whether the converter can convert to the destination type + + Destination type + The current binding context + True if conversion supported, false otherwise + + + + Convert the string representation to the destination type + + Input string + Destination type + Current context + Converted object of the destination type + + + + Contains extension methods for the type. + + + + + Retrieves the member that an expression is defined for. + + The expression to retrieve the member from. + A instance if the member could be found; otherwise . + + + + Creates new instance + + the name of the property which failed to bind + the value attempted to set + the underlying exception + + + + Gets the property name for which the bind failed + + + + + Gets the value which was attempted to be assigned to the property + + + + + Handles an incoming . + + The instance. + An instance, containing the information about the current request. + A instance containing the request/response context. + + + + Handles an incoming . + + The instance. + An instance, containing the information about the current request. + Delegate to call before the request is processed + A instance containing the request/response context. + + + + Handles an incoming async. + + The instance. + An instance, containing the information about the current request. + Delegate to call before the request is processed + Delegate to call when the request is complete + Delegate to call when any errors occur + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + + + + Handles an incoming async. + + The instance. + An instance, containing the information about the current request. + Delegate to call when the request is complete + Delegate to call when any errors occur + + + + Add a cookie to the response. + + The instance. + The instance that should be added. + The modified instance. + + + + Add a collection of cookies to the response. + + The instance. + The instances that should be added. + The modified instance. + + + + Add a header to the response + + Negotiator object + Header name + Header value + Modified negotiator + + + + Add a content type to the response + + Negotiator object + Content type value + Modified negotiator + + + + Adds headers to the response using anonymous types + + Negotiator object + + Array of headers - each header should be an anonymous type with two string properties + 'Header' and 'Value' to represent the header name and its value. + + Modified negotiator + + + + Adds headers to the response using anonymous types + + Negotiator object + + Array of headers - each header should be a Tuple with two string elements + for header name and header value + + Modified negotiator + + + + Allows the response to be negotiated with any processors available for any content type + + Negotiator object + Modified negotiator + + + + Allows the response to be negotiated with a specific media range + This will remove the wildcard range if it is already specified + + Negotiator object + Media range to add + Modified negotiator + + + + Uses the specified model as the default model for negotiation + + Negotiator object + Model object + Modified negotiator + + + + Uses the specified view for html output + + Negotiator object + View name + Modified negotiator + + + + Sets the model to use for a particular media range. + Will also add the MediaRange to the allowed list + + Negotiator object + Range to match against + Model object + Updated negotiator object + + + + Sets the model to use for a particular media range. + Will also add the MediaRange to the allowed list + + Negotiator object + Range to match against + Model factory for returning the model object + Updated negotiator object + + + + Sets the to use for a particular media range. + Will also add the MediaRange to the allowed list + + Negotiator object + Range to match against + A object + Updated negotiator object + + + + Sets the to use for a particular media range. + Will also add the MediaRange to the allowed list + + Negotiator object + Range to match against + Factory for returning the object + Updated negotiator object + + + + Sets the status code that should be assigned to the final response. + + Negotiator object + The status code that should be used. + Updated negotiator object + + + + Sets the description of the status code that should be assigned to the final response. + + Negotiator object + The status code description that should be used. + Updated negotiator object + + + + Sets the status code that should be assigned to the final response. + + Negotiator object + The status code that should be used. + Updated negotiator object + + + + OWIN extensions for the delegate-based approach. + + + + + Adds Nancy to the OWIN pipeline. + + The application builder delegate. + A configuration builder action. + The application builder delegate. + + + + Adds Nancy to the OWIN pipeline. + + The application builder delegate. + The Nancy options. + The application builder delegate. + + + + OWIN extensions for the NancyContext. + + + + + Gets the OWIN environment dictionary. + + The Nancy context. + The OWIN environment dictionary. + + + + Options for hosting Nancy with OWIN. + + + + + Gets or sets the bootstrapper. If none is set, NancyBootstrapperLocator.Bootstrapper is used. + + + + + Gets or sets the delegate that determines if NancyMiddleware performs pass through. + + + + + Gets or sets a value indicating whether to request a client certificate or not. + Defaults to false. + + + + + Extensions for the NancyOptions class. + + + + + Tells the NancyMiddleware to pass through when + response has one of the given status codes. + + The Nancy options. + The HTTP status code. + + + + Nancy middleware for OWIN. + + + + + The request environment key + + + + + Use Nancy in an OWIN pipeline + + A delegate to configure the . + An OWIN middleware delegate. + + + + Use Nancy in an OWIN pipeline + + An to configure the Nancy middleware + An OWIN middleware delegate. + + + + Gets a delegate to handle converting a nancy response + to the format required by OWIN and signals that the we are + now complete. + + OWIN environment. + The next stage in the OWIN pipeline. + The task completion source to signal. + A predicate that will allow the caller to determine if the request passes through to the + next stage in the owin pipeline. + Delegate + + + + Gets a delegate to handle request errors + + Completion source to signal + Delegate + + + + Creates the Nancy URL + + OWIN Hostname + OWIN Scheme + OWIN Base path + OWIN Path + OWIN Querystring + + + + + Gets a delegate to store the OWIN environment into the NancyContext + + OWIN Environment + Delegate + + + + Encapsulates HTTP-response information from an Nancy operation. + + + + + Null object representing no body + + + + + Initializes a new instance of the class. + + + + + Executes at the end of the nancy execution pipeline and before control is passed back to the hosting. + Can be used to pre-render/validate views while still inside the main pipeline/error handling. + + Nancy context + Task for completion/erroring + + + + Adds a to the response. + + The name of the cookie. + The value of the cookie. + The instance. + + + + Adds a to the response. + + The name of the cookie. + The value of the cookie. + The expiration date of the cookie. Can be if it should expire at the end of the session. + The instance. + + + + Adds a to the response. + + The name of the cookie. + The value of the cookie. + The expiration date of the cookie. Can be if it should expire at the end of the session. + The domain of the cookie. + The path of the cookie. + The instance. + + + + Adds a to the response. + + A instance. + + + + + Implicitly cast an value to a instance, with the + set to the value of the . + + The value that is being cast from. + A instance. + + + + Implicitly cast an int value to a instance, with the + set to the value of the int. + + The int value that is being cast from. + A instance. + + + + Implicitly cast an string instance to a instance, with the + set to the value of the string. + + The string that is being cast from. + A instance. + + + + Implicitly cast an , where T is a , instance to + a instance, with the set to the value of the action. + + The instance that is being cast from. + A instance. + + + + Implicitly cast a instance to a instance, + with the set to the value of the . + + The instance that is being cast from. + A instance. + + + + Converts a string content value to a response action. + + The string containing the content. + A response action that will write the content of the string to the response stream. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + This method can be overridden in sub-classes to dispose of response specific resources. + + + + Gets or sets the type of the content. + + The type of the content. + The default value is text/html. + + + + Gets the delegate that will render contents to the response stream. + + An delegate, containing the code that will render contents to the response stream. + The host of Nancy will pass in the output stream after the response has been handed back to it by Nancy. + + + + Gets the collection of HTTP response headers that should be sent back to the client. + + An instance, containing the key/value pair of headers. + + + + Gets or sets the HTTP status code that should be sent back to the client. + + A value. + + + + Gets or sets a text description of the HTTP status code returned to the client. + + The HTTP status code description. + + + + Gets the instances that are associated with the response. + + A instance, containing instances. + + + + Defines the functionality a diagnostics provider. + + + + + Gets the name of the provider. + + A containing the name of the provider. + + + + Gets the description of the provider. + + A containing the description of the provider. + + + + Gets the object that contains the interactive diagnostics methods. + + An instance of the interactive diagnostics object. + + + + Gets the name of the provider. + + A containing the name of the provider. + + + + Gets the description of the provider. + + A containing the description of the provider. + + + + Gets the object that contains the interactive diagnostics methods. + + An instance of the interactive diagnostics object. + + + + Enable JSONP support in the application + + Application Pipeline to Hook into + + + + Disable JSONP support in the application + + Application Pipeline to Hook into + + + + Transmogrify original response and apply JSONP Padding + + Current Nancy Context + + + + Enables JSONP support at application startup. + + + + + Perform any initialisation tasks + + Application pipelines + + + + Exception that is thrown when an unhandled exception occurred during + the execution of the current request. + + + + + Initializes a new instance of the , with + the specified . + + + + + + Takes an existing response and materialises the body. + Can be used as a wrapper to force execution of the deferred body for + error checking etc. + Copies the existing response into memory, so use with caution. + + + + + Response that indicates that the response format should be negotiated between the client and the server. + + + + + Initializes a new instance of the response for the + provided . + + The response value that should be negotiated. + + + + Gets or sets the value that should be negotiated. + + + + + The default implementation for a response negotiator. + + + + + Creates a response from a given result and context. + + + + + Negotiates the response based on the given result and context. + + The route result. + The context. + A . + + + + Initializes a new instance of the class. + + The response processors. + The Accept header coercion conventions. + + + + Negotiates the response based on the given result and context. + + The route result. + The context. + A . + + + + Tries to cast the dynamic result to a . + + The result. + The response. + true if the result is a , false otherwise. + + + + Gets a based on the given result and context. + + The route result. + The context. + A . + + + + Gets the coerced accept headers based on the . + + The context. + IEnumerable{Tuple{System.String, System.Decimal}}. + + + + Gets compatible response processors by header. + + The accept header. + The model. + The context. + IEnumerable{Tuple{IResponseProcessor, ProcessorMatch}}. + + + + Creates a response from the compatible headers. + + The compatible headers. + The negotiation context. + The context. + A . + + + + Prioritizes the response processors and tries to negotiate a response. + + The compatible headers. + The negotiation context. + The context. + Response. + + + + Adds a link header to the . + + The compatible headers. + The response. + The request URL. + + + + Gets the link processors based on the compatible headers and content-type. + + The compatible headers. + The content-type of the response. + Dictionary{System.String, MediaRange}. + + + + Creates the link header with the different media ranges. + + The request URL. + The link processors. + The link header. + + + + Adds the content type header from the to the . + + The negotiation context. + The response. + + + + Adds the negotiated headers from the to the . + + The negotiation context. + The response. + + + + Sets the status code from the on the . + + The negotiation context. + The response. + + + + Sets the reason phrase from the on the . + + The negotiation context. + The response. + + + + Adds the cookies from the to the . + + The negotiation context. + The response. + + + + Content negotiation response processor + + + + + Determines whether the processor can handle a given content type and model. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A result that determines the priority of the processor. + + + + Process the response. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A instance. + + + + Gets a set of mappings that map a given extension (such as .json) + to a media range that can be sent to the client in a vary header. + + + + + Processes the model for json media types and extension. + + + + + Initializes a new instance of the class, + with the provided . + + The serializes that the processor will use to process the request. + + + + Determines whether the processor can handle a given content type and model + + Content type requested by the client + The model for the given media range + The nancy context + A ProcessorMatch result that determines the priority of the processor + + + + Process the response + + Content type requested by the client + The model for the given media range + The nancy context + A response + + + + Gets a set of mappings that map a given extension (such as .json) + to a media range that can be sent to the client in a vary header. + + + + + Represents whether a processor has matched/can handle processing the response. + Values are of increasing priority. + + + + + No match, nothing to see here, move along + + + + + Will accept anything + + + + + Matched, but in a non-specific way such as a wildcard match or fallback + + + + + Exact specific match + + + + + Represents a media range from an accept header + + + + + Initializes a new instance of the class from a string representation of a media range + + the content type + + + + Initializes a new instance of the class. + + + + + Whether or not a media range matches another, taking into account wildcards + + Other media range + True if matching, false if not + + + + Whether or not a media range matches another, taking into account wildcards and parameters + + Other media range + True if matching, false if not + + + + Creates a MediaRange from a "Type/SubType" string + + + + + + + Media range type + + + + + Media range subtype + + + + + Media range parameters + + + + + Gets a value indicating if the media range is the */* wildcard + + + + + Provides strongly-typed access to media range parameters. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The parameters. + + + + Returns an enumerator that iterates through the collection. + + A that can be used to iterate through the collection. + + + + Whether or not a set of media range parameters matches another, regardless of order + + Other media range parameters + True if matching, false if not + + + + Returns an enumerator that iterates through a collection. + + An object that can be used to iterate through the collection. + + + + Creates a MediaRangeParameters collection from a "a=1,b=2" string + + + + + + + Gets the names of the available parameters. + + An containing the names of the parameters. + + + + Gets all the parameters values. + + An that contains all the parameters values. + + + + Gets the value for the parameter identified by the parameter. + + The name of the parameter to return the value for. + The value for the parameter. If the parameter is not defined then null is returned. + + + + Represents a media type or subtype in a . + + + + + Initializes a new instance of the class for the media type part. + + + + + + Matched the media type with another media type. + + The media type that should be matched against. + if the media types match, otherwise . + + + + Gets a value indicating whether the media type is a wildcard or not + + if the media type is a wildcard, otherwise . + + + + Context for content negotiation. + + + + + Initializes a new instance of the class. + + + + + Gets the correct model for the given media range + + The to get the model for. + The model for the provided if it has been mapped, otherwise the will be returned. + + + + Gets or sets additional cookies to assign to the response. + + An of instances. + + + + Gets or sets the default model that will be used if a content type specific model is not specified. + + The default model instance. + + + + Gets or sets the additional response headers required. + + An containing the headers. + + + + Gets or sets the model mappings for media ranges. + + An containing the media range model mappings. + + + + The name of the that is locating a view. + + A containing the name of the module. + + + + The module path of the that is locating a view. + + A containing the module path. + + + + Gets or sets allowed media ranges. + + A list of the allowed media ranges. + + + + Gets or sets the status code of the response. + + A value. + + + + Gets or sets a text description of the HTTP status code returned to the client. + + The HTTP status code description. + + + + Gets or sets the view name if one is required. + + The name of the view that should be rendered. + + + + Initializes a new instance of the class, + with the provided . + + The context that should be negotiated. + + + + Gets the used by the negotiator. + + A instance. + + + + Represents whether a processor has matched / can handle a requested response + + + + + A with both and set to . + + + + + Gets or sets the match result based on the content type + + + + + Gets or sets the match result based on the model + + + + + Processes negotiated responses of model type . + + + + + Determines whether the processor can handle a given content type and model. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A result that determines the priority of the processor. + + + + Process the response. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A instance. + + + + Gets a set of mappings that map a given extension (such as .json) + to a media range that can be sent to the client in a vary header. + + + + + Processes the model for view requests. + + + + + Initializes a new instance of the class, + with the provided . + + The view factory that should be used to render views. + + + + Determines whether the processor can handle a given content type and model. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A result that determines the priority of the processor. + + + + Process the response. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A instance. + + + + Gets a set of mappings that map a given extension (such as .json) + to a media range that can be sent to the client in a vary header. + + + + + Processes the model for xml media types and extension. + + + + + Initializes a new instance of the class, + with the provided . + + The serializes that the processor will use to process the request. + + + + Determines whether the processor can handle a given content type and model. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A result that determines the priority of the processor. + + + + Process the response. + + Content type requested by the client. + The model for the given media range. + The nancy context. + A instance. + + + + Gets a set of mappings that map a given extension (such as .json) + to a media range that can be sent to the client in a vary header. + + + + + Response with status code 406 (Not Acceptable). + + + + + Initializes a new instance of the class. + + + + + Response that returns the contents of a stream of a given content-type. + + + + + Initializes a new instance of the class with the + provided stream provider and content-type. + + The value producer for the response. + The content-type of the stream contents. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + + + + To close the unclosable stream.. + To fight the unbeatable foe.. + To bear with unbearable sorrow.. + To run where the brave dare not go.. + + + + + The wrapped stream + + + + + Initializes a new instance of the class. + + The base stream to wrap. + + + + Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + + 1 + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device. + + An I/O error occurs. 2 + + + + When overridden in a derived class, sets the position within the current stream. + + + The new position within the current stream. + + A byte offset relative to the parameter. A value of type indicating the reference point used to obtain the new position. An I/O error occurs. The stream does not support seeking, such as if the stream is constructed from a pipe or console output. Methods were called after the stream was closed. 1 + + + + When overridden in a derived class, sets the length of the current stream. + + The desired length of the current stream in bytes. An I/O error occurs. The stream does not support both writing and seeking, such as if the stream is constructed from a pipe or console output. Methods were called after the stream was closed. 2 + + + + When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + + + The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + + An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. The zero-based byte offset in at which to begin storing the data read from the current stream. The maximum number of bytes to be read from the current stream. The sum of and is larger than the buffer length. is null. or is negative. An I/O error occurs. The stream does not support reading. Methods were called after the stream was closed. 1 + + + + When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + + An array of bytes. This method copies bytes from to the current stream. The zero-based byte offset in at which to begin copying bytes to the current stream. The number of bytes to be written to the current stream. The sum of and is greater than the buffer length. is null. or is negative. An I/O error occurs. The stream does not support writing. Methods were called after the stream was closed. 1 + + + + Begins an asynchronous read operation. + + + An that represents the asynchronous read, which could still be pending. + + The buffer to read the data into. The byte offset in at which to begin writing data read from the stream. The maximum number of bytes to read. An optional asynchronous callback, to be called when the read is complete. A user-provided object that distinguishes this particular asynchronous read request from other requests. Attempted an asynchronous read past the end of the stream, or a disk error occurs. One or more of the arguments is invalid. Methods were called after the stream was closed. The current Stream implementation does not support the read operation. 2 + + + + Begins an asynchronous write operation. + + + An IAsyncResult that represents the asynchronous write, which could still be pending. + + The buffer to write data from. The byte offset in from which to begin writing. The maximum number of bytes to write. An optional asynchronous callback, to be called when the write is complete. A user-provided object that distinguishes this particular asynchronous write request from other requests. Attempted an asynchronous write past the end of the stream, or a disk error occurs. One or more of the arguments is invalid. Methods were called after the stream was closed. The current Stream implementation does not support the write operation. 2 + + + + Waits for the pending asynchronous read to complete. + + + The number of bytes read from the stream, between zero (0) and the number of bytes you requested. Streams return zero (0) only at the end of the stream, otherwise, they should block until at least one byte is available. + + The reference to the pending asynchronous request to finish. is null. did not originate from a method on the current stream. The stream is closed or an internal error has occurred.2 + + + + Ends an asynchronous write operation. + + A reference to the outstanding asynchronous I/O request. is null. did not originate from a method on the current stream. The stream is closed or an internal error has occurred.2 + + + + Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. + + + The unsigned byte cast to an Int32, or -1 if at the end of the stream. + + The stream does not support reading. Methods were called after the stream was closed. 2 + + + + Writes a byte to the current position in the stream and advances the position within the stream by one byte. + + The byte to write to the stream. An I/O error occurs. The stream does not support writing, or the stream is already closed. Methods were called after the stream was closed. 2 + + + + Releases the unmanaged resources used by the and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Gets the base stream that the wrapper is wrapping + + + + + When overridden in a derived class, gets a value indicating whether the current stream supports reading. + + + true if the stream supports reading; otherwise, false. + + 1 + + + + When overridden in a derived class, gets a value indicating whether the current stream supports seeking. + + + true if the stream supports seeking; otherwise, false. + + 1 + + + + When overridden in a derived class, gets a value indicating whether the current stream supports writing. + + + true if the stream supports writing; otherwise, false. + + 1 + + + + When overridden in a derived class, gets the length in bytes of the stream. + + + A long value representing the length of the stream in bytes. + + A class derived from Stream does not support seeking. Methods were called after the stream was closed. 1 + + + + When overridden in a derived class, gets or sets the position within the current stream. + + + The current position within the stream. + + An I/O error occurs. The stream does not support seeking. Methods were called after the stream was closed. 1 + + + + Gets a value that determines whether the current stream can time out. + + + A value that determines whether the current stream can time out. + + 2 + + + + Gets or sets a value, in milliseconds, that determines how long the stream will attempt to read before timing out. + + + A value, in milliseconds, that determines how long the stream will attempt to read before timing out. + + The method always throws an . 2 + + + + Gets or sets a value, in milliseconds, that determines how long the stream will attempt to write before timing out. + + + A value, in milliseconds, that determines how long the stream will attempt to write before timing out. + + The method always throws an . 2 + + + + Whether the serializer can serialize the content type + + Content type to serialise + True if supported, false otherwise + + + + Serialize the given model with the given contentType + + Content type to serialize into + Model to serialize + Output stream to serialize to + Serialised object + + + + Gets the list of extensions that the serializer can handle. + + An of extensions if any are available, otherwise an empty enumerable. + + + + Json serializer settings + + + + + Max length of json output + + + + + Maximum number of recursions + + + + + Default charset for json responses. + + + + + Set to true to retain the casing used in the C# code in produced JSON. + Set to false to use camelCasing in the produced JSON. + False by default. + + + + + Serialized date format + + + + + Whether the serializer can serialize the content type + + Content type to serialise + True if supported, false otherwise + + + + Serialize the given model with the given contentType + + Content type to serialize into + Model to serialize + Stream to serialize to + Serialised object + + + + Attempts to detect if the content type is JSON. + Supports: + application/json + text/json + application/vnd[something]+json + Matches are case insentitive to try and be as "accepting" as possible. + + Request content type + True if content type is JSON, false otherwise + + + + Gets the list of extensions that the serializer can handle. + + An of extensions if any are available, otherwise an empty enumerable. + + + + Set to true to retain the casing used in the C# code in produced JSON. + Set to false to use camelCasig in the produced JSON. + False by default. + + + + + Set to true to use the ISO8601 format for datetimes in produced JSON. + Set to false to use the WCF \/Date()\/ format in the produced JSON. + True by default. + + + + + Whether the serializer can serialize the content type + + Content type to serialise + True if supported, false otherwise + + + + Serialize the given model with the given contentType + + Content type to serialize into + Model to serialize + Output stream to serialize to + Serialised object + + + + Gets the list of extensions that the serializer can handle. + + An of extensions if any are available, otherwise an empty enumerable. + + + + Represents a text (text/plain) response + + + + + Creates a new instance of the TextResponse class + + Text content - defaults to empty if null + Content Type - defaults to text/plain + String encoding - UTF8 if null + + + + Creates a new instance of the TextResponse class + + Status code - defaults to OK + Text content - defaults to empty if null + String encoding - UTF8 if null + Headers if required + Cookies if required + + + + Constraint for alphabetical route segments. + + + + + Convenience class for implementing a route segment constraint. + + The type of parameter to capture. + + + + Defines the functionality to constrain route matching. + + + + + Determines whether the given constraint should be matched. + + The route constraint. + true if the constraint matches, false otherwise. + + + + Matches the segment and parameter name against the constraint. + + The constraint. + The segment. + Name of the parameter. + A containing information about the captured parameters. + + + + Tries to match the given segment against the constraint. + + The constraint. + The segment to match. + The matched value. + true if the segment matches the constraint, false otherwise. + + + + Gets the name of the constraint, i.e. "int". + + The constraint's name. + + + + Constraint for route segments. + + + + + Constraint for route segments with custom format. + + + + + Convenience class for implementing a route segment constraint that expects parameters. + + The type of parameter to capture. + + + + Tries to parse an integer using . + + The string value. + The resulting integer. + true if the parsing was successful, false otherwise. + + + + Tries to match the given segment and parameters against the constraint. + + The segment to match. + The parameters to match. + The matched value. + true if the segment and parameters matches the constraint, false otherwise. + + + + Constraint for route segments. + + + + + Constraint for route segments. + + + + + Constraint for route segments. + + + + + Constraint for route segments. + + + + + Constraint for route segments. + + + + + Constraint for route segments with a specific length. + + + + + Constraint for route segments with a maximum length. + + + + + Constraint for route segments with a maximum value. + + + + + Constraint for route segments with a minimum length. + + + + + Constraint for route segments with a minimum length. + + + + + Constraint for route segments with value within a specified range. + + + + + Constraint for version route segments. + + + + + Default implementation of a request dispatcher. + + + + + Functionality for processing an incoming request. + + + + + Dispatches a requests. + + The for the current request. + Cancellation token + + + + Initializes a new instance of the class, with + the provided , and . + + + + + + + + Dispatches a requests. + + The for the current request. + + + + Default implementation of the interface. Will look for + route descriptions in resource files. The resource files should have the same name as the module + for which it defines routes. + + + + + Defines the functionality for retrieving a description for a specific route. + + + + + Get the description for a route. + + The module that the route is defined in. + The path of the route that the description should be retrieved for. + A containing the description of the route if it could be found, otherwise . + + + + Get the description for a route. + + The module that the route is defined in. + The path of the route that the description should be retrieved for. + A containing the description of the route if it could be found, otherwise . + + + + Default route invoker implementation. + + + + + Defines the functionality for invoking a and returning a + + + + + Invokes the specified with the provided . + + The route that should be invoked. + Cancellation token + The parameters that the route should be invoked with. + The context of the route that is being invoked. + A instance that represents the result of the invoked route. + + + + Initializes a new instance of the class. + + The response negotiator. + + + + Invokes the specified with the provided . + + The route that should be invoked. + Cancellation token + The parameters that the route should be invoked with. + The context of the route that is being invoked. + A instance that represents the result of the invoked route. + + + + Default implementation of the interface. + + + + + Defines the functionality for extracting the individual segments from a route path. + + + + + Extracts the segments from the ; + + The path that the segments should be extracted from. + An , containing the extracted segments. + + + + Extracts the segments from the ; + + The path that the segments should be extracted from. + An , containing the extracted segments. + + + + Defines the functionality for retrieving metadata for routes. + + + + + Gets the of the metadata that is created by the provider. + + The instance that the route is declared in. + A for the route. + A instance, or if nothing is found. + + + + Gets the metadata for the provided route. + + The instance that the route is declared in. + A for the route. + An object representing the metadata for the given route, or if nothing is found. + + + + Information about a segment parameter. + + + + + Initializes a new instance of the class. + + The name of the parameter + The default value, if any, of the parameter. + if the parameter is optional, otherwise . + + + + Gets the default value for the parameter. + + + + + Gets the full name of the segment. + + Returns a string in one of the formats: {name}, {name?}, {name?defaultValue} depending on the kind of parameter. + + + + Gets whether or not the parameter is optional. + + if the parameter is optional, otherwise . + + + + Gets the name of the parameter. + + + + + A class representing a route resolution result + + + + + Gets or sets the route + + + + + Gets or sets the captured parameters + + + + + Gets or sets the before module pipeline + + + + + Gets or sets the after module pipeline + + + + + Gets or sets the on error module pipeline + + + + + Route that is returned when the path could be matched but, the method was OPTIONS and there was no user defined handler for OPTIONS. + + + + + Stores information about a declared route in Nancy. + + + + + Initializes a new instance of the type, with the specified . + + + The action that should take place when the route is invoked. + + + + Initializes a new instance of the type, with the specified definition. + + Route name + The HTTP method that the route is declared for. + The path that the route is declared for. + A condition that needs to be satisfied inorder for the route to be eligible for invocation. + The action that should take place when the route is invoked. + + + + Initializes a new instance of the type, with the specified definition. + + The HTTP method that the route is declared for. + The path that the route is declared for. + A condition that needs to be satisfied inorder for the route to be eligiable for invocation. + The action that should take place when the route is invoked. + + + + Invokes the route with the provided . + + A that contains the parameters that should be passed to the route. + Cancellation token + A (hot) task of instance. + + + + Creates a route from a sync delegate signature + + + The action that should take place when the route is invoked. + A Route instance + + + + Creates a route from a sync delegate signature + + The HTTP method that the route is declared for. + The path that the route is declared for. + A condition that needs to be satisfied inorder for the route to be eligiable for invocation. + The action that should take place when the route is invoked. + A Route instance + + + + Creates a route from a sync delegate signature + + Route name + The HTTP method that the route is declared for. + The path that the route is declared for. + A condition that needs to be satisfied inorder for the route to be eligible for invocation. + The action that should take place when the route is invoked. + A Route instance + + + + Wraps a sync delegate in a delegate that returns a task + + Sync delegate + Task wrapped version + + + + Gets or sets the action that should take place when the route is invoked. + + A that represents the action of the route. + + + + Gets the description of the route. + + A instance. + + + + Contains extensions for the type. + + + + + Retrieves metadata for all declared routes. + + The type of the metadata to retrieve. + The to retrieve the metadata. + An containing instances of the type. + + + + Stores metadata created by instances. + + + + + Creates a new instance of the class. + + An containing the metadata, organised by the type that it is stored in. + + + + Gets a boolean that indicates if the specific type of metadata is stored. + + The type of the metadata to check for. + if metadata, of the requested type is stored, otherwise . + + + + Retrieves metadata of the provided type. + + The type of the metadata to retrieve. + The metadata instance if available, otherwise . + + + + Gets the raw metadata . + + An instance. + + + + Defines the functionality for retrieving metadata for routes. + + The metadata type. + + + + Gets the of the metadata that is created by the provider. + + The instance that the route is declared in. + A for the route. + A instance, or null if none are found. + + + + Gets the metadata for the provided route. + + The instance that the route is declared in. + A for the route. + An instance of . + + + + Gets the metadata for the provided route. + + The instance that the route is declared in. + A for the route. + An instance of . + + + + Trie structure for resolving routes + + + + + Build the trie from the route cache + + The route cache + + + + Get all matches for the given method and path + + HTTP method + Requested path + Current Nancy context + An array of elements + + + + Get all method options for the given path + + Requested path + Current Nancy context + A collection of strings, each representing an allowed method + + + + Factory for creating trie nodes from route definition segments + + + + + Gets the correct Trie node type for the given segment + + Parent node + Segment + Corresponding TrieNode instance + + + + Match result for a matched route + + + + + Represents a route that ends at a particular node. + We store/calculate as much as we can at build time to save + time during route matching. + + + + + Gets or sets the module type from the matching module + + + + + Gets or sets the route method + + + + + Gets or sets the index in the module routing table + + + + + Gets or sets the number of segments in the route + + + + + Gets or sets the route score + + + + + Gets or sets the route condition delegate + + + + + Compares the current object with another object of the same type. + + + A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the parameter.Zero This object is equal to . Greater than zero This object is greater than . + + An object to compare with this object. + + + + Gets or sets the captured parameters + + + + + Gets the "no match" + + + + + Gets the "no matches" collection + + + + + Helpers methods for NodeData + + + + + Converts a instance into a + + Node data + Captured parameters + A instance + + + + A node for standard captures e.g. {foo} + + + + + A base class representing a node in the route trie + + + + + Initializes a new instance of the class + + Parent node + Segment of the route definition + Factory for creating new nodes + + + + Add a new route to the trie + + The segments of the route definition + The module key the route comes from + The route index in the module + The route description + + + + Add a new route to the trie + + The segments of the route definition + Current index in the segments array + Current score for this route + Number of nodes added for this route + The module key the route comes from + The route index in the module + The route description + + + + Gets all matches for a given requested route + + Requested route segments + Current Nancy context + A collection of objects + + + + Gets all matches for a given requested route + + Requested route segments + Current index in the route segments + Currently captured parameters + Current Nancy context + A collection of objects + + + + Gets a string representation of all routes + + Collection of strings, each representing a route + + + + Build the node data that will be used to create the + We calculate/store as much as possible at build time to reduce match time. + + Number of nodes in the route + Score for the route + The module key the route comes from + The route index in the module + The route description + A NodeData instance + + + + Returns whether we are at the end of the segments + + Route segments + Current index + True if no more segments left, false otherwise + + + + Build the results collection from the captured parameters if + this node is the end result + + Currently captured parameters + Parameters captured by the local matching + Array of objects corresponding to each set of stored at this node + + + + Gets all the matches from this node's children + + Requested route segments + Current index + Currently captured parameters + Parameters captured by the local matching + Current Nancy context + Collection of objects + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Gets or sets the parent node + + + + + Gets or sets the segment from the route definition that this node represents + + + + + Gets or sets the children of this node + + + + + Gets or sets the node data stored at this node, which will be converted + into the if a match is found + + + + + Additional parameters to set that can be determined at trie build time + + + + + Score for this node + + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + A node for constraint captures e.g. {foo:alpha}, {foo:datetime} + + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + A capture node with a default value e.g. {foo?default} + + + + + Add a new route to the trie + Adds itself as a normal capture node, but also sets a default capture + on the parent and adds this node's children as children of the parent + too (so it can effectively be "skipped" during matching) + + The segments of the route definition + Current index in the segments array + Current score for this route + Number of nodes added for this route + The module key the route comes from + The route index in the module + The route description + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + A node multiple standard captures combined with a literal e.g. {id}.png.{thing}.{otherthing} + + + + + Captures parameters within segments that contain literals. + i.e: + /{file}.{name} + /{file}.html + /{major}.{minor}.{revision}B{build} + + The parent node + The segment to match upon + The factory + + + + + Determines whether this TrieNode should be used for the given segment. + + The route segment + a boolean + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Extracts the parameter name and the literals for the segment + + + + + Score for this node + + + + + A greedy regular expression capture node e.g. ^(?<id>\d{0,100})$ + For use on an entire route path, regular expression must be surrounded by ^( )$ + e.g. @"^(?:(?<id>videos/\d{1,10})(?:/{0,1}(?<slug>.*)))$" + This will match for a Url like /videos/123/some-random-slug + and capture 'videos/123' and 'some-random-slug' + + + + + Gets all matches for a given requested route + Overridden to handle greedy capturing + + Requested route segments + Current index in the route segments + Currently captured parameters + Current Nancy context + A collection of objects + + + + Matches the segment for a requested route + Not-required or called for this node type + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + A greedy capture node e.g. {greedy*} + e.g. /foo/bar/{greedy*} - this node will be hit for /foo/bar/[anything that doesn't match another route], but + not for just /foo/bar + e.g. /foo/{greedy*}/bar - this node will be hit for /foo/[anything that doesn't match another route]/bar + + + + + Gets all matches for a given requested route + Overridden to handle greedy capturing + + Requested route segments + Current index in the route segments + Currently captured parameters + Current Nancy context + A collection of objects + + + + Matches the segment for a requested route + Not-required or called for this node type + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + Literal string node e.g. goo + + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + An optional capture node e.g. {foo?} + + + + + Add a new route to the trie + Adds itself as a normal capture node, but also adds this node's + children as children of the parent too + (so it can effectively be "skipped" during matching) + + The segments of the route definition + Current index in the segments array + Current score for this route + Number of nodes added for this route + The module key the route comes from + The route index in the module + The route description + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + A regular expression capture node e.g. (?<foo>\d{2,4}) + + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + Root node of a trie + + + + + Gets all matches for a given requested route + + Requested route segments + Current index in the route segments + Currently captured parameters + Current Nancy context + A collection of objects + + + + Matches the segment for a requested route + + Segment string + A instance representing the result of the match + + + + Score for this node + + + + + The default route resolution trie + + + + + Build the trie from the route cache + + The route cache + + + + Get all matches for the given method and path + + HTTP method + Requested path + Current Nancy context + An array of elements + + + + Get all method options for the given path + + Requested path + Current Nancy context + A collection of strings, each representing an allowed method + + + + Returns a string that represents the current object. + + + A string that represents the current object. + + 2 + + + + A segment match result + + + + + Gets a value indicating whether the match was successful or not + + + + + Gets a representing "no match" + + + + + Gets the captured parameters from the match, if the match was successful + + + + + Factory for creating the correct type of TrieNode + + + + + Gets the correct Trie node type for the given segment + + Parent node + Segment + TrieNode instance + + + + Allows a BeforeRequest hook to change Url to HTTPS if X-Forwarded-Proto header present + + + + + Checks for Forwarded or X-Forwarded-Proto header and if so makes current url scheme https + + Application pipelines + + + + Configuration options for cookie based sessions + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + + + + Gets or sets the cryptography configuration + + + + + Formatter for de/serializing the session objects + + + + + Cookie name for storing session information + + + + + Gets or sets the domain of the session cookie + + + + + Gets or sets the path of the session cookie + + + + + Gets a value indicating whether the configuration is valid or not. + + + + + Registers the static contents hook in the application pipeline at startup. + + + + + Initializes a new instance of the class, using the + provided and . + + The current root path provider. + The static content conventions. + + + + Perform any initialisation tasks + + + + + Enable "manual" static content. + Only use this if you want to manually configure a pipeline hook to have static + content server, for example, after authentication. + + The pipelines to hook into + + + + This is a wrapper around the type + IEnumerable<Func<string, object, ViewLocationContext, string>> and its + only purpose is to make Ninject happy which was throwing an exception + when constructor injecting this type. + + + + + Calculates how long a byte array of X length will be after base64 encoding + + The normal, 8bit per byte, length of the byte array + Base64 encoded length + + + + Cryptographic setup for classes that use encryption and HMAC + + + + + Creates a new instance of the CryptographyConfiguration class + + Encryption provider + HMAC provider + + + + Gets the default configuration - Rijndael encryption, HMACSHA256 HMAC, random keys + + + + + Gets configuration with no encryption and HMACSHA256 HMAC with a random key + + + + + Gets the encryption provider + + + + + Gets the hmac provider + + + + + Provides SHA-256 HMACs + + + + + Creates Hash-based Message Authentication Codes (HMACs) + + + + + Create a hmac from the given data + + Data to create hmac from + Hmac bytes + + + + Create a hmac from the given data + + Data to create hmac from + Hmac bytes + + + + Gets the length of the HMAC signature in bytes + + + + + Preferred key size for HMACSHA256 + + + + + HMAC length + + + + + Key + + + + + Creates a new instance of the DefaultHmacProvider type + + Key generator to use to generate the key + + + + Create a hmac from the given data using the given passPhrase + + Data to create hmac from + String representation of the hmac + + + + Create a hmac from the given data + + Data to create hmac from + Hmac bytes + + + + Gets the length of the HMAC signature + + + + + Compare two hmac byte arrays without any early exits + + First hmac + Second hmac + Expected length of the hash + True if equal, false otherwise + + + + Provides key byte generation + + + + + Generate a sequence of bytes + + Number of bytes to return + Array bytes + + + + A "no op" encryption provider + Useful for debugging or performance. + + + + + Provides symmetrical encryption support + + + + + Encrypt and base64 encode the string + + Data to encrypt + Encrypted string + + + + Decrypt string + + Data to decrypt + Decrypted string + + + + Encrypt data + + Data to encrypt + Encrypted string + + + + Decrypt string + + Data to decrypt + Decrypted string + + + + Provides key generation using PBKDF2 / Rfc2898 + NOTE: the salt is static so the passphrase should be long and complex + (As the bytes are generated at app startup, because it's too slow to do per + request, so the salt cannot be randomly generated and stored) + + + + + Initializes a new instance of the class, with + the provided , and optional + number of + + The passphrase that should be used. + The salt + The number of iterations. The default value is 10000. + + + + Generate a sequence of bytes + + Number of bytes to return + Array bytes + + + + Generates random secure keys using RNGCryptoServiceProvider + + + + + Creates NancyContext instances + + + + + Creates NancyContext instances + + + + + Create a new NancyContext + + NancyContext instance + + + + Creates a new instance of the class. + + An instance. + An instance. + An instance. + + + + Create a new instance. + + A instance. + + + + The default implementation of the interface. + + + + + Gets the generic item store. + + An instance containing the items. + + + + Gets or sets the information about the request. + + An instance. + + + + Gets or sets the information about the response. + + An instance. + + + + Gets or sets the trace log. + + A instance. + + + + Initializes a new instance of the class. + + The value to store in the instance + + + + Returns a default value if Value is null + + When no default value is supplied, required to supply the default type + Optional parameter for default value, if not given it returns default of type T + If value is not null, value is returned, else default value is returned + + + + Attempts to convert the value to type of T, failing to do so will return the defaultValue. + + When no default value is supplied, required to supply the default type + Optional parameter for default value, if not given it returns default of type T + If value is not null, value is returned, else default value is returned + + + + Indicates whether the current object is equal to another object of the same type. + + true if the current object is equal to the parameter; otherwise, false. + + An to compare with this instance. + + + + Determines whether the specified is equal to the current . + + true if the specified is equal to the current ; otherwise, false. + The to compare with the current . + + + + Serves as a hash function for a particular type. + + A hash code for the current instance. + + + + Provides implementation for binary operations. Classes derived from the class can override this method to specify dynamic behavior for operations such as addition and multiplication. + + true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) + Provides information about the binary operation. The binder.Operation property returns an object. For example, for the sum = first + second statement, where first and second are derived from the DynamicObject class, binder.Operation returns ExpressionType.Add.The right operand for the binary operation. For example, for the sum = first + second statement, where first and second are derived from the DynamicObject class, is equal to second.The result of the binary operation. + + + + Provides implementation for type conversion operations. Classes derived from the class can override this method to specify dynamic behavior for operations that convert an object from one type to another. + + true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) + Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted. For example, for the statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic), where sampleObject is an instance of the class derived from the class, binder.Type returns the type. The binder.Explicit property provides information about the kind of conversion that occurs. It returns true for explicit conversion and false for implicit conversion.The result of the type conversion operation. + + + + Returns the for this instance. + + + The enumerated constant that is the of the class or value type that implements this interface. + + 2 + + + + Converts the value of this instance to an equivalent Boolean value using the specified culture-specific formatting information. + + + A Boolean value equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent Unicode character using the specified culture-specific formatting information. + + + A Unicode character equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 8-bit signed integer using the specified culture-specific formatting information. + + + An 8-bit signed integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 8-bit unsigned integer using the specified culture-specific formatting information. + + + An 8-bit unsigned integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 16-bit signed integer using the specified culture-specific formatting information. + + + An 16-bit signed integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 16-bit unsigned integer using the specified culture-specific formatting information. + + + An 16-bit unsigned integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 32-bit signed integer using the specified culture-specific formatting information. + + + An 32-bit signed integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 32-bit unsigned integer using the specified culture-specific formatting information. + + + An 32-bit unsigned integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 64-bit signed integer using the specified culture-specific formatting information. + + + An 64-bit signed integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent 64-bit unsigned integer using the specified culture-specific formatting information. + + + An 64-bit unsigned integer equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent single-precision floating-point number using the specified culture-specific formatting information. + + + A single-precision floating-point number equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent double-precision floating-point number using the specified culture-specific formatting information. + + + A double-precision floating-point number equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent number using the specified culture-specific formatting information. + + + A number equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent using the specified culture-specific formatting information. + + + A instance equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an equivalent using the specified culture-specific formatting information. + + + A instance equivalent to the value of this instance. + + An interface implementation that supplies culture-specific formatting information. 2 + + + + Converts the value of this instance to an of the specified that has an equivalent value, using the specified culture-specific formatting information. + + + An instance of type whose value is equivalent to the value of this instance. + + The to which the value of this instance is converted. An interface implementation that supplies culture-specific formatting information. 2 + + + + Gets a value indicating whether this instance has value. + + true if this instance has value; otherwise, false. + is considered as not being a value. + + + + Gets the inner value + + + + + Default error handler + + + + + Provides informative responses for particular HTTP status codes + + + + + Check if the error handler can handle errors of the provided status code. + + Status code + The instance of the current request. + True if handled, false otherwise + + + + Handle the error code + + Status code + Current context + + + + Initializes a new instance of the type. + + + + + Whether then + + Status code + The instance of the current request. + True if handled, false otherwise + + + + Handle the error code + + Status code + The instance of the current request. + Nancy Response + + + + + A simple pipeline for on-error hooks. + Hooks will be executed until either a hook returns a response, or every + hook has been executed. + + + Can be implictly cast to/from the on-error hook delegate signature + (Func NancyContext, Exception, Response) for assigning to NancyEngine or for building + composite pipelines. + + + + + + Pipeline items to execute + + + + + Add an item to the start of the pipeline + + Item to add + + + + Add an item to the start of the pipeline + + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Add an item to the end of the pipeline + + Item to add + + + + Add an item to the end of the pipeline + + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Add an item to a specific place in the pipeline. + + Index to add at + Item to add + + + + Add an item to a specific place in the pipeline. + + Index to add at + Item to add + + Whether to replace an existing item with the same name in its current place, + rather than at the position requested. Defaults to false. + + + + + Insert an item before a named item. + If the named item does not exist the item is inserted at the start of the pipeline. + + Name of the item to insert before + Item to insert + + + + Insert an item before a named item. + If the named item does not exist the item is inserted at the start of the pipeline. + + Name of the item to insert before + Item to insert + + + + Insert an item after a named item. + If the named item does not exist the item is inserted at the end of the pipeline. + + Name of the item to insert after + Item to insert + + + + Insert an item after a named item. + If the named item does not exist the item is inserted at the end of the pipeline. + + Name of the item to insert after + Item to insert + + + + Remove a named pipeline item + + Name + Index of item that was removed or -1 if nothing removed + + + + Gets the current pipeline items + + + + + Gets the current pipeline item delegates + + + + + Invoke the pipeline. Each item will be invoked in turn until either an + item returns a Response, or all items have been invoked. + + + The current context to pass to the items. + + + The exception currently being handled by the error pipeline + + + Response from an item invocation, or null if no response was generated. + + + + + Assembly extension methods + + + + + Gets exported types from an assembly and catches common errors + that occur when running under test runners. + + Assembly to retrieve from + An array of types + + + + Bootstrapper for the Nancy Engine + + + + + Initialise the bootstrapper. Must be called prior to GetEngine. + + + + + Gets the configured INancyEngine + + Configured INancyEngine + + + + Represents a module type for registration into a container + + Type of the module + + + + Nancy bootstrapper base class + + IoC container type + + + + Stores whether the bootstrapper has been initialised + prior to calling GetEngine. + + + + + Stores whether the bootstrapper is in the process of + being disposed. + + + + + Stores the used by Nancy + + + + + Default Nancy conventions + + + + + Internal configuration + + + + + Nancy modules - built on startup from the app domain scanner + + + + + Initializes a new instance of the class. + + + + + Initialise the bootstrapper. Must be called prior to GetEngine. + + + + + Gets the diagnostics for initialisation + + IDiagnostics implementation + + + + Gets all registered application startup tasks + + An instance containing instances. + + + + Registers and resolves all request startup tasks + + Container to use + Types to register + An instance containing instances. + + + + Gets all registered application registration tasks + + An instance containing instances. + + + + Get all NancyModule implementation instances + + The current context + An instance containing instances. + + + + Retrieves a specific implementation - should be per-request lifetime + + Module type + The current context + The instance + + + + Gets the configured INancyEngine + + Configured INancyEngine + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Hides Equals from the overrides list + + Object to compare + Boolean indicating equality + + + + Hides GetHashCode from the overrides list + + Hash code integer + + + + Creates and initializes the request pipelines. + + The used by the request. + An instance. + + + + Hides ToString from the overrides list + + String representation + + + + Initialise the bootstrapper - can be used for adding pre/post hooks and + any other initialisation tasks that aren't specifically container setup + related + + Container instance for resolving types if required. + + + + Initialise the request - can be used for adding pre/post hooks and + any other per-request initialisation tasks that aren't specifically container setup + related + + Container + Current pipelines + Current context + + + + Configure the application level container with any additional registrations. + + Container instance + + + + Overrides/configures Nancy's conventions + + Convention object instance + + + + Resolve INancyEngine + + INancyEngine implementation + + + + Gets the application level container + + Container instance + + + + Register the bootstrapper's implemented types into the container. + This is necessary so a user can pass in a populated container but not have + to take the responsibility of registering things like INancyModuleCatalog manually. + + Application container to register into + + + + Register the default implementations of internally used types into the container as singletons + + Container to register into + Type registrations to register + + + + Register the various collections into the container as singletons to later be resolved + by IEnumerable{Type} constructor dependencies. + + Container to register into + Collection type registrations to register + + + + Register the given module types into the container + + Container to register into + NancyModule types + + + + Register the given instances into the container + + Container to register into + Instance registration types + + + + Gets additional required type registrations + that don't form part of the core Nancy configuration + + Collection of TypeRegistration types + + + + Gets any additional instance registrations that need to + be registered into the container + + Collection of InstanceRegistration types + + + + Creates a list of types for the collection types that are + required to be registered in the application scope. + + Collection of CollectionTypeRegistration types + + + + Takes the registration tasks and calls the relevant methods to register them + + Registration tasks + + + + Application pipelines. + Pipelines are "cloned" per request so they can be modified + at the request level. + + + + + Cache of request startup task types + + + + + Gets the Container instance - automatically set during initialise. + + + + + Nancy internal configuration + + + + + Nancy conventions + + + + + Gets all available module types + + + + + Gets the available view engine types + + + + + Gets the available custom model binders + + + + + Gets the available custom type converters + + + + + Gets the available custom body deserializers + + + + + Gets all application startup tasks + + + + + Gets all request startup tasks + + + + + Gets all registration tasks + + + + + Gets the root path provider + + + + + Gets the validator factories. + + + + + Gets the default favicon + + + + + Gets the cryptography configuration + + + + + Gets the diagnostics / dashboard configuration (password etc) + + + + + Class for locating an INancyBootstrapper implementation. + + Will search the app domain for a non-abstract one, and if it can't find one + it will use the default nancy one that uses TinyIoC. + + + + + Gets the located bootstrapper + + + + + Represents a type to be registered into the container + + + + + Represents a type to be registered into the container + + Registration type i.e. IMyInterface + Implementation type i.e. MyClassThatImplementsIMyInterface + Lifetime to register the type as + + + + Implementation type i.e. MyClassThatImplementsIMyInterface + + + + + Default cookie implementation for Nancy. + + + + + The domain to restrict the cookie to + + + + + When the cookie should expire + + A instance containing the date and time when the cookie should expire; otherwise if it should expire at the end of the session. + + + + The name of the cookie + + + + + Gets the encoded name of the cookie + + + + + The path to restrict the cookie to + + + + + The value of the cookie + + + + + Gets the encoded value of the cookie + + + + + Whether the cookie is http only + + + + + Whether the cookie is secure (i.e. HTTPS only) + + + + + Initializes a new instance of the class. + + The name of the cookie. + The value of the cookie. + + + + Initializes a new instance of the class. + + The name of the cookie. + The value of the cookie. + The expiration date of the cookie. Can be if it should expire at the end of the session. + + + + Initializes a new instance of the class. + + The name of the cookie. + The value of the cookie. + Whether the cookie is http only. + + + + Initializes a new instance of the class. + + The name of the cookie. + The value of the cookie. + Whether the cookie is http only. + Whether the cookie is secure (i.e. HTTPS only). + + + + Initializes a new instance of the class. + + The name of the cookie. + The value of the cookie. + Whether the cookie is http only. + Whether the cookie is secure (i.e. HTTPS only). + The expiration date of the cookie. Can be if it should expire at the end of the session. + + + + The domain to restrict the cookie to + + + + + When the cookie should expire + + A instance containing the date and time when the cookie should expire; otherwise if it should expire at the end of the session. + + + + The name of the cookie + + + + + Gets the encoded name of the cookie + + + + + The path to restrict the cookie to + + + + + The value of the cookie + + + + + Gets the encoded value of the cookie + + + + + Whether the cookie is http only + + + + + Whether the cookie is secure (i.e. HTTPS only) + + + + + TinyIoC bootstrapper - registers default route resolver and registers itself as + INancyModuleCatalog for resolving modules but behaviour can be overridden if required. + + + + + Nancy bootstrapper base with per-request container support. + Stores/retrieves the child container in the context to ensure that + only one child container is stored per request, and that the child + container will be disposed at the end of the request. + + IoC container type + + + + Context key for storing the child container in the context + + + + + Stores the module registrations to be registered into the request container + + + + + Get all implementation instances + + The current context + An instance containing instances. + + + + Retrieves a specific implementation - should be per-request lifetime + + Module type + The current context + The instance + + + + Creates and initializes the request pipelines. + + The used by the request. + An instance. + + + + Takes the registration tasks and calls the relevant methods to register them + + Registration tasks + + + + Gets the per-request container + + Current context + Request container instance + + + + Configure the request container + + Request container instance + + + + + Register the given module types into the container + + Container to register into + NancyModule types + + + + Creates a per request child/nested container + + Current context + Request container instance + + + + Register the given module types into the request container + + Container to register into + NancyModule types + + + + Retrieve all module instances from the container + + Container to use + Collection of NancyModule instances + + + + Retrieve a specific module instance from the container + + Container to use + Type of the module + NancyModule instance + + + + Stores the per-request type registrations + + + + + Stores the per-request collection registrations + + + + + Gets the context key for storing the child container in the context + + + + + Default assemblies that are ignored for autoregister + + + + + Configures the container using AutoRegister followed by registration + of default INancyModuleCatalog and IRouteResolver. + + Container instance + + + + Resolve INancyEngine + + INancyEngine implementation + + + + Create a default, unconfigured, container + + Container instance + + + + Register the bootstrapper's implemented types into the container. + This is necessary so a user can pass in a populated container but not have + to take the responsibility of registering things like INancyModuleCatalog manually. + + Application container to register into + + + + Register the default implementations of internally used types into the container as singletons + + Container to register into + Type registrations to register + + + + Register the various collections into the container as singletons to later be resolved + by IEnumerable{Type} constructor dependencies. + + Container to register into + Collection type registrations to register + + + + Register the given module types into the container + + Container to register into + NancyModule types + + + + Register the given instances into the container + + Container to register into + Instance registration types + + + + Creates a per request child/nested container + + Current context + Request container instance + + + + Gets the diagnostics for initialisation + + IDiagnostics implementation + + + + Gets all registered startup tasks + + An instance containing instances. + + + + Gets all registered request startup tasks + + An instance containing instances. + + + + Gets all registered application registration tasks + + An instance containing instances. + + + + Retrieve all module instances from the container + + Container to use + Collection of NancyModule instances + + + + Retrieve a specific module instance from the container + + Container to use + Type of the module + NancyModule instance + + + + Executes auto registation with the given container. + + Container instance + + + + Gets the assemblies to ignore when autoregistering the application container + Return true from the delegate to ignore that particular assembly, returning true + does not mean the assembly *will* be included, a false from another delegate will + take precedence. + + + + + Containing extensions for the object + + + + + Ascertains if a request originated from an Ajax request or not. + + The current nancy context + True if the request was done using ajax, false otherwise + + + + Expands a path to take into account a base path (if any) + + Nancy context + Path to expand + Expanded path + + + + Returns a redirect response with the redirect path expanded to take into + account a base path (if any) + + Nancy context + Path to redirect to + Redirect response + + + + Retrieves exception details from the context, if any exist + + Nancy context + Exception details + + + + Get a thrown exception from the context. + + The context. + The thrown exception or null if not exception has been thrown. + + + + Get a thrown exception of the given type from the context. + + The type of exception to get. + The context. + The thrown exception or null if not exception has been thrown. + + + + Tries to get a thrown exception from the context. + + The context. + The thrown exception. + true if an exception has been thrown during the request, false otherwise. + + + + Tries to get a thrown exception of the given type from the context. + + The type of exception to get. + The context. + The thrown exception. + true if an exception of the given type has been thrown during the request, false otherwise. + + + + Shortcut extension method for writing trace information + + Nancy context + Log delegate + + + + Returns a boolean indicating whether a given url string is local or not + + Nancy context + Url string (relative or absolute) + True if local, false otherwise + + + + Containing extensions for implementations. + + + + + A regular expression used to manipulate parameterized route segments. + + A object. + + + + Extracts the friendly name of a Nancy module given its type. + + The module instance + A string containing the name of the parameter. + + + + + Returns a boolean indicating whether the route is executing, or whether the module is + being constructed. + + The module instance + True if the route is being executed, false if the module is being constructed + + + + Adds the before delegate to the Before pipeline if the module is not currently executing, + or executes the delegate directly and returns any response returned if it is. + Uses + + Current module + Delegate to add or execute + Optional reason for the early exit (if necessary) + + + + Containing extensions for the object + + + + + An extension method making it easy to check if the request was done using ajax + + The request made by client + if the request was done using ajax, otherwise . + + + + Gets a value indicating whether the request is local. + + The request made by client + if the request is local, otherwise . + + + + Containing extensions for the object. + + + + + A regular expression used to manipulate parameterized route segments. + + A object. + + + + Extracts information about the parameters in the . + + The segment that the information should be extracted from. + An , containing instances for the parameters in the segment. + + + + Checks if a segment contains any parameters. + + The segment to check for parameters. + true if the segment contains a parameter; otherwise false. + A parameter is defined as a string which is surrounded by a pair of curly brackets. + The provided value for the segment parameter was null or empty. + + + + Gets a dynamic dictionary back from a Uri query string + + The query string to extract values from + A dynamic dictionary containing the query string values + + + + Converts the value from PascalCase to camelCase. + + The value. + System.String. + + + + Converts the value from camelCase to PascalCase. + + The value. + System.String. + + + + Provides strongly-typed access to HTTP request headers. + + + + + Initializes a new instance of the class. + + The headers. + + + + Returns an enumerator that iterates through the collection. + + A that can be used to iterate through the collection. + + + + Returns an enumerator that iterates through a collection. + + An object that can be used to iterate through the collection. + + + + Content-types that are acceptable. + + An that contains the header values if they are available; otherwise it will be empty. + + + + Character sets that are acceptable. + + An that contains the header values if they are available; otherwise it will be empty. + + + + Acceptable encodings. + + An that contains the header values if they are available; otherwise it will be empty. + + + + Acceptable languages for response. + + An that contains the header values if they are available; otherwise it will be empty. + + + + Authorization header value for request. + + A containing the header value if it is available; otherwise . + + + + Used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain. + + An that contains the header values if they are available; otherwise it will be empty. + + + + Contains name/value pairs of information stored for that URL. + + An that contains instances if they are available; otherwise it will be empty. + + + + What type of connection the user-agent would prefer. + + A containing the header value if it is available; otherwise . + + + + The length of the request body in octets (8-bit bytes). + + The length of the contents if it is available; otherwise 0. + + + + The mime type of the body of the request (used with POST and PUT requests). + + A containing the header value if it is available; otherwise . + + + + The date and time that the message was sent. + + A instance that specifies when the message was sent. If not available then will be returned. + + + + The domain name of the server (for virtual hosting), mandatory since HTTP/1.1 + + A containing the header value if it is available; otherwise . + + + + Only perform the action if the client supplied entity matches the same entity on the server. This is mainly for methods like PUT to only update a resource if it has not been modified since the user last updated it. + + An that contains the header values if they are available; otherwise it will be empty. + + + + Allows a 304 Not Modified to be returned if content is unchanged + + A instance that specifies when the requested resource must have been changed since. If not available then will be returned. + + + + Allows a 304 Not Modified to be returned if content is unchanged + + An that contains the header values if they are available; otherwise it will be empty. + + + + If the entity is unchanged, send me the part(s) that I am missing; otherwise, send me the entire new entity. + + A containing the header value if it is available; otherwise . + + + + Only send the response if the entity has not been modified since a specific time. + + A instance that specifies when the requested resource may not have been changed since. If not available then will be returned. + + + + Gets the names of the available request headers. + + An containing the names of the headers. + + + + Limit the number of times the message can be forwarded through proxies or gateways. + + The number of the maximum allowed number of forwards if it is available; otherwise 0. + + + + This is the address of the previous web page from which a link to the currently requested page was followed. + + A containing the header value if it is available; otherwise . + + + + The user agent string of the user agent + + A containing the header value if it is available; otherwise . + + + + Gets all the header values. + + An that contains all the header values. + + + + Gets the values for the header identified by the parameter. + + The name of the header to return the values for. + An that contains the values for the header. If the header is not defined then is returned. + + + + Represents a HTML (text/html) response + + + + + Creates a new instance of the HtmlResponse class + + Status code - defaults to OK + Response body delegate - defaults to empty if null + Headers if required + Cookies if required + + + + Csrf protection methods + + + + + Enables Csrf token generation. + This is disabled by default. + + Application pipelines + + + + Disable csrf token generation + + Application pipelines + + + + Creates a new csrf token for this response with an optional salt. + Only necessary if a particular route requires a new token for each request. + + Nancy module + + + + + Validate that the incoming request has valid CSRF tokens. + Throws if validation fails. + + Module object + Optional validity period before it times out + If validation fails + + + + Wires up the CSRF (anti-forgery token) support at application startup. + + + + + Initializes a new instance of the class, using the + provided , and . + + The cryptographic configuration to use. + The serializer that should be used. + The token validator that should be used. + + + + Perform any initialisation tasks + + Application pipelines + + + + Gets the configured crypto config + + + + + Gets the configured object serialiser + + + + + Gets the configured token validator + + + + + Represents a Csrf protection token + + + + + The default key for the csrf cookie/form value/querystring value + + + + + Determines whether the specified is equal to the current . + + + true if the specified is equal to the current ; otherwise, false. + + The to compare with the current . 2 + + + + Serves as a hash function for a particular type. + + + A hash code for the current . + + 2 + + + + Randomly generated bytes + + + + + Date and time the token was created + + + + + Tamper prevention hmac + + + + + Gets a byte array representation of the csrf token for generating + hmacs + + Token + Byte array representing the token + + + + Calculates and sets the Hmac property on a given token + + Token + Hmac provider to use + Hmac bytes + + + + Creates random bytes for the csrf token + + Random byte array + + + + The default implementation of the interface. + + + + + Validates Csrf tokens + + + + + Validates a pair of tokens + + First token (usually from either a form post or querystring) + Second token (usually from a cookie) + Optional period that the tokens are valid for + Token validation result + + + + Validates that a cookie token is still valid with the current configuration / keys + + Token to validate + True if valid, false otherwise + + + + Initializes a new instance of the class, + using the provided . + + The that should be used. + + + + Validates a pair of tokens + + First token (usually from either a form post or querystring) + Second token (usually from a cookie) + Optional period that the tokens are valid for + Token validation result + + + + Validates that a cookie token is still valid with the current configuration / keys + + Token to validate + True if valid, false otherwise + + + + Result of Csrf Token validation + + + + + Validated ok + + + + + One or both of the tokens appears to have been tampered with + + + + + One or both of the tokens are missing + + + + + Tokens to not match + + + + + Token is valid, but has expired + + + + + Containing extensions for the object. + + + + + Force the response to be downloaded as an attachment + + Response object + Filename for the download + Optional content type + Modified Response object + + + + Adds a to the response. + + Response object + The name of the cookie. + The value of the cookie. + The instance. + + + + Adds a to the response. + + Response object + The name of the cookie. + The value of the cookie. + The expiration date of the cookie. Can be if it should expire at the end of the session. + The instance. + + + + Adds a to the response. + + Response object + The name of the cookie. + The value of the cookie. + The expiration date of the cookie. Can be if it should expire at the end of the session. + The domain of the cookie. + The path of the cookie. + The instance. + + + + Adds a to the response. + + Response object + A instance. + + + + + Add a header to the response + + Response object + Header name + Header value + Modified response + + + + Adds headers to the response using anonymous types + + Response object + + Array of headers - each header should be an anonymous type with two string properties + 'Header' and 'Value' to represent the header name and its value. + + Modified response + + + + Adds headers to the response using anonymous types + + Response object + + Array of headers - each header should be a Tuple with two string elements + for header name and header value + + Modified response + + + + Sets the content type of the response + + Response object + The type of the content + Modified response + + + + Sets the status code of the response + + Response object + The http status code + Modified response + + + + Sets the status code of the response + + Response object + The http status code + Modified response + + + + Assigns the root path of the application whom ever needs it. + + This task is run at application startup. + + + + Initializes a new instance of the class. + + An instance. + + + + Perform any initialisation tasks + + + + + Defines the core functionality of an identity + + + + + The username of the authenticated user. + + A containing the username. + + + + The claims of the authenticated user. + + An , containing the claims. + + + + Gets or sets a value indicating whether or not to disable traces in error messages + + + + + Gets or sets a value indicating whether or not to respond with 405 responses + + + + + Gets or sets a value indicating whether or not to enable case sensitivity in query, parameters (DynamicDictionary) and model binding. Enable this to conform with RFC3986. + + + + + Gets or sets a value indicating whether or not to route HEAD requests explicitly. + + + + + Gets a value indicating whether we are running in debug mode or not. + Checks the entry assembly to see whether it has been built in debug mode. + If anything goes wrong it returns false. + + + + + Gets or sets the limit on the number of query string variables, form fields, + or multipart sections in a request. + + + + + Gets or sets a value indicating whether or not to enable request tracing + + + + + Gets or sets a value indicating whether or not to enable runtime view discovery + Defaults to True in debug mode and False in release mode + + + + + Gets or sets a value indicating whether or not to allow runtime changes of views + Defaults to True in debug mode and False in release mode + + + + + Represents a full Url of the form scheme://hostname:port/basepath/path?query + + Since this is for internal use, and fragments are not passed to the server, fragments are not supported. + + + + Creates an instance of the class + + + + + Creates an instance of the class + + A containing a URL. + + + + Clones the url. + + Returns a new cloned instance of the url. + + + + Clones the url. + + Returns a new cloned instance of the url. + + + + Casts the current instance to a instance. + + The instance that should be cast. + A representation of the . + + + + Casts the current instance to a instance. + + The instance that should be cast. + An representation of the . + + + + Casts the current instance to a instance. + + The instance that should be cast. + An representation of the . + + + + Casts a instance to a instance + + The instance that should be cast. + An representation of the . + + + + Gets or sets the HTTP protocol used by the client. + + The protocol. + + + + Gets the hostname of the request + + + + + Gets the port name of the request + + + + + Gets the base path of the request i.e. the "Nancy root" + + + + + Gets the path of the request, relative to the base path + This property drives the route matching + + + + + Gets the querystring data of the requested resource. + + + + + Gets the domain part of the request + + + + + Gets whether the url is secure or not. + + + + + A composite validator to combine other validators. + + + + + Provides a way to validate a type as well as a description to use for client-side validation. + + + + + Validates the specified instance. + + The instance that should be validated. + The of the current request. + A with the result of the validation. + + + + Gets the description of the validator. + + + + + Gets the of the model that is being validated by the validator. + + + + + Initializes a new instance of the class. + + The validators. + The type of the model that is being validated. + + + + Validates the specified instance. + + The instance that should be validated. + The of the current request. + A with the result of the validation. + + + + Gets the description of the validator. + + + + + The type of the model that is being validated by the validator. + + + + + The default Nancy implementation of IValidatorLocator. + + + + + Locates a validator for a given type. + + + + + Gets a validator for a given type. + + The type to validate. + An instance or if none found. + + + + Initializes a new instance of the class. + + The factories. + + + + Gets a validator for a given type. + + The type to validate. + An instance or if none found. + + + + Creates instances of IValidator. + + + + + Creates a validator for the given type. + + The type. + A validator for the given type or null if none exists. + + + + Exception that is thrown during problems with model validation. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class, + with the provided . + + The error message that explains the reason for the exception. + + + + Initializes a new instance of the class, + with the provided and + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception, or a null reference if no inner exception is specified. + + + + Extensions to for validation. + + + + + Performs validation on the specified . + + The type of the that is being validated. + The module that the validation is performed from. + The instance that is being validated. + A instance. + + + + Specifies the validation comparison operators used by the type. + + + + + A comparison for greater than. + + + + + A comparison for greater than or equal to. + + + + + A comparison for less than. + + + + + A comparison for less than or equal to. + + + + + A comparison for equality. + + + + + A comparison for inequality. + + + + + Implementation of for ensuring a string does not + contain an empty value. + + + + + A description of a validation rule. + + + + + Initializes a new instance of the class. + + Type of the rule. + The error message formatter. + + + + Initializes a new instance of the class. + + Type of the rule. + The error message formatter. + Name of the member. + + + + Gets the error message that this rule will provide upon error. + + The name. + The error message. + + + + Gets the names of the members this rule validates. + + An that contains the name of the member. + + + + Gets the type of the rule. + + The type of the rule. + + + + Initializes a new instance of the class. + + The error message formatter. + The member names. + + + + Implementation of for ensuring a string is not null. + + + + + Initializes a new instance of the class. + + The error message formatter. + The member names. + + + + Implementation of for comparing two values using a + provided . + + + + + Initializes a new instance of the class. + + The error message formatter. + The member names. + The that should be used when comparing values. + Gets the value to compare against. + + + + The that should be used when comparing values. + + A value. + + + + Gets the value to compare against. + + + + + Implementation of for ensuring a string matches the + pattern which is defined by a regex. + + + + + Initializes a new instance of the class. + + The error message formatter. + The member names. + The regex pattern that should be used to check for a match. + + + + The regex pattern that should be used to check for a match. + + + + + Implementation of for ensuring that the length of a string + is withing the specified range. + + + + + Initializes a new instance of the class. + + The error message formatter. + The member names. + Minimum allowed length of the string + Maximum allowed length of the string + + + + Gets the length of the min. + + The length of the min. + + + + Gets the length of the max. + + The length of the max. + + + + A description of the rules a validator provides. + + + + + Initializes a new instance of the class. + + The rules that describes the model. + The type of the model that the rules are defined for. + + + + Initializes a new instance of the class. + + The rules that describes the model, grouped by member name. + The type of the model that the rules are defined for. + + + + The type of the model that is being described. + + + + + Gets the rules. + + An instance that contains instances grouped by property name. + + + + Represents a model validation error. + + + + + Initializes a new instance of the class. + + Name of the member that the error describes. + + + + + Initializes a new instance of the class. + + The member names that the error describes. + + + + + Implicitly cast a validation error to a string. + + The that should be cast. + A containing the validation error description. + + + + Returns the . + + A string containing the error message. + + + + Gets the member names that are a part of the error. + + An that contains the name of the members. + + + + + + + + + Represents the result of a model validation. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The instances that makes up the result. + + + + Initializes a new instance of the class. + + The instances that makes up the result, grouped by member name. + + + + Gets the errors. + + An instance that contains instances grouped by property name. + + + + Gets a value indicating whether the validated instance is valid or not. + + if the validated instance is valid; otherwise, . + + + + Default implementation for retrieving information about views that are stored on the file system. + + + + + Defines the functionality for retrieving information about views that are stored on the file system. + + + + + Gets information about view that are stored in folders below the applications root path. + + The path of the folder where the views should be looked for. + A list of view extensions to look for. + An containing view locations and contents readers. + + + + Gets the last modified time for the file specified + + Filename + Time the file was last modified + + + + Gets information about specific views that are stored in folders below the applications root path. + + The path of the folder where the views should be looked for. + Name of the view to search for + A list of view extensions to look for. + An containing view locations and contents readers. + + + + Gets information about view that are stored in folders below the applications root path. + + The path of the folder where the views should be looked for. + A list of view extensions to look for. + An containing view locations and contents readers. + + + + Gets the last modified time for the file specified + + Filename + Time the file was last modified + + + + Gets information about specific views that are stored in folders below the applications root path. + + The path of the folder where the views should be looked for. + Name of the view to search for + A list of view extensions to look for. + An containing view locations and contents readers. + + + + Default render context implementation. + + + + + Defines the functionality of the context that is passed into a view engine when the view is requested to be rendered. + + + + + Parses a path and returns an absolute url path, taking into account + base directory etc. + + Input url such as ~/styles/main.css + Parsed absolute url path + + + + HTML encodes a string. + + The string that should be HTML encoded. + A HTML encoded . + + + + Locates a view that matches the provided and . + + The name of the view that should be located. + The model that should be used when locating the view. + A instance if the view could be located; otherwise, . + + + + Gets the current Csrf token. + The token should be stored in a cookie and the form as a hidden field. + In both cases the name should be the key of the returned key value pair. + + A tuple containing the name (cookie name and form/querystring name) and value + + + + Gets the context of the current request. + + A instance. + + + + Gets the view cache that is used by Nancy. + + An instance. + + + + Gets the text resource for localisation + + + + + Gets the text resource finder for localisation + + + + + Initializes a new instance of the class. + + + + + + + + + Parses a path and returns an absolute url path, taking into account + base directory etc. + + Input url such as ~/styles/main.css + Parsed absolute url path + + + + HTML encodes a string. + + The string that should be HTML encoded. + A HTML encoded . + + + + Locates a view that matches the provided and . + + The name of the view that should be located. + The model that should be used when locating the view. + A instance if the view could be located; otherwise, . + + + + Generates a Csrf token. + The token should be stored in a cookie and the form as a hidden field. + In both cases the name should be the key of the returned key value pair. + + A tuple containing the name (cookie name and form/querystring name) and value + + + + Gets the context of the current request. + + A instance. + + + + Gets the view cache that is used by Nancy. + + An instance. + + + + Gets the text resource for localisation + + + + + Gets the text resource finder for localisation + + + + + Default render context factory implementation. + + + + + Defines the functionality required to manufacture instances. + + + + + Gets a for the specified . + + The for which the context should be created. + A instance. + + + + Initializes a new instance of the class. + + The view cache that should be used by the created render context. + The view resolver that should be used by the created render context. + The that should be used by the engine. + + + + Gets a for the specified . + + The for which the context should be created. + A instance. + + + + Default set of assemblies that should be scanned for items (views, text, content etc) + embedded as resources. + + The default convention will scan all assemblies that references another assemblies that has a name that starts with Nancy* + + + + Defines the functionality for retrieving which assemblies that should be used by Nancy. + + + + + Gets a list of assemblies that should be scanned. + + An of instances. + + + + Gets a list of assemblies that should be scanned for views. + + An of instances. + + + + Default implementation for extracting view information form an assembly. + + + + + Defines the functionality of a reader that extracts embedded views from an assembly. + + + + + Gets information about the resources that are embedded in the assembly. + + The to retrieve view information from. + A list of view extensions to look for. + A of resource locations and content readers. + + + + Gets information about the resources that are embedded in the assembly. + + The to retrieve view information from. + A list of view extensions to look for. + A of resource locations and content readers. + + + + Resource based implementation of + + + + + Initializes a new instance of to read strings from *.resx files + + The that should be used when scanning. + + + + Used to return a string value from *.resx files + + The key to look for in the resource file + The used to determine the culture for returning culture specific values. + Returns a string value from culture specific or default file or null if key does not exist as determined by . + + + + Default implementation of the interface. + + + + + Interface for manually rendering views to a Response object, rather + than going through content negotiation. + + + + + Renders a view to a response object, bypassing content negotiation. + + Current Nancy context + View name + Model object (or null) + Response object containing the rendered view (if found) + + + + Initializes an instance of the type, with + the provided . + + The that should be used to render the views. + + + + Renders a view to a response object, bypassing content negotiation. + + Current Nancy context + View name + Model object (or null) + Response object containing the rendered view (if found) + + + + View cache that supports expiring content if it is stale + + + + + Defines the functionality of a Nancy view cache. + + + + + Gets or adds a view from the cache. + + The type of the cached view instance. + A instance that describes the view that is being added or retrieved from the cache. + A function that produces the value that should be added to the cache in case it does not already exist. + An instance of the type specified by the type. + + + + Initializes a new instance of the class. + + + + + Gets or adds a view from the cache. + + The type of the cached view instance. + A instance that describes the view that is being added or retrieved from the cache. + A function that produces the value that should be added to the cache in case it does not already exist. + An instance of the type specified by the type. + + + + Contains miscellaneous extension methods. + + + + + Checks if the evaluated instance is an anonymous + + The object instance to check. + if the object is an anonymous type; otherwise . + + + + Contains the functionality for locating a view that is located on the file system. + + + + + Defines the functionality used by Nancy to located a view. + + + + + Returns an instance for all the views that could be located by the provider. + + An instance, containing the view engine file extensions that is supported by the running instance of Nancy. + An instance, containing instances for the located views. + If no views could be located, this method should return an empty enumerable, never . + + + + Returns an instance for all the views matching the viewName that could be located by the provider. + + An instance, containing the view engine file extensions that is supported by the running instance of Nancy. + Location of the view + The name of the view to try and find + An instance, containing instances for the located views. + If no views could be located, this method should return an empty enumerable, never . + + + + Initializes a new instance of the class. + + A instance. + Creating an instance using this constructor will result in the being used internally. + + + + Initializes a new instance of the class. + + A instance. + An instance that should be used when retrieving view information from the file system. + + + + Returns an instance for all the views that could be located by the provider. + + An instance, containing the view engine file extensions that is supported by the running instance of Nancy. + An instance, containing instances for the located views. + If no views could be located, this method should return an empty enumerable, never . + + + + Returns an instance for all the views matching the viewName that could be located by the provider. + + An instance, containing the view engine file extensions that is supported by the running instance of Nancy. + The name of the view to try and find + An instance, containing instances for the located views. + If no views could be located, this method should return an empty enumerable, never . + + + + Represents a HEAD only response. + + + + + Initializes a new instance of the class. + + + The full response to create the head response from. + + + + + Containing extensions for the collection objects. + + + + + Converts a to a instance. + + The to convert. + An instance. + + + + Converts an instance to a instance. + + The instance to convert. + A instance. + + + + Merges a collection of instances into a single one. + + The list of instances to merge. + An instance containing the keys and values from the other instances. + + + + Filters a collection based on a provided key selector. + + The collection filter. + The predicate to filter by. + The type of the collection to filter. + The type of the key to filter by. + A instance with the filtered values. + + + + Decodes an HTML-encoded string and returns the decoded string. + + The HTML string to decode. + The decoded text. + + + + Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream. + + The HTML string to decode + The TextWriter output stream containing the decoded string. + + + + HTML-encodes a string and sends the resulting output to a TextWriter output stream. + + The string to encode. + The TextWriter output stream containing the encoded string. + + + + Represents a file that was captured in a HTTP multipart/form-data request + + + + + Initializes a new instance of the class, + using the provided . + + The that contains the file information. + + + + Initializes a new instance of the class, + using the provided values + + The content type of the file. + The name of the file. + The content of the file. + The name of the field that uploaded the file. + + + + Gets or sets the type of the content. + + A containing the content type of the file. + + + + Gets or sets the name of the file. + + A containing the name of the file. + + + + Gets or sets the form element name of this file. + + A containing the key. + + + + Gets or sets the value stream. + + A containing the contents of the file. + This is a instance that sits ontop of the request stream. + + + + Retrieves instances from a request stream. + + + + + Initializes a new instance of the class. + + The request stream to parse. + The boundary marker to look for. + + + + Gets the instances from the request stream. + + An instance, containing the found instances. + + + + Represents the content boundary of a HTTP multipart/form-data boundary in a stream. + + + + + Initializes a new instance of the class. + + The stream that contains the boundary information. + + + + Gets the contents type of the boundary value. + + A containing the name of the value if it is available; otherwise . + + + + Gets or the filename for the boundary value. + + A containing the filename value if it is available; otherwise . + This is the RFC2047 decoded value of the filename attribute of the Content-Disposition header. + + + + Gets name of the boundary value. + + This is the RFC2047 decoded value of the name attribute of the Content-Disposition header. + + + + A stream containing the value of the boundary. + + This is the RFC2047 decoded value of the Content-Type header. + + + + A buffer that is used to locate a HTTP multipart/form-data boundary in a stream. + + + + + Initializes a new instance of the class. + + The boundary as a byte-array. + The closing boundary as byte-array + + + + Resets the buffer so that inserts happens from the start again. + + This does not clear any previously written data, just resets the buffer position to the start. Data that is inserted after Reset has been called will overwrite old data. + + + + Inserts the specified value into the buffer and advances the internal position. + + The value to insert into the buffer. + This will throw an is you attempt to call insert more times then the of the buffer and was not invoked. + + + + Gets a value indicating whether the buffer contains the same values as the boundary. + + if buffer contains the same values as the boundary; otherwise, . + + + + Gets a value indicating whether this buffer is full. + + if buffer is full; otherwise, . + + + + Gets the number of bytes that can be stored in the buffer. + + The number of bytes that can be stored in the buffer. + + + + HTTP Status Codes + + The values are based on the list found at http://en.wikipedia.org/wiki/List_of_HTTP_status_codes + + + + 100 Continue + + + + + 101 SwitchingProtocols + + + + + 102 Processing + + + + + 103 Checkpoint + + + + + 200 OK + + + + + 201 Created + + + + + 202 Accepted + + + + + 203 NonAuthoritativeInformation + + + + + 204 NoContent + + + + + 205 ResetContent + + + + + 206 PartialContent + + + + + 207 MultipleStatus + + + + + 226 IMUsed + + + + + 300 MultipleChoices + + + + + 301 MovedPermanently + + + + + 302 Found + + + + + 303 SeeOther + + + + + 304 NotModified + + + + + 305 UseProxy + + + + + 306 SwitchProxy + + + + + 307 TemporaryRedirect + + + + + 308 ResumeIncomplete + + + + + 400 BadRequest + + + + + 401 Unauthorized + + + + + 402 PaymentRequired + + + + + 403 Forbidden + + + + + 404 NotFound + + + + + 405 MethodNotAllowed + + + + + 406 NotAcceptable + + + + + 407 ProxyAuthenticationRequired + + + + + 408 RequestTimeout + + + + + 409 Conflict + + + + + 410 Gone + + + + + 411 LengthRequired + + + + + 412 PreconditionFailed + + + + + 413 RequestEntityTooLarge + + + + + 414 RequestUriTooLong + + + + + 415 UnsupportedMediaType + + + + + 416 RequestedRangeNotSatisfiable + + + + + 417 ExpectationFailed + + + + + 418 ImATeapot + + + + + 420 Enhance Your Calm + + + + + 422 UnprocessableEntity + + + + + 423 Locked + + + + + 424 FailedDependency + + + + + 425 UnorderedCollection + + + + + 426 UpgradeRequired + + + + + 429 Too Many Requests + + + + + 444 NoResponse + + + + + 449 RetryWith + + + + + 450 BlockedByWindowsParentalControls + + + + + 499 ClientClosedRequest + + + + + 500 InternalServerError + + + + + 501 NotImplemented + + + + + 502 BadGateway + + + + + 503 ServiceUnavailable + + + + + 504 GatewayTimeout + + + + + 505 HttpVersionNotSupported + + + + + 506 VariantAlsoNegotiates + + + + + 507 InsufficientStorage + + + + + 509 BandwidthLimitExceeded + + + + + 510 NotExtended + + + + + An extension point for adding support for formatting response contents. No members should be added to this interface without good reason. + + Extension methods to this interface should always return or one of the types that can implicitly be types into a . + + + + Gets all serializers currently registered + + + + + Gets the context for which the response is being formatted. + + A instance. + + + + Gets the root path of the application. + + A containing the root path. + + + + Attempts to detect if the content type is JSON. + Supports: + application/json + text/json + application/vnd[something]+json + Matches are case insensitive to try and be as "accepting" as possible. + + Request content type + True if content type is JSON, false otherwise + + + + Gets the type of the typed list's items. + + The type. + The type of the typed list's items. + + + + Determines whether the member is an indexed property. + + The member. + + true if the member is an indexed property; otherwise, false. + + + + + Determines whether the property is an indexed property. + + The property. + + true if the property is an indexed property; otherwise, false. + + + + + Gets the member's value on the object. + + The member. + The target object. + The member's value on the object. + + + + Sets the member's value on the target object. + + The member. + The target. + The value. + + + + Determines whether the specified MemberInfo can be read. + + The MemberInfo to determine whether can be read. + + true if the specified MemberInfo can be read; otherwise, false. + + + + + Determines whether the specified MemberInfo can be set. + + The MemberInfo to determine whether can be set. + + true if the specified MemberInfo can be set; otherwise, false. + + + + + Model binding context object + + + + + The binding configuration + + + + + Current Nancy context + + + + + Binding destination type + + + + + The generic type of a collection is only used when DestinationType is a enumerable. + + + + + The current model object (or null for body deserialization) + + + + + DestinationType properties that are not black listed + + + + + The incoming data fields + + + + + Available type converters - user converters followed by any defaults + + + + + Provides default binding converters/deserializers + The defaults have less precedence than any user supplied ones + + + + + Initializes a new instance of the class. + + + + + Gets the default type converters + + + + + Gets the default type converters + + + + + Default binder - used as a fallback when a specific modelbinder + is not available. + + + + + Binds incoming request data to a model type + + + + + Bind to the given model type + + Current context + Model type to bind to + The that should be applied during binding. + Blacklisted property names + Existing instance of the object + Bound model + + + + Bind to the given model type + + Current context + Model type to bind to + Optional existing instance + The that should be applied during binding. + Blacklisted binding property names + Bound model + + + + Gets the number of distinct indexes from context: + + i.e: + IntProperty_5 + StringProperty_5 + IntProperty_7 + StringProperty_8 + You'll end up with a list of 3 matches: 5,7,8 + + + Current Context + An int containing the number of elements + + + + Deserializes request bodies in JSON format + + + + + Provides a way to deserialize the contents of a request + into a bound model. + + + + + Whether the deserializer can deserialize the content type + + Content type to deserialize + Current . + True if supported, false otherwise + + + + Deserialize the request body to a model + + Content type to deserialize + Request body stream + Current . + Model instance + + + + Whether the deserializer can deserialize the content type + + Content type to deserialize + Current . + True if supported, false otherwise + + + + Deserialize the request body to a model + + Content type to deserialize + Request body stream + Current context + Model instance + + + + Deserializes request bodies in XML format + + + + + Whether the deserializer can deserialize the content type + + Content type to deserialize + Current . + True if supported, false otherwise + + + + Deserialize the request body to a model + + Content type to deserialize + Request body stream + Current . + Model instance + + + + Converter for handling enumerable types + + + + + Whether the converter can convert to the destination type + + Destination type + The current binding context + True if conversion supported, false otherwise + + + + Convert the string representation to the destination type + + Input string + Destination type + Current context + Converted object of the destination type + + + + A fallback converter that uses TypeDescriptor.GetConverter to try + and convert the value. + + + + + Whether the converter can convert to the destination type + + Destination type + The current binding context + True if conversion supported, false otherwise + + + + Convert the string representation to the destination type + + Input string + Destination type + Current context + Converted object of the destination type + + + + Default field name converter + Converts camel case to pascal case + + + + + Provides the capability to supply a convention to + convert form field names to property names if required. + + + + + Converts a field name to a property name + + Field name + Property name + + + + Converts a field name to a property name + + Field name + Property name + + + + Provides wiring up of a model binder when cast to a destination type + + + + + Initializes a new instance of the class. + + Model binder locator + Nancy context + Optional existing instance, or null + The that should be applied during binding. + Blacklisted property names + + + + Provides implementation for type conversion operations. Classes derived from the class can override this method to specify dynamic behavior for operations that convert an object from one type to another. + + + true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) + + Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted. For example, for the statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic), where sampleObject is an instance of the class derived from the class, binder.Type returns the type. The binder.Explicit property provides information about the kind of conversion that occurs. It returns true for explicit conversion and false for implicit conversion.The result of the type conversion operation. + + + + Provides a way to bind an incoming request, via the context, to a model type + + + + + Whether the binder can bind to the given model type + + Required model type + True if binding is possible, false otherwise + + + + Locates model binders for a particular model + + + + + Gets a binder for the given type + + Destination type to bind to + The instance of the current request. + IModelBinder instance or null if none found + + + + Locates model binders for a particular model + + + + + Available model binders + + + + + Default model binder to fall back on + + + + + Initializes a new instance of the class. + + Available model binders + Fallback binder + + + + Gets a binder for the given type + + Destination type to bind to + The instance of the current request. + IModelBinder instance or null if none found + + + + Represents an exception when attempting to bind to a model + + + + + Initializes a new instance of the ModelBindingException class with a specified model type, + property name and the original exception, which caused the problem + + the model type to bind to + the original exceptions, thrown while binding the property + + + + Gets all failures + + + + + Gets the model type, which caused the exception + + + + + Parses an array of expressions like t => t.Property to a list of strings containing the property names; + + Type of the model + Expressions that tell which property should be ignored + Array of strings containing the names of the properties. + + + + Bind the incoming request to a model + + Current module + Property names to blacklist from binding + Model adapter - cast to a model type to bind it + + + + Bind the incoming request to a model + + Current module + The that should be applied during binding. + Property names to blacklist from binding + Model adapter - cast to a model type to bind it + + + + Bind the incoming request to a model + + Model type + Current module + Bound model instance + + + + Bind the incoming request to a model + + Model type + Current module + Property names to blacklist from binding + Bound model instance + + + + Bind the incoming request to a model + + Model type + Current module + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + Bound model instance + + + + Bind the incoming request to a model and validate + + Model type + Current module + Property names to blacklist from binding + Bound model instance + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to a model and validate + + Model type + Current module + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + Bound model instance + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to a model and validate + + Model type + Current module + Bound model instance + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to a model + + Model type + Current module + The that should be applied during binding. + Bound model instance + + + + Bind the incoming request to a model + + Model type + Current module + The that should be applied during binding. + Property names to blacklist from binding + Bound model instance + + + + Bind the incoming request to a model + + Model type + Current module + The that should be applied during binding. + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + Bound model instance + + + + Bind the incoming request to a model + + Model type + Current module + The that should be applied during binding. + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + Bound model instance + + + + Bind the incoming request to a model and validate + + Model type + Current module + The that should be applied during binding. + Property names to blacklist from binding + Bound model instance + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to a model and validate + + Model type + Current module + The that should be applied during binding. + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + Bound model instance + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to a model and validate + + Model type + Current module + The that should be applied during binding. + Bound model instance + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to an existing instance + + Model type + Current module + The class instance to bind properties to + Property names to blacklist from binding + + + + Bind the incoming request to an existing instance + + Model type + Current module + The class instance to bind properties to + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + + + + Bind the incoming request to an existing instance + + Model type + Current module + The class instance to bind properties to + + + + Bind the incoming request to an existing instance and validate + + Model type + Current module + The class instance to bind properties to + Property names to blacklist from binding + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to an existing instance and validate + + Model type + Current module + The class instance to bind properties to + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to an existing instance and validate + + Model type + Current module + The class instance to bind properties to + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to an existing instance + + Model type + Current module + The class instance to bind properties to + The that should be applied during binding. + Property names to blacklist from binding + + + + Bind the incoming request to an existing instance + + Model type + Current module + The class instance to bind properties to + The that should be applied during binding. + Expressions that tell which property should be ignored + this.Bind<Person>(p => p.Name, p => p.Age) + + + + Bind the incoming request to an existing instance + + Model type + Current module + The class instance to bind properties to + The that should be applied during binding. + + + + Bind the incoming request to an existing instance and validate + + Model type + Current module + The class instance to bind properties to + The that should be applied during binding. + Property names to blacklist from binding + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Bind the incoming request to an existing instance and validate + + Model type + Current module + The class instance to bind properties to + The that should be applied during binding. + Expressions that tell which property should be ignored + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + this.BindToAndValidate(person, config, p => p.Name, p => p.Age) + + + + Bind the incoming request to an existing instance and validate + + Model type + Current module + The class instance to bind properties to + The that should be applied during binding. + is stored in NancyModule.ModelValidationResult and NancyContext.ModelValidationResult. + + + + Nancy context. + + + + + Initializes a new instance of the class. + + + + + Disposes any disposable items in the dictionary. + + + + + Gets the dictionary for storage of per-request items. Disposable items will be disposed when the context is. + + + + + Gets or sets the resolved route + + + + + Gets or sets the parameters for the resolved route + + + + + Gets or sets the incoming request + + + + + Gets or sets the outgoing response + + + + + Gets or sets the current user + + + + + Diagnostic request tracing + + + + + Gets a value indicating whether control panel access is enabled for this request + + + + + Non-model specific data for rendering in the response + + + + + Gets or sets the model validation result. + + + + + Gets or sets the context's culture + + + + + Context of content negotiation (if relevant) + + + + + Gets or sets the dynamic object used to locate text resources. + + + + + Wraps a sync delegate into it's async form + + Sync pipeline item instance + Async pipeline item instance + + + + Wraps a sync delegate into it's async form + + Sync pipeline item instance + Async pipeline item instance + + + + The default implementation of the interface. + + + + + Initializes a new instance of the class. + + The that should be used by the instance. + The that should be used by the instance. + + + + Gets all serializers currently registered + + + + + Gets the context for which the response is being formatted. + + A instance. + + + + Gets the root path of the application. + + A containing the root path. + + + + A decorator that can handle moving the stream out from memory and on to disk when the contents reaches a certain length. + + + + + Initializes a new instance of the class. + + The expected length of the contents in the stream. + The content length that will trigger the stream to be moved out of memory. + if set to the stream will never explicitly be moved to disk. + + + + Initializes a new instance of the class. + + The that should be handled by the request stream + The expected length of the contents in the stream. + if set to the stream will never explicitly be moved to disk. + + + + Initializes a new instance of the class. + + The expected length of the contents in the stream. + if set to the stream will never explicitly be moved to disk. + + + + Initializes a new instance of the class. + + The that should be handled by the request stream + The expected length of the contents in the stream. + The content length that will trigger the stream to be moved out of memory. + if set to the stream will never explicitly be moved to disk. + + + + Begins an asynchronous read operation. + + An that represents the asynchronous read, which could still be pending. + The buffer to read the data into. + The byte offset in at which to begin writing data read from the stream. + The maximum number of bytes to read. + An optional asynchronous callback, to be called when the read is complete. + A user-provided object that distinguishes this particular asynchronous read request from other requests. + + + + Begins an asynchronous write operation. + + An that represents the asynchronous write, which could still be pending. + The buffer to write data from. + The byte offset in from which to begin writing. + The maximum number of bytes to write. + An optional asynchronous callback, to be called when the write is complete. + A user-provided object that distinguishes this particular asynchronous write request from other requests. + + + + Waits for the pending asynchronous read to complete. + + + The number of bytes read from the stream, between zero (0) and the number of bytes you requested. Streams return zero (0) only at the end of the stream, otherwise, they should block until at least one byte is available. + + The reference to the pending asynchronous request to finish. + + + + Ends an asynchronous write operation. + + A reference to the outstanding asynchronous I/O request. + + + + Clears all buffers for this stream and causes any buffered data to be written to the underlying device. + + + + + Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + + The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. + The zero-based byte offset in at which to begin storing the data read from the current stream. + The maximum number of bytes to be read from the current stream. + + + + Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. + + The unsigned byte cast to an Int32, or -1 if at the end of the stream. + + + + Sets the position within the current stream. + + The new position within the current stream. + A byte offset relative to the parameter. + A value of type indicating the reference point used to obtain the new position. + + + + Sets the length of the current stream. + + The desired length of the current stream in bytes. + The stream does not support having it's length set. + This functionality is not supported by the type and will always throw . + + + + Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + + An array of bytes. This method copies bytes from to the current stream. + The zero-based byte offset in at which to begin copying bytes to the current stream. + The number of bytes to be written to the current stream. + + + + Gets a value indicating whether the current stream supports reading. + + Always returns . + + + + Gets a value indicating whether the current stream supports seeking. + + Always returns . + + + + Gets a value that determines whether the current stream can time out. + + Always returns . + + + + Gets a value indicating whether the current stream supports writing. + + Always returns . + + + + Gets the length in bytes of the stream. + + A long value representing the length of the stream in bytes. + + + + Gets a value indicating whether the current stream is stored in memory. + + if the stream is stored in memory; otherwise, . + The stream is moved to disk when either the length of the contents or expected content length exceeds the threshold specified in the constructor. + + + + Gets or sets the position within the current stream. + + The current position within the stream. + + + + A response representing a file. + + If the response contains an invalid file (not found, empty name, missing extension and so on) the status code of the response will be set to . + + + + Size of buffer for transmitting file. Default size 4 Mb + + + + + Initializes a new instance of the for the file specified + by the parameter. + + The name of the file, including path relative to the root of the application, that should be returned. + The method will be used to determine the mimetype of the file and will be used as the content-type of the response. If no match if found the content-type will be set to application/octet-stream. + + + + Initializes a new instance of the for the file specified + by the parameter. + + The name of the file, including path relative to the root of the application, that should be returned. + The method will be used to determine the mimetype of the file and will be used as the content-type of the response. If no match if found the content-type will be set to application/octet-stream. + Current context + + + + Initializes a new instance of the for the file specified + by the parameter and the content-type specified by the parameter. + + The name of the file, including path relative to the root of the application, that should be returned. + The content-type of the response. + Current context + + + + Represents a list of "base paths" where it is safe to + serve files from. + Attempting to server a file outside of these safe paths + will fail with a 404. + + + + + Gets the filename of the file response + + A string containing the name of the file. + + + + A response representing an HTTP redirect + + + + + + + Initializes a new instance of the class. + + Location to redirect to + Type of redirection to perform + + + + Which type of redirect + + + + + HTTP 301 - All future requests should be to this URL + + + + + HTTP 307 - Redirect this request but allow future requests to the original URL + + + + + HTTP 303 - Redirect this request using an HTTP GET + + + + + Default implementation for building a full configured instance. + + + + + Initializes a new instance of the class. + + The instance that should be assigned to the module. + An instance that should be used to create a response formatter for the module. + A instance that should be assigned to the module. + A instance that should be assigned to the module. + + + + Builds a fully configured instance, based upon the provided . + + The that should be configured. + The current request context. + A fully configured instance. + + + + It's not safe for a module to take a dependency on the cache (cyclic dependency) + + We provide an IRouteCacheProvider instead - the default implementation uses + TinyIoC'd Func based lazy factory. + + + + + It's not safe for a module to take a dependency on the cache (cyclic dependency) + + We provide an instead. + + It is *not* safe to call GetCache() inside a NancyModule constructor, although that shouldn't be necessary anyway. + + + + + Gets an instance of the route cache. + + An instance. + + + + Initializes a new instance of the DefaultRouteCacheProvider class. + + + + + + Gets an instance of the route cache. + + An instance. + + + + Gets the name of the provider. + + A containing the name of the provider. + + + + Gets the description of the provider. + + A containing the description of the provider. + + + + Gets the object that contains the interactive diagnostics methods. + + An instance of the interactive diagnostics object. + + + + Default implementation of a route pattern matcher. + + + + + Defined the functionality that is required by a route pattern matcher. + + Implement this interface if you want to support a custom route syntax. + + + + Attempts to match a requested path with a route pattern. + + The path that was requested. + The route pattern that the requested path should be attempted to be matched with. + + The instance for the current request. + An instance, containing the outcome of the match. + + + + Attempts to match a requested path with a route pattern. + + The path that was requested. + The route pattern that the requested path should be attempted to be matched with. + + The instance for the current request. + An instance, containing the outcome of the match. + + + + Contains a cache of all routes registered in the system + + + + + Gets a boolean value that indicates of the cache is empty or not. + + if the cache is empty, otherwise . + + + + Caches information about all the available routes that was discovered by the bootstrapper. + + + + + Initializes a new instance of the class. + + The that should be used by the cache. + The that should be used to create a context instance. + + + + + + + + Gets a boolean value that indicates of the cache is empty or not. + + if the cache is empty, otherwise . + + + + Defines the functionality that is required by a route pattern match result. + + + + + Gets the that was active when the result was produced. + + A instance. + + + + Gets a value indicating whether or not a match was made. + + if a match was made; otherwise . + + + + The parameters that could be captured in the route. + + A instance containing the captured parameters and values. + Should be empty if is . + + + + Route that is returned when the path could be matched but it was for the wrong request method. + + This is equal to sending back the 405 HTTP status code. + + + + Initializes a new instance of the type, for the + specified , and . + + The path of the route. + The HTTP method of the route. + The HTTP methods that can be used to invoke the route. + + + + Represents the various parts of a route lambda. + + + + + Initializes a new instance of the class. + + Route name + The request method of the route. + The path that the route will be invoked for. + The condition that has to be fulfilled for the route to be a valid match. + + + + The name of the route + + + + + The condition that has to be fulfilled inorder for the route to be a valid match. + + A function that evaluates the condition when a instance is passed in. + + + + The description of what the route is for. + + A containing the description of the route. + + + + Gets or sets the metadata information for a route. + + A instance. + + + + Gets the method of the route. + + A containing the method of the route. + + + + Gets the path that the route will be invoked for. + + A containing the path of the route. + + + + Gets or set the segments, for the route, that was returned by the . + + An , containing the segments for the route. + + + + The default implementation of a route pattern matching result. + + + + + Initializes a new instance of the class. + + A value indicating if the result was a match or not. + A instance containing the parameters and values that was captured in the match. + The instance of the current request. + + + + Gets the that was active when the result was produced. + + A instance. + + + + Gets a value indicating whether or not a match was made. + + if a match was made; otherwise . + + + + The parameters that could be captured in the route. + + A instance containing the captured parameters and values. + Should be empty if is . + + + + Some simple helpers give some nice authentication syntax in the modules. + + + + + This module requires authentication + + Module to enable + + + + This module requires authentication and certain claims to be present. + + Module to enable + Claim(s) required + + + + This module requires authentication and any one of certain claims to be present. + + Module to enable + Claim(s) required + + + + This module requires claims to be validated + + Module to enable + Claims validator + + + + This module requires https. + + The that requires HTTPS. + + + + This module requires https. + + The that requires HTTPS. + if the user should be redirected to HTTPS (no port number) if the incoming request was made using HTTP, otherwise if should be returned. + + + + This module requires https. + + The that requires HTTPS. + if the user should be redirected to HTTPS if the incoming request was made using HTTP, otherwise if should be returned. + The HTTPS port number to use + + + + Hooks to be used in a request pipeline. + + + + + Creates a hook to be used in a pipeline before a route handler to ensure that + the request was made by an authenticated user. + + Hook that returns an Unauthorized response if not authenticated in, + null otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure + that the request was made by an authenticated user having the required claims. + + Claims the authenticated user needs to have + Hook that returns an Unauthorized response if the user is not + authenticated or does not have the required claims, null otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure + that the request was made by an authenticated user having at least one of + the required claims. + + Claims the authenticated user needs to have at least one of + Hook that returns an Unauthorized response if the user is not + authenticated or does not have at least one of the required claims, null + otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure + that the request was made by an authenticated user whose claims satisfy the + supplied validation function. + + Validation function to be called with the authenticated + users claims + Hook that returns an Unauthorized response if the user is not + authenticated or does not pass the supplied validation function, null + otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure that + the request satisfies a specific test. + + Test that must return true for the request to continue + Hook that returns an Unauthorized response if the test fails, null otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure that + the request satisfies a specific test. + + Test that must return true for the request to continue + Hook that returns an Forbidden response if the test fails, null otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure that + the request satisfies a specific test. + + HttpStatusCode to use for the response + Test that must return true for the request to continue + Hook that returns a response with a specific HttpStatusCode if the test fails, null otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure that + the resource is served over HTTPS + + if the user should be redirected to HTTPS (no port number) if the incoming request was made using HTTP, otherwise if should be returned. + Hook that returns a RedirectResponse with the Url scheme set to HTTPS, + or a Response with a Forbidden HTTP status code if redirect is false or the method is not GET, + null otherwise + + + + Creates a hook to be used in a pipeline before a route handler to ensure that + the resource is served over HTTPS + + if the user should be redirected to HTTPS (no port number) if the incoming request was made using HTTP, otherwise if should be returned. + The HTTPS port number to use + Hook that returns a with the Url scheme set to HTTPS, + or a with a status code if redirect is false or the method is not GET, + null otherwise + + + + Extension methods for working with IUserIdentity. + + + + + Tests if the user is authenticated. + + User to be verified + True if the user is authenticated, false otherwise + + + + Tests if the user has a required claim. + + User to be verified + Claim the user needs to have + True if the user has the required claim, false otherwise + + + + Tests if the user has all of the required claims. + + User to be verified + Claims the user needs to have + True if the user has all of the required claims, false otherwise + + + + Tests if the user has at least one of the required claims. + + User to be verified + Claims the user needs to have at least one of + True if the user has at least one of the required claims, false otherwise + + + + Tests if the user has claims that satisfy the supplied validation function. + + User to be verified + Validation function to be called with the authenticated + users claims + True if the user does pass the supplied validation function, false otherwise + + + + Cookie based session storage + + + + + Allows setting of the serializer for session object storage + + + + + Using the specified serializer + + Serializer to use + + + + Initializes a new instance of the class. + + The encryption provider. + The hmac provider + Session object serializer to use + + + + Initializes a new instance of the class. + + Cookie based sessions configuration. + + + + Initialise and add cookie based session hooks to the application pipeline + + Application pipelines + Cookie based sessions configuration. + Formatter selector for choosing a non-default serializer + + + + Initialise and add cookie based session hooks to the application pipeline + + Application pipelines + Cryptography configuration + Formatter selector for choosing a non-default serializer + + + + Initialise and add cookie based session hooks to the application pipeline with the default encryption provider. + + Application pipelines + Formatter selector for choosing a non-default serializer + + + + Using the specified serializer + + Formatter to use + + + + Save the session into the response + + Session to save + Response to save into + + + + Loads the session from the request + + Request to load from + ISession containing the load session values + + + + Saves the request session into the response + + Nancy context + Session store + + + + Loads the request session + + Nancy context + Session store + Always returns null + + + + Gets the cookie name that the session is stored in + + Cookie name + + + + Default encryption provider using Rijndael + + + + + Creates a new instance of the RijndaelEncryptionProvider class + + Key generator to use to generate the key and iv + + + + Encrypt data + + Data to encrypt + Encrypted string + + + + Decrypt string + + Data to decrypt + Decrypted string + + + + De/Serialisation for cookie objects + + + + + Serialize an object + + Source object + Serialised object string + + + + Deserialize an object string + + Source object string + Deserialized object + + + + Serialize an object + + Source object + Serialised object string + + + + Deserialize an object string + + Source object string + Deserialized object + + + + Defines the interface for a session + + + + + Deletes the session and all associated information + + + + + Deletes the specific key from the session + + + + + The number of session values + + + + + + Retrieves the value from the session + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Deletes the session and all associated information + + + + + Deletes the specific key from the session + + + + + The number of session values + + + + + + Retrieves the value from the session + + + + + Session implementation + + + + + Deletes all items + + + + + Delete an item with the given key + + Key to delete + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the number of items stored + + + + + Gets or sets values + + The key whos value to get or set + The value, or null or the key didn't exist + + + + Gets whether the session has changed + + + + + A decorator stream that sits on top of an existing stream and appears as a unique stream. + + + + + Initializes a new instance of the class. + + The stream to create the sub-stream ontop of. + The start offset on the parent stream where the sub-stream should begin. + The end offset on the parent stream where the sub-stream should end. + + + + When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device. + + In the type this method is implemented as no-op. + + + + When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + + The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. + The zero-based byte offset in at which to begin storing the data read from the current stream. + The maximum number of bytes to be read from the current stream. + + + + Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. + + The unsigned byte cast to an Int32, or -1 if at the end of the stream. + + + + When overridden in a derived class, sets the position within the current stream. + + The new position within the current stream. + A byte offset relative to the parameter. + A value of type indicating the reference point used to obtain the new position. + + + + When overridden in a derived class, sets the length of the current stream. + + The desired length of the current stream in bytes. + This will always throw a for the type. + + + + When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + + An array of bytes. This method copies bytes from to the current stream. + The zero-based byte offset in at which to begin copying bytes to the current stream. + The number of bytes to be written to the current stream. + This will always throw a for the type. + + + + When overridden in a derived class, gets a value indicating whether the current stream supports reading. + + if the stream supports reading; otherwise, . + + + + When overridden in a derived class, gets a value indicating whether the current stream supports seeking. + + if the stream supports seeking; otherwise, . + + + + When overridden in a derived class, gets a value indicating whether the current stream supports writing. + + if the stream supports writing; otherwise, . + + + + When overridden in a derived class, gets the length in bytes of the stream. + + A long value representing the length of the stream in bytes. + A class derived from Stream does not support seeking. Methods were called after the stream was closed. + + + + When overridden in a derived class, gets or sets the position within the current stream. + + + The current position within the stream. + + An I/O error occurs. The stream does not support seeking. Methods were called after the stream was closed. 1 + + + + Gets a generic method from a type given the method name, binding flags, generic types and parameter types + + Source type + Binding flags + Name of the method + Generic types to use to make the method generic + Method parameters + MethodInfo or null if no matches found + + + + + + Name/Value pairs for specifying "user" parameters when resolving + + + + + Attempt to resolve type, even if the type isn't registered. + + Registered types/options will always take precedence. + + + + + Fail resolution if type not explicitly registered + + + + + Attempt to resolve unregistered type if requested type is generic + and no registration exists for the specific generic parameters used. + + Registered types/options will always take precedence. + + + + + Resolution settings + + + + + Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found) + + + + + Preconfigured option for attempting resolution of unregistered types and failing on named resolution if name not found + + + + + Preconfigured option for failing on resolving unregistered types and on named resolution if name not found + + + + + Preconfigured option for failing on resolving unregistered types, but attempting unnamed resolution if name not found + + + + + Attempt to automatically register all non-generic classes and interfaces in the current app domain. + + If more than one class implements an interface then only one implementation will be registered + although no error will be thrown. + + + + + Attempt to automatically register all non-generic classes and interfaces in the current app domain. + Types will only be registered if they pass the supplied registration predicate. + + If more than one class implements an interface then only one implementation will be registered + although no error will be thrown. + + Predicate to determine if a particular type should be registered + + + + Attempt to automatically register all non-generic classes and interfaces in the current app domain. + + What action to take when encountering duplicate implementations of an interface/base class. + + + + + Attempt to automatically register all non-generic classes and interfaces in the current app domain. + Types will only be registered if they pass the supplied registration predicate. + + What action to take when encountering duplicate implementations of an interface/base class. + Predicate to determine if a particular type should be registered + + + + + Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + + If more than one class implements an interface then only one implementation will be registered + although no error will be thrown. + + Assemblies to process + + + + Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + Types will only be registered if they pass the supplied registration predicate. + + If more than one class implements an interface then only one implementation will be registered + although no error will be thrown. + + Assemblies to process + Predicate to determine if a particular type should be registered + + + + Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + + Assemblies to process + What action to take when encountering duplicate implementations of an interface/base class. + + + + + Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + Types will only be registered if they pass the supplied registration predicate. + + Assemblies to process + What action to take when encountering duplicate implementations of an interface/base class. + Predicate to determine if a particular type should be registered + + + + + Creates/replaces a container class registration with default options. + + Type to register + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with default options. + + Type to register + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a given implementation and default options. + + Type to register + Type to instantiate that implements RegisterType + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with a given implementation and default options. + + Type to register + Type to instantiate that implements RegisterType + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a specific, strong referenced, instance. + + Type to register + Instance of RegisterType to register + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with a specific, strong referenced, instance. + + Type to register + Instance of RegisterType to register + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a specific, strong referenced, instance. + + Type to register + Type of instance to register that implements RegisterType + Instance of RegisterImplementation to register + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with a specific, strong referenced, instance. + + Type to register + Type of instance to register that implements RegisterType + Instance of RegisterImplementation to register + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a user specified factory + + Type to register + Factory/lambda that returns an instance of RegisterType + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a user specified factory + + Type to register + Factory/lambda that returns an instance of RegisterType + Name of registation + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with default options. + + Type to register + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with default options. + + Type to register + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a given implementation and default options. + + Type to register + Type to instantiate that implements RegisterType + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with a given implementation and default options. + + Type to register + Type to instantiate that implements RegisterType + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a specific, strong referenced, instance. + + Type to register + Instance of RegisterType to register + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with a specific, strong referenced, instance. + + Type to register + Instance of RegisterType to register + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a specific, strong referenced, instance. + + Type to register + Type of instance to register that implements RegisterType + Instance of RegisterImplementation to register + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with a specific, strong referenced, instance. + + Type to register + Type of instance to register that implements RegisterType + Instance of RegisterImplementation to register + Name of registration + RegisterOptions for fluent API + + + + Creates/replaces a container class registration with a user specified factory + + Type to register + Factory/lambda that returns an instance of RegisterType + RegisterOptions for fluent API + + + + Creates/replaces a named container class registration with a user specified factory + + Type to register + Factory/lambda that returns an instance of RegisterType + Name of registation + RegisterOptions for fluent API + + + + Register multiple implementations of a type. + + Internally this registers each implementation using the full name of the class as its registration name. + + Type that each implementation implements + Types that implement RegisterType + MultiRegisterOptions for the fluent API + + + + Register multiple implementations of a type. + + Internally this registers each implementation using the full name of the class as its registration name. + + Type that each implementation implements + Types that implement RegisterType + MultiRegisterOptions for the fluent API + + + + Attempts to resolve a type using default options. + + Type to resolve + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using specified options. + + Type to resolve + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using default options and the supplied name. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + Name of registration + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using supplied options and name. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + Name of registration + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using default options and the supplied constructor parameters. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + User specified constructor parameters + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using specified options and the supplied constructor parameters. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + User specified constructor parameters + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using default options and the supplied constructor parameters and name. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + User specified constructor parameters + Name of registration + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a named type using specified options and the supplied constructor parameters. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + Name of registration + User specified constructor parameters + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using default options. + + Type to resolve + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using specified options. + + Type to resolve + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using default options and the supplied name. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + Name of registration + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using supplied options and name. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + Name of registration + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using default options and the supplied constructor parameters. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + User specified constructor parameters + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using specified options and the supplied constructor parameters. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + User specified constructor parameters + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a type using default options and the supplied constructor parameters and name. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + User specified constructor parameters + Name of registration + Instance of type + Unable to resolve the type. + + + + Attempts to resolve a named type using specified options and the supplied constructor parameters. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Type to resolve + Name of registration + User specified constructor parameters + Resolution options + Instance of type + Unable to resolve the type. + + + + Attempts to predict whether a given type can be resolved with default options. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with default options. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given type can be resolved with the specified options. + + Note: Resolution may still fail if user defined factory registrations fail to construct objects when called. + + Type to resolve + Name of registration + Resolution options + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with the specified options. + + Note: Resolution may still fail if user defined factory registrations fail to construct objects when called. + + Type to resolve + Name of registration + Resolution options + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + User supplied named parameter overloads + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + User supplied named parameter overloads + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given type can be resolved with the supplied constructor parameters options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + User supplied named parameter overloads + Resolution options + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + User supplied named parameter overloads + Resolution options + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given type can be resolved with default options. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with default options. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given type can be resolved with the specified options. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + Resolution options + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with the specified options. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + Resolution options + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + User supplied named parameter overloads + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + User supplied named parameter overloads + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given type can be resolved with the supplied constructor parameters options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registrations fail to construct objects when called. + + Type to resolve + User supplied named parameter overloads + Resolution options + Bool indicating whether the type can be resolved + + + + Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options. + + Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + + Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + + Type to resolve + Name of registration + User supplied named parameter overloads + Resolution options + Bool indicating whether the type can be resolved + + + + Attemps to resolve a type using the default options + + Type to resolve + Resolved type or default if resolve fails + True if resolved sucessfully, false otherwise + + + + Attemps to resolve a type using the given options + + Type to resolve + Resolution options + Resolved type or default if resolve fails + True if resolved sucessfully, false otherwise + + + + Attemps to resolve a type using the default options and given name + + Type to resolve + Name of registration + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the given options and name + + Type to resolve + Name of registration + Resolution options + Resolved type or default if resolve fails + True if resolved sucessfully, false otherwise + + + + Attemps to resolve a type using the default options and supplied constructor parameters + + Type to resolve + User specified constructor parameters + Resolved type or default if resolve fails + True if resolved sucessfully, false otherwise + + + + Attemps to resolve a type using the default options and supplied name and constructor parameters + + Type to resolve + Name of registration + User specified constructor parameters + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the supplied options and constructor parameters + + Type to resolve + Name of registration + User specified constructor parameters + Resolution options + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the supplied name, options and constructor parameters + + Type to resolve + Name of registration + User specified constructor parameters + Resolution options + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the default options + + Type to resolve + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the given options + + Type to resolve + Resolution options + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the default options and given name + + Type to resolve + Name of registration + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the given options and name + + Type to resolve + Name of registration + Resolution options + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the default options and supplied constructor parameters + + Type to resolve + User specified constructor parameters + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the default options and supplied name and constructor parameters + + Type to resolve + Name of registration + User specified constructor parameters + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the supplied options and constructor parameters + + Type to resolve + Name of registration + User specified constructor parameters + Resolution options + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Attemps to resolve a type using the supplied name, options and constructor parameters + + Type to resolve + Name of registration + User specified constructor parameters + Resolution options + Resolved type or default if resolve fails + True if resolved successfully, false otherwise + + + + Returns all registrations of a type + + Type to resolveAll + Whether to include un-named (default) registrations + IEnumerable + + + + Returns all registrations of a type, both named and unnamed + + Type to resolveAll + IEnumerable + + + + Returns all registrations of a type + + Type to resolveAll + Whether to include un-named (default) registrations + IEnumerable + + + + Returns all registrations of a type, both named and unnamed + + Type to resolveAll + Whether to include un-named (default) registrations + IEnumerable + + + + Attempts to resolve all public property dependencies on the given object. + + Object to "build up" + + + + Attempts to resolve all public property dependencies on the given object using the given resolve options. + + Object to "build up" + Resolve options to use + + + + Lazy created Singleton instance of the container for simple scenarios + + + + + Registration options for "fluent" API + + + + + Make registration a singleton (single instance) if possible + + RegisterOptions + + + + + Make registration multi-instance if possible + + RegisterOptions + + + + + Make registration hold a weak reference if possible + + RegisterOptions + + + + + Make registration hold a strong reference if possible + + RegisterOptions + + + + + Switches to a custom lifetime manager factory if possible. + + Usually used for RegisterOptions "To*" extension methods such as the ASP.Net per-request one. + + RegisterOptions instance + Custom lifetime manager + Error string to display if switch fails + RegisterOptions + + + + Registration options for "fluent" API when registering multiple implementations + + + + + Initializes a new instance of the MultiRegisterOptions class. + + Registration options + + + + Make registration a singleton (single instance) if possible + + RegisterOptions + + + + + Make registration multi-instance if possible + + MultiRegisterOptions + + + + + Switches to a custom lifetime manager factory if possible. + + Usually used for RegisterOptions "To*" extension methods such as the ASP.Net per-request one. + + MultiRegisterOptions instance + Custom lifetime manager + Error string to display if switch fails + MultiRegisterOptions + + + + Provides custom lifetime management for ASP.Net per-request lifetimes etc. + + + + + Gets the stored object if it exists, or null if not + + Object instance or null + + + + Store the object + + Object to store + + + + Release the object + + + + + Create the type + + Type user requested to be resolved + Container that requested the creation + Any user parameters passed + + + + + + Whether to assume this factory successfully constructs its objects + + Generally set to true for delegate style factories as CanResolve cannot delve + into the delegates they contain. + + + + + The type the factory instantiates + + + + + Constructor to use, if specified + + + + + IObjectFactory that creates new instances of types for each resolution + + + + + IObjectFactory that invokes a specified delegate to construct the object + + + + + IObjectFactory that invokes a specified delegate to construct the object + Holds the delegate using a weak reference + + + + + Stores an particular instance to return for a type + + + + + Stores an particular instance to return for a type + + Stores the instance with a weak reference + + + + + A factory that lazy instantiates a type and always returns the same instance + + + + + A factory that offloads lifetime to an external lifetime provider + + + + + Defines the functionality of an engine that can handle Nancy s. + + + + + Handles an incoming async. + + An instance, containing the information about the current request. + Delegate to call before the request is processed + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + The task object representing the asynchronous operation. + + + + Factory for creating an instance for a incoming request. + + An instance. + + + + Encapsulates HTTP-request information to an Nancy application. + + + + + Initializes a new instance of the class. + + The HTTP data transfer method used by the client. + The path of the requested resource, relative to the "Nancy root". This should not include the scheme, host name, or query portion of the URI. + The HTTP protocol that was used by the client. + + + + Initializes a new instance of the class. + + The HTTP data transfer method used by the client. + The url of the requested resource + The headers that was passed in by the client. + The that represents the incoming HTTP body. + The client's IP address + The client's certificate when present. + The HTTP protocol version. + + + + Gets the cookie data from the request header if it exists + + Cookies dictionary + + + + Gets the certificate sent by the client. + + + + + Gets the HTTP protocol version. + + + + + Gets the IP address of the client + + + + + Gets or sets the HTTP data transfer method used by the client. + + The method. + + + + Gets the url + + + + + Gets the request path, relative to the base path. + Used for route matching etc. + + + + + Gets the query string data of the requested resource. + + A instance, containing the key/value pairs of query string data. + + + + Gets a that can be used to read the incoming HTTP body + + A object representing the incoming HTTP body. + + + + Gets the request cookies. + + + + + Gets the current session. + + + + + Gets a collection of files sent by the client- + + An instance, containing an instance for each uploaded file. + + + + Gets the form data of the request. + + A instance, containing the key/value pairs of form data. + Currently Nancy will only parse form data sent using the application/x-www-url-encoded mime-type. + + + + Gets the HTTP headers sent by the client. + + An containing the name and values of the headers. + The values are stored in an of string to be compliant with multi-value headers. + + + + Default engine for handling Nancy s. + + + + + Initializes a new instance of the class. + + An instance that will be used to resolve a route, from the modules, that matches the incoming . + A factory for creating contexts + Error handlers + The request tracing instance. + + The provider to use for serving static content + + + + Factory for creating an instance for a incoming request. + + An instance. + + + + Returns a route that matches the request + + + + + Gets the route, and the corresponding parameter dictionary from the URL + + Current context + A containing the resolved route information. + + + + Route that is returned when the path could not be matched. + + This is equal to sending back the 404 HTTP status code. + + + + Initializes a new instance of the type, for the + specified and . + + The HTTP method of the route. + The path of the route. + + + + A dictionary that supports dynamic access. + + + + + Creates a dynamic dictionary from an instance. + + An instance, that the dynamic dictionary should be created from. + An instance. + + + + Provides the implementation for operations that set member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as setting a value for a property. + + true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) + Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member to which the value is being assigned. For example, for the statement sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.The value to set to the member. For example, for sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the class, the is "Test". + + + + Provides the implementation for operations that get member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. + + true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) + Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.The result of the get operation. For example, if the method is called for a property, you can assign the property value to . + + + + Returns the enumeration of all dynamic member names. + + A that contains dynamic member names. + + + + Returns the enumeration of all dynamic member names. + + A that contains dynamic member names. + + + + Returns the enumeration of all dynamic member names. + + A that contains dynamic member names. + + + + Indicates whether the current is equal to another object of the same type. + + if the current instance is equal to the parameter; otherwise, . + An instance to compare with this instance. + + + + Determines whether the specified is equal to this instance. + + The to compare with this instance. + if the specified is equal to this instance; otherwise, . + + + + Returns an enumerator that iterates through the collection. + + A that can be used to iterate through the collection. + + + + Returns a hash code for this . + + A hash code for this , suitable for use in hashing algorithms and data structures like a hash table. + + + + Adds an element with the provided key and value to the . + + The object to use as the key of the element to add. + The object to use as the value of the element to add. + + + + Adds an item to the . + + The object to add to the . + + + + Determines whether the contains an element with the specified key. + + if the contains an element with the key; otherwise, . + + The key to locate in the . + + + + Gets the value associated with the specified key. + + if the contains an element with the specified key; otherwise, . + The key whose value to get. + When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. + + + + Removes all items from the . + + + + + Determines whether the contains a specific value. + + if is found in the ; otherwise, . + + The object to locate in the . + + + + Copies the elements of the to an , starting at a particular index. + + The one-dimensional that is the destination of the elements copied from the . The must have zero-based indexing. + The zero-based index in at which copying begins. + + + + Removes the element with the specified key from the . + + if the element is successfully removed; otherwise, . + The key of the element to remove. + + + + Removes the first occurrence of a specific object from the . + + if was successfully removed from the ; otherwise, . + The object to remove from the . + + + + Gets a typed Dictionary of from + + Gets a typed Dictionary of from + + + + Returns an empty dynamic dictionary. + + A instance. + + + + Gets or sets the with the specified name. + + A instance containing a value. + + + + Gets an containing the keys of the . + + An containing the keys of the . + + + + Gets the number of elements contained in the . + + The number of elements contained in the . + + + + Gets a value indicating whether the is read-only. + + Always returns . + + + + Gets an containing the values in the . + + An containing the values in the . + + + + Default implementation of the interface. + + + + + Initializes a new instance of the class, using + the provided , , + and . + + A instance. + A instance. + A instance. + A instance. + + + + Gets the route, and the corresponding parameter dictionary from the URL + + Current context + A containing the resolved route information. + + + + Thrown when multiple instances describe the exact same view. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The message that should be displayed with the exception. + + + + The default implementation for how views are resolved and rendered by Nancy. + + + + + Defines the functionality used by a to render a view to the response. + + + + + Renders the view with the name and model defined by the and parameters. + + The name of the view to render. + The module path of the module that is rendering the view. + A instance, containing information about the context for which the view is being rendered. + A response. + + + + Initializes a new instance of the class. + + An instance that should be used to resolve the location of a view. + An instance containing the instances that should be able to be used to render a view + A instance that should be used to create an when a view is rendered. + An instance that should be used to resolve all possible view locations + An instance. + + + + Renders the view with the name and model defined by the and parameters. + + The name of the view to render. + The model that should be passed into the view. + A instance, containing information about the context for which the view is being rendered. + A delegate that can be invoked with the that the view should be rendered to. + + + + The default implementation for how views are located by Nancy. + + + + + Defines the functionality for locating the requested view. + + + + + Gets the location of the view defined by the parameter. + + Name of the view to locate. + The instance for the current request. + A instance if the view could be located; otherwise . + + + + Gets all the views that are currently discovered + Note: this is *not* the recommended way to deal with the view locator + as it doesn't allow for runtime discovery of views with the + settings. + + A collection of instances + + + + Gets the location of the view defined by the parameter. + + Name of the view to locate. + The instance for the current request. + A instance if the view could be located; otherwise . + + + + Gets all the views that are currently discovered + Note: this is *not* the recommended way to deal with the view locator + as it doesn't allow for runtime discovery of views with the + settings. + + A collection of instances + + + + Default implementation on how views are resolved by Nancy. + + + + + Initializes a new instance of the class. + + The view locator that should be used to locate views. + The conventions that the view resolver should use to figure out where to look for views. + + + + Locates a view based on the provided information. + + The name of the view to locate. + The model that will be used with the view. + A instance, containing information about the context for which the view is being located. + A instance if the view could be found, otherwise . + + + + View location result for file system based views. + Supports detecting if the contents have changed since it + was last read. + + + + + Contains the result of an attempt to locate a view. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The location of where the view was found. + The name of the view. + The file extension of the located view. + A that can be used to read the contents of the located view. + + + + Gets a value indicating whether the current item is stale + + True if stale, false otherwise + + + + Indicates whether the current object is equal to another object of the same type. + + if the current object is equal to the parameter; otherwise, . + An to compare with this instance. + + + + Determines whether the specified is equal to the current . + + if the specified is equal to the current ; otherwise, . + The to compare with the current . + + + + Serves as a hash function for a particular type. + + A hash code for the current . + + + + Gets a function that produces a reader for retrieving the contents of the view. + + A instance that can be used to produce a reader for retrieving the contents of the view. + + + + Gets the extension of the view that was located. + + A containing the extension of the view that was located. + The extension should not contain a leading dot. + + + + Gets the location of where the view was found. + + A containing the location of the view. + + + + Gets the full name of the view that was found + + A containing the name of the view. + + + + Initializes a new instance of the class. + + The location of where the view was found. + The name of the view. + The file extension of the located view. + A that can be used to read the contents of the located view. + Full filename of the file + An instance that should be used when retrieving view information from the file system. + + + + Gets a value indicating whether the current item is stale + + True if stale, false otherwise + + + + Wraps the real contents delegate to set the last modified date first + + TextReader to read the file + + + + Defines the functionality that a view engine must support to be integrated into Nancy. + + + + + Initialise the view engine (if necessary) + + Startup context + + + + Renders the view. + + A instance, containing information on how to get the view template. + The model that should be passed into the view + + A response + + + + Gets the extensions file extensions that are supported by the view engine. + + An instance containing the extensions. + The extensions should not have a leading dot in the name. + + + + Contains the functionality for locating a view that has been embedded into an assembly resource. + + + + + User-configured root namespaces for assemblies. + + + + + A list of assemblies to ignore when scanning for embedded views. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + An instance that should be used when extracting embedded views. + An instance that should be used to determine which assemblies to scan for embedded views. + + + + Returns an instance for all the views that could be located by the provider. + + An instance, containing the view engine file extensions that is supported by the running instance of Nancy. + An instance, containing instances for the located views. + If no views could be located, this method should return an empty enumerable, never . + + + + Returns an instance for all the views matching the viewName that could be located by the provider. + + An instance, containing the view engine file extensions that is supported by the running instance of Nancy. + The name of the view to try and find + An instance, containing instances for the located views. + If no views could be located, this method should return an empty enumerable, never . + + + + Matches and modifies the content of a rendered SuperSimpleViewEngine view. + + + + + Invokes the matcher on the content of the rendered view. + + The content of the rendered view. + The model that was passed to the view. + The host. + The modified version of the view. + + + + Provides the view engine with utility functions for + encoding, locating partial view templates etc. + + + + + Html "safe" encode a string + + Input string + Encoded string + + + + Get the contents of a template + + Name/location of the template + Model to use to locate the template via conventions + Contents of the template, or null if not found + + + + Gets a uri string for a named route + + Named route name + Parameters to use to expand the uri string + Expanded uri string, or null if not found + + + + Expands a path to include any base paths + + Path to expand + Expanded path + + + + Get the anti forgery token form element + + String containing the form element + + + + Context object of the host application. + + An instance of the context object from the host. + + + + Initializes a new instance of the class. + + + The render context. + + + + + Html "safe" encode a string + + Input string + Encoded string + + + + Get the contents of a template + + Name/location of the template + Model to use to locate the template via conventions + Contents of the template, or null if not found + + + + Gets a uri string for a named route + + Named route name + Parameters to use to expand the uri string + Expanded uri string, or null if not found + + + + Expands a path to include any base paths + + Path to expand + Expanded path + + + + Get the anti forgery token form element + + String containing the form element + + + + Context object of the host application. + + An instance of the context object from the host. + + + + A super-simple view engine + + + + + Compiled Regex for viewbag substitutions + + + + + Compiled Regex for single substitutions + + + + + Compiled Regex for context subsituations + + + + + Compiled Regex for each blocks + + + + + Compiled Regex for each block current substitutions + + + + + Compiled Regex for if blocks + + + + + Compiled regex for partial blocks + + + + + Compiled RegEx for section block declarations + + + + + Compiled RegEx for section block contents + + + + + Compiled RegEx for master page declaration + + + + + Compiled RegEx for path expansion + + + + + Compiled RegEx for path expansion in attribute values + + + + + Compiled RegEx for the CSRF anti forgery token + + + + + View engine transform processors + + + + + View engine extensions + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class, using + the provided extensions. + + The matchers to use with the engine. + + + + Renders a template + + The template to render. + The model to user for rendering. + The view engine host + A string containing the expanded template. + + + + + Gets a property value from the given model. + + + Anonymous types, standard types and ExpandoObject are supported. + Arbitrary dynamics (implementing IDynamicMetaObjectProvider) are not, unless + they also implement IDictionary string, object for accessing properties. + + + The model. + The property name to evaluate. + Tuple - Item1 being a bool for whether the evaluation was successful, Item2 being the value. + Model type is not supported. + + + + A property extractor for standard types. + + The model. + The property name. + Tuple - Item1 being a bool for whether the evaluation was successful, Item2 being the value. + + + + A property extractor designed for ExpandoObject, but also for any + type that implements IDictionary string object for accessing its + properties. + + The model. + The property name. + Tuple - Item1 being a bool for whether the evaluation was successful, Item2 being the value. + + + + Gets an IEnumerable of capture group values + + The match to use. + Group name containing the capture group. + IEnumerable of capture group values as strings. + + + + Gets a property value from a collection of nested parameter names + + The model containing properties. + A collection of nested parameters (e.g. User, Name + Tuple - Item1 being a bool for whether the evaluation was successful, Item2 being the value. + + + + Gets the predicate result for an If or IfNot block + + The item to evaluate + Property list to evaluate + Whether to check for null, rather than straight boolean + Bool representing the predicate result + + + + Returns the predicate result if the substitionObject is a valid bool + + The substitution object. + + Bool value of the substitutionObject, or false if unable to cast. + + + + Returns the predicate result if the substitionObject is a valid ICollection + + The substitution object. + Bool value of the whether the ICollection has items, or false if unable to cast. + + + + Performs single @ViewBag.PropertyName substitutions. + + The template. + This parameter is not used, the model is based on the "host.Context.ViewBag". + View engine host + Template with @ViewBag.PropertyName blocks expanded. + + + + Performs single @Model.PropertyName substitutions. + + The template. + The model. + View engine host + Template with @Model.PropertyName blocks expanded. + + + + Performs single @Context.PropertyName substitutions. + + The template. + The model. + View engine host + Template with @Context.PropertyName blocks expanded. + + + + Performs @Each.PropertyName substitutions + + The template. + The model. + View engine host + Template with @Each.PropertyName blocks expanded. + + + + Expand a @Current match inside an @Each iterator + + Contents of the @Each block + Current item from the @Each enumerable + View engine host + String result of the expansion of the @Each. + + + + Performs @If.PropertyName and @IfNot.PropertyName substitutions + + The template. + The model. + View engine host + Template with @If.PropertyName @IfNot.PropertyName blocks removed/expanded. + + + + Perform path expansion substitutions + + The template. + The model. + View engine host + Template with paths expanded + + + + Perform CSRF anti forgery token expansions + + The template. + The model. + View engine host + Template with anti forgery tokens expanded + + + + Perform @Partial partial view expansion + + The template. + The model. + View engine host + Template with partials expanded + + + + Invokes the master page rendering with current sections if necessary + + The template. + The model. + View engine host + Template with master page applied and sections substituted + + + + Renders a master page - does a normal render then replaces any section tags with sections passed in + + The master page template + Dictionary of section contents + The model. + View engine host + Template with the master page applied and sections substituted + + + + Gets the master page name, if one is specified + + The template + Master page name or String.Empty + + + + Performs application registrations for the SuperSimpleViewEngine. + + + + + Gets the type registrations to register for this startup task + + + + + Gets the collection registrations to register for this startup task + + + + + Gets the instance registrations to register for this startup task + + + + + Nancy IViewEngine wrapper for the super simple view engine + + + + + Extensions that the view engine supports + + + + + The engine itself + + + + + Initializes a new instance of the class, using + the provided extensions. + + The matchers to use with the engine. + + + + Initialise the view engine (if necessary) + + Startup context + + + + Renders the view. + + A instance, containing information on how to get the view template. + The model that should be passed into the view + An instance. + A response + + + + Gets the extensions file extensions that are supported by the view engine. + + An instance containing the extensions. + The extensions should not have a leading dot in the name. + + + + Calls the initialize method on all implementations, at application startup. + + + + + Initializes a new instance of the class, with the + provided , and . + + The available view engines. + The view cache. + The view locator. + + + + Perform any initialisation tasks + + Application pipelines + + + + Context passed to each view engine on startup + + + + + Gets the Nancy view cache - can be used to precompile views at startup + if necessary. + + + + + Gets the Nancy view locator + + + + + The context for which a view is being located. + + + + + The module path of the that is locating a view. + + A containing the module path. + + + + The name of the that is locating a view. + + A containing the name of the module. + + + + The request/response context + + + + + Exception that is thrown when a view could not be located. + + + + + Initializes a new instance of the . + + The name of the view that was being located. + List of available view extensions that can be rendered by the available view engines. + The locations that were inspected for the view. + An instance. + + + + Initializes a new instance of the + + A message describing the problem + + + + Gets a message that describes the current exception. + + The error message that explains the reason for the exception, or an empty string(""). + + + + An exception that indicates the view could not be rendered + + + + + Create an instance of + + A description of the rendering problem + + + + Create an instance of + + A description of the rendering problem + The exception that is the cause of the current exception. + + + + Helper class for rendering a view from a route handler. + + + + + Initializes a new instance of the class. + + The instance that is rendering the view. + + + + Renders the view with its name resolved from the model type, and model defined by the parameter. + + The model that should be passed into the view. + A delegate that can be invoked with the that the view should be rendered to. + The view name is model.GetType().Name with any Model suffix removed. + + + + Renders the view with the name defined by the parameter. + + The name of the view to render. + A delegate that can be invoked with the that the view should be rendered to. + The extension in the view name is optional. If it is omitted, then Nancy will try to resolve which of the available engines that should be used to render the view. + + + + Renders the view with the name and model defined by the and parameters. + + The name of the view to render. + The model that should be passed into the view. + A delegate that can be invoked with the that the view should be rendered to. + The extension in the view name is optional. If it is omitted, then Nancy will try to resolve which of the available engines that should be used to render the view. + + + + Gets or sets whether character encoding should be enabled, or not, for XML responses. + + + The default value is + + + + + Gets the default encoding for XML responses. + + + The default value is + + + + diff --git a/packages/Nancy.Hosting.Self.1.2.0/Nancy.Hosting.Self.1.2.0.nupkg b/packages/Nancy.Hosting.Self.1.2.0/Nancy.Hosting.Self.1.2.0.nupkg new file mode 100644 index 0000000..8816b8d Binary files /dev/null and b/packages/Nancy.Hosting.Self.1.2.0/Nancy.Hosting.Self.1.2.0.nupkg differ diff --git a/packages/Nancy.Hosting.Self.1.2.0/Nancy.Hosting.Self.1.2.0.nuspec b/packages/Nancy.Hosting.Self.1.2.0/Nancy.Hosting.Self.1.2.0.nuspec new file mode 100644 index 0000000..a389906 --- /dev/null +++ b/packages/Nancy.Hosting.Self.1.2.0/Nancy.Hosting.Self.1.2.0.nuspec @@ -0,0 +1,21 @@ + + + + Nancy.Hosting.Self + 1.2.0 + Andreas Håkansson, Steven Robbins and contributors + Andreas Håkansson, Steven Robbins and contributors + https://github.com/NancyFx/Nancy/blob/master/license.txt + http://nancyfx.org/ + http://nancyfx.org/nancy-nuget.png + false + Enables hosting Nancy in any application. + Nancy is a lightweight web framework for the .Net platform, inspired by Sinatra. Nancy aim at delivering a low ceremony approach to building light, fast web applications. + Andreas Håkansson, Steven Robbins and contributors + en-US + Nancy + + + + + \ No newline at end of file diff --git a/packages/Nancy.Hosting.Self.1.2.0/lib/net40/Nancy.Hosting.Self.dll b/packages/Nancy.Hosting.Self.1.2.0/lib/net40/Nancy.Hosting.Self.dll new file mode 100644 index 0000000..3667ef5 Binary files /dev/null and b/packages/Nancy.Hosting.Self.1.2.0/lib/net40/Nancy.Hosting.Self.dll differ diff --git a/packages/Nancy.Hosting.Self.1.2.0/lib/net40/Nancy.Hosting.Self.xml b/packages/Nancy.Hosting.Self.1.2.0/lib/net40/Nancy.Hosting.Self.xml new file mode 100644 index 0000000..629395c --- /dev/null +++ b/packages/Nancy.Hosting.Self.1.2.0/lib/net40/Nancy.Hosting.Self.xml @@ -0,0 +1,216 @@ + + + + Nancy.Hosting.Self + + + + + A helper class that checks for a header against a list of headers that should be ignored + when populating the headers of an object. + + + + + Determines if a header is ignored when populating the headers of an + object. + + The name of the header. + true if the header is ignored; otherwise, false. + + + + Configuration for automatic url reservation creation + + + + + Gets or sets a value indicating whether url reservations + are automatically created when necessary. + Defaults to false. + + + + + Gets or sets a value for the user to use to create the url reservations for. + Defaults to the "Everyone" group. + + + + + Helpers for UAC + + + + + Run an executable elevated + + File to execute + Arguments to pass to the executable + True if successful, false otherwise + + + + Host configuration for the self host + + + + + Gets or sets a property that determines if localhost uris are + rewritten to htp://+:port/ style uris to allow for listening on + all ports, but requiring either a url reservation, or admin + access + Defaults to true. + + + + + Configuration around automatically creating url reservations + + + + + Gets or sets a property that determines if Transfer-Encoding: Chunked is allowed + for the response instead of Content-Length (default: true). + + + + + Gets or sets a property that provides a callback to be called + if there's an unhandled exception in the self host. + Note: this will *not* be called for normal nancy Exceptions + that are handled by the Nancy handlers. + Defaults to writing to debug out. + + + + + Gets or sets a property that determines whether client certificates + are enabled or not. + When set to true the self host will request a client certificate if the + request is running over SSL. + Defaults to false. + + + + + Gets or sets a property determining if base uri matching can fall back to just + using Authority (Schema + Host + Port) as base uri if it cannot match anything in + the known list. This should only be set to True if you have issues with port forwarding + (e.g. on Azure). + + + + + Allows to host Nancy server inside any application - console or windows service. + + + NancyHost uses internally. Therefore, it requires full .net 4.0 profile (not client profile) + to run. will launch a thread that will listen for requests and then process them. Each request is processed in + its own execution thread. NancyHost needs in order to be used from another appdomain under + mono. Working with AppDomains is necessary if you want to unload the dependencies that come with NancyHost. + + + + + Initializes a new instance of the class for the specified . + Uses the default configuration + + The s that the host will listen to. + + + + Initializes a new instance of the class for the specified . + Uses the specified configuration. + + The s that the host will listen to. + Configuration to use + + + + Initializes a new instance of the class for the specified , using + the provided . + Uses the default configuration + + The bootstrapper that should be used to handle the request. + The s that the host will listen to. + + + + Initializes a new instance of the class for the specified , using + the provided . + Uses the specified configuration. + + The bootstrapper that should be used to handle the request. + Configuration to use + The s that the host will listen to. + + + + Initializes a new instance of the class for the specified , using + the provided . + Uses the default configuration + + The that the host will listen to. + The bootstrapper that should be used to handle the request. + + + + Initializes a new instance of the class for the specified , using + the provided . + Uses the specified configuration. + + The that the host will listen to. + The bootstrapper that should be used to handle the request. + Configuration to use + + + + Stops the host if it is running. + + + + + Start listening for incoming requests with the given configuration + + + + + Stop listening for incoming requests. + + + + + Executes NetSh commands + + + + + Add a url reservation + + Url to add + User to add the reservation for + True if successful, false otherwise. + + + + Exception for when automatic address reservation creation fails. + Provides the user with manual instructions. + + + + + Gets a message that describes the current exception. + + + The error message that explains the reason for the exception, or an empty string(""). + + 1 + + + + Extension methods for working with instances. + + + + diff --git a/prebuild.xml b/prebuild.xml new file mode 100644 index 0000000..91ea772 --- /dev/null +++ b/prebuild.xml @@ -0,0 +1,190 @@ + + + + + + TRACE;DEBUG + false + false + true + 4 + false + 1591,1574,0419,0618 + bin + true + true + false + + + + + TRACE + true + false + true + 4 + false + 1591,1574,0419,0618 + bin + false + true + false + + + + + + + + + + ../bin/ + + + + + ../bin/ + OpenMetaverseTypes.XML + + + + ../bin/ + + + + + + + + + + + ../bin/ + + + + + ../bin/ + OpenMetaverse.StructuredData.XML + + + + ../bin/ + + + + + + + + + + + + ../bin/ + + + + + ../bin/ + OpenMetaverse.XML + + + + ../bin/ + + + + + + + + + + + + + + + + + + + + ../bin/ + + + + + ../bin/ + OpenMetaverse.Utilities.XML + + + + ../bin/ + + + + + + + + + + + + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + + + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + + + diff --git a/runprebuild.sh b/runprebuild.sh new file mode 100755 index 0000000..f48aeba --- /dev/null +++ b/runprebuild.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +mono bin/Prebuild.exe /target nant +mono bin/Prebuild.exe /target monodev +mono bin/Prebuild.exe /target vs2010 + +if [ x$1 == xnant ]; then + nant -buildfile:OpenMetaverse.build + RES=$? + echo Build Exit Code: $RES + if [ x$2 == xruntests ]; then + nunit-console bin/OpenMetaverse.Tests.dll -exclude=Network -labels -xml=testresults.xml + fi + + exit $RES +fi + +if [ x$1 == xprimrender ]; then + nant -buildfile:OpenMetaverse.Rendering.GPL.build + exit $? +fi + +if [ x$1 == xopenjpeg ]; then + ARCH=`arch` + cd openjpeg-dotnet + if [ $ARCH == x86_64 ]; then + # since we're a 64bit host, compile a 32bit vesion of openjpeg + make ARCH=-i686 ARCHFLAGS=-m32 install + fi + # compile for default detected platform + make install +fi