diff --git a/SLProxy/SLProxy.cs b/SLProxy/SLProxy.cs index fa8a7a50..f9b291dc 100644 --- a/SLProxy/SLProxy.cs +++ b/SLProxy/SLProxy.cs @@ -45,7 +45,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Xml; using libsecondlife; -using libsecondlife.LLSD; +using libsecondlife.StructuredData; using libsecondlife.Packets; // SLProxy: proxy library for Second Life @@ -604,7 +604,7 @@ namespace SLProxy if (cap.ReqFmt == CapsDataFormat.LLSD) { - content = LLSDParser.SerializeXmlBytes(capReq.Request); + content = LLSDParser.SerializeXmlBytes((LLSD)capReq.Request); } else { @@ -612,7 +612,8 @@ namespace SLProxy } } - byte[] respBuf = null; string consoleMsg = ""; + byte[] respBuf = null; + string consoleMsg = String.Empty; if (shortCircuit) { @@ -750,7 +751,7 @@ namespace SLProxy if (cap.RespFmt == CapsDataFormat.LLSD) { - respBuf = LLSDParser.SerializeXmlBytes(capReq.Response); + respBuf = LLSDParser.SerializeXmlBytes((LLSD)capReq.Response); } else { diff --git a/bin/openjpeg-libsl.dll b/bin/openjpeg-libsl.dll index 12a5f479..5f74acb2 100644 Binary files a/bin/openjpeg-libsl.dll and b/bin/openjpeg-libsl.dll differ diff --git a/importprimscript/importprimscript.cs b/importprimscript/importprimscript.cs index 197c9a37..92a0111e 100644 --- a/importprimscript/importprimscript.cs +++ b/importprimscript/importprimscript.cs @@ -20,8 +20,7 @@ namespace importprimscript class importprimscript { - static SecondLife Client; - static AssetManager Assets; + static SecondLife Client = new SecondLife(); static Sculpt CurrentSculpt = null; static AutoResetEvent RezzedEvent = new AutoResetEvent(false); static LLVector3 RootPosition = LLVector3.Zero; @@ -61,10 +60,6 @@ namespace importprimscript Environment.Exit(-3); } - // Initialize libsecondlife - Client = new SecondLife(); - Assets = new AssetManager(Client); - // Add callback handlers for asset uploads finishing. new prims spotted, and logging Client.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim); Client.OnLogMessage += new SecondLife.LogCallback(Client_OnLogMessage); @@ -102,7 +97,7 @@ namespace importprimscript string start = NetworkManager.StartLocation(args[3], x, y, z); // Attempt to login - if (!Client.Network.Login(args[0], args[1], args[2], "importprimscript 1.1.0", start, + if (!Client.Network.Login(args[0], args[1], args[2], "importprimscript 1.3.0", start, "John Hurliman ")) { Console.WriteLine("Login failed: " + Client.Network.LoginMessage); diff --git a/libsecondlife/AgentManager.cs b/libsecondlife/AgentManager.cs index 8b07a8b7..76837edb 100644 --- a/libsecondlife/AgentManager.cs +++ b/libsecondlife/AgentManager.cs @@ -693,9 +693,6 @@ namespace libsecondlife public LLVector3 Acceleration { get { return acceleration; } } /// public LLVector3 AngularVelocity { get { return angularVelocity; } } - /// The point the avatar is currently looking at - /// (may not stay updated) - public LLVector3 LookAt { get { return lookAt; } } /// Position avatar client will goto when login to 'home' or during /// teleport request to 'home' region. public LLVector3 HomePosition { get { return homePosition; } } @@ -827,7 +824,6 @@ namespace libsecondlife private LLUUID secureSessionID; private string startLocation = String.Empty; private string agentAccess = String.Empty; - private LLVector3 lookAt; private LLVector3 homePosition; private LLVector3 homeLookAt; private string firstName = String.Empty; @@ -1329,8 +1325,11 @@ namespace libsecondlife Movement.UpPos = false; Movement.FinishAnim = true; Movement.SendUpdate(true); + + // HACK: Try and give enough time for the jump animation to finish + System.Threading.Thread.Sleep(1000); + Movement.FinishAnim = false; - Movement.SendUpdate(true); return true; } else @@ -1947,7 +1946,7 @@ namespace libsecondlife s.StartLocationData.LocationPos = Client.Self.SimPosition; s.StartLocationData.LocationID = 1; s.StartLocationData.SimName = Helpers.StringToField(String.Empty); - s.StartLocationData.LocationLookAt = Client.Self.lookAt; + s.StartLocationData.LocationLookAt = Movement.Camera.AtAxis; Client.Network.SendPacket(s); } @@ -2110,8 +2109,8 @@ namespace libsecondlife { AgentMovementCompletePacket movement = (AgentMovementCompletePacket)packet; - this.relativePosition = movement.Data.Position; - this.lookAt = movement.Data.LookAt; + relativePosition = movement.Data.Position; + Movement.Camera.LookDirection(movement.Data.LookAt); simulator.Handle = movement.Data.RegionHandle; } @@ -2180,11 +2179,13 @@ namespace libsecondlife } } - private void EstablishAgentCommunicationEventHandler(string message, Dictionary body, CapsEventQueue caps) + private void EstablishAgentCommunicationEventHandler(string message, StructuredData.LLSD llsd, CapsEventQueue caps) { + StructuredData.LLSDMap body = (StructuredData.LLSDMap)llsd; + if (Client.Settings.MULTIPLE_SIMS && body.ContainsKey("sim-ip-and-port")) { - string ipAndPort = (string)body["sim-ip-and-port"]; + string ipAndPort = body["sim-ip-and-port"].AsString(); string[] pieces = ipAndPort.Split(':'); IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(pieces[0]), Convert.ToInt32(pieces[1])); Simulator sim = Client.Network.FindSimulator(endPoint); @@ -2201,7 +2202,7 @@ namespace libsecondlife Client.Log("Got EstablishAgentCommunication for " + sim.ToString(), Helpers.LogLevel.Info); - sim.SetSeedCaps((string)body["seed-capability"]); + sim.SetSeedCaps(body["seed-capability"].AsString()); } } } @@ -2296,8 +2297,8 @@ namespace libsecondlife teleportMessage = "Teleport finished"; flags = (TeleportFlags)local.Info.TeleportFlags; teleportStat = TeleportStatus.Finished; - lookAt = local.Info.LookAt; relativePosition = local.Info.Position; + Movement.Camera.LookDirection(local.Info.LookAt); // This field is apparently not used for anything //local.Info.LocationID; finished = true; @@ -2324,7 +2325,7 @@ namespace libsecondlife lastName = reply.LastName; startLocation = reply.StartLocation; agentAccess = reply.AgentAccess; - lookAt = reply.LookAt; + Movement.Camera.LookDirection(reply.LookAt); homePosition = reply.HomePosition; homeLookAt = reply.HomeLookAt; } diff --git a/libsecondlife/Capabilities.cs b/libsecondlife/Capabilities.cs index 291e1d41..c9e8ad1e 100644 --- a/libsecondlife/Capabilities.cs +++ b/libsecondlife/Capabilities.cs @@ -28,7 +28,7 @@ using System; using System.Collections.Generic; using System.Text; using System.Threading; -using libsecondlife.LLSD; +using libsecondlife.StructuredData; namespace libsecondlife { @@ -46,14 +46,14 @@ namespace libsecondlife /// Event name /// Decoded event data /// The CAPS system that made the call - public delegate void EventQueueCallback(string message, Dictionary body, CapsEventQueue eventQueue); + public delegate void EventQueueCallback(string message, StructuredData.LLSD body, CapsEventQueue eventQueue); /// /// Triggered when an HTTP call in the queue is executed and a response /// is received /// /// Decoded response /// Original capability request - public delegate void CapsResponseCallback(Dictionary body, HttpRequestState request); + public delegate void CapsResponseCallback(StructuredData.LLSD body, HttpRequestState request); /// Reference to the simulator this system is connected to public Simulator Simulator; @@ -134,7 +134,7 @@ namespace libsecondlife return; // Create a request list - List req = new List(); + LLSDArray req = new LLSDArray(); req.Add("MapLayer"); req.Add("MapLayerGod"); req.Add("NewFileAgentInventory"); @@ -165,11 +165,11 @@ namespace libsecondlife _SeedRequest.MakeRequest(postData, "application/xml", 0, null); } - private void seedRequest_OnCapsResponse(object response, HttpRequestState state) + private void seedRequest_OnCapsResponse(LLSD response, HttpRequestState state) { - if (response is Dictionary) + if (response.Type == LLSDType.Map) { - Dictionary respTable = (Dictionary)response; + LLSDMap respTable = (LLSDMap)response; StringBuilder capsList = new StringBuilder(); @@ -178,7 +178,7 @@ namespace libsecondlife capsList.Append(cap); capsList.Append(' '); - _Caps[cap] = (string)respTable[cap]; + _Caps[cap] = respTable[cap].AsString(); } Simulator.Client.DebugLog("Got capabilities: " + capsList.ToString()); diff --git a/libsecondlife/Capabilities/HttpBase.cs b/libsecondlife/Capabilities/HttpBase.cs index 43c81598..a90e5b81 100644 --- a/libsecondlife/Capabilities/HttpBase.cs +++ b/libsecondlife/Capabilities/HttpBase.cs @@ -66,15 +66,12 @@ namespace libsecondlife.Caps protected const int HTTP_TIMEOUT = 1 * 30 * 1000; protected HttpRequestState _RequestState; - protected HttpListener _Listener; - protected int _ListenPort; protected string _RequestURL; protected string _ProxyURL; protected string _ContentType; protected byte[] _PostData; protected object _State; protected bool _Aborted = false; - protected AsyncCallback _ServerCallback; public HttpBase(string requestURL) : this(requestURL, null, null, null, null) @@ -82,6 +79,9 @@ namespace libsecondlife.Caps public HttpBase(string requestURL, string proxyURL, string contentType, byte[] postData, object state) { + if (String.IsNullOrEmpty(_RequestURL)) + throw new ArgumentException("requestURL cannot be null or emtpy"); + _RequestURL = requestURL; _ProxyURL = proxyURL; _ContentType = contentType; @@ -89,89 +89,66 @@ namespace libsecondlife.Caps _State = state; } - public HttpBase(int listeningPort) - { - _ServerCallback = new AsyncCallback(ListenerCallback); - - _ListenPort = listeningPort; - _Listener = new HttpListener(); - _Listener.Prefixes.Add("http://+:" + _ListenPort + "/"); - } - public void Start() { - if (_Listener != null) + // Client mode + HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(_RequestURL); + IAsyncResult result; + + // Always disable keep-alive for our purposes + httpRequest.KeepAlive = false; + + // Create a state object to track this request in async callbacks + _RequestState = new HttpRequestState(httpRequest); + _RequestState.State = _State; + + if (!String.IsNullOrEmpty(_ProxyURL)) { - // Server mode - _Listener.Start(); - _Listener.BeginGetContext(_ServerCallback, _Listener); + // Create a proxy object + WebProxy proxy = new WebProxy(); + + // Associate a new Uri object to the _wProxy object, using the proxy address + // selected by the user + proxy.Address = new Uri(_ProxyURL); + + // Finally, initialize the Web request object proxy property with the _wProxy + // object + httpRequest.Proxy = proxy; } - else if (!String.IsNullOrEmpty(_RequestURL)) + + try { - // Client mode - HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(_RequestURL); - IAsyncResult result; - - // Always disable keep-alive for our purposes - httpRequest.KeepAlive = false; - - // Create a state object to track this request in async callbacks - _RequestState = new HttpRequestState(httpRequest); - _RequestState.State = _State; - - if (!String.IsNullOrEmpty(_ProxyURL)) + if (_PostData != null) { - // Create a proxy object - WebProxy proxy = new WebProxy(); + // POST request + _RequestState.WebRequest.Method = "POST"; + _RequestState.WebRequest.ContentLength = _PostData.Length; + if (!String.IsNullOrEmpty(_ContentType)) + _RequestState.WebRequest.ContentType = _ContentType; + _RequestState.RequestData = _PostData; - // Associate a new Uri object to the _wProxy object, using the proxy address - // selected by the user - proxy.Address = new Uri(_ProxyURL); - - // Finally, initialize the Web request object proxy property with the _wProxy - // object - httpRequest.Proxy = proxy; + result = (IAsyncResult)_RequestState.WebRequest.BeginGetRequestStream( + new AsyncCallback(RequestStreamCallback), _RequestState); + } + else + { + // GET request + result = (IAsyncResult)_RequestState.WebRequest.BeginGetResponse( + new AsyncCallback(ResponseCallback), _RequestState); } - try - { - if (_PostData != null) - { - // POST request - _RequestState.WebRequest.Method = "POST"; - _RequestState.WebRequest.ContentLength = _PostData.Length; - if (!String.IsNullOrEmpty(_ContentType)) - _RequestState.WebRequest.ContentType = _ContentType; - _RequestState.RequestData = _PostData; - - result = (IAsyncResult)_RequestState.WebRequest.BeginGetRequestStream( - new AsyncCallback(RequestStreamCallback), _RequestState); - } - else - { - // GET request - result = (IAsyncResult)_RequestState.WebRequest.BeginGetResponse( - new AsyncCallback(ResponseCallback), _RequestState); - } - - // If there is a timeout, the callback fires and the request becomes aborted - ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), - _RequestState, HTTP_TIMEOUT, true); - } - catch (WebException e) - { - Stop(false, e); - return; - } - - // If we get here the request has been initialized, so fire the callback for a request being started - RequestSent(_RequestState); + // If there is a timeout, the callback fires and the request becomes aborted + ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), + _RequestState, HTTP_TIMEOUT, true); } - else + catch (WebException e) { - SecondLife.LogStatic("HttpBase.Start() called with no client or server mode initialized", - Helpers.LogLevel.Error); + Stop(false, e); + return; } + + // If we get here the request has been initialized, so fire the callback for a request being started + RequestSent(_RequestState); } public void Stop() @@ -226,23 +203,6 @@ namespace libsecondlife.Caps if (timedOut) Stop(true, null); } - protected void ListenerCallback(IAsyncResult result) - { - try - { - HttpListenerContext context = _Listener.EndGetContext(result); - // Start listening again immediately - _Listener.BeginGetContext(_ServerCallback, _Listener); - - // FIXME: Fire a callback - // Need http method, URL and/or parameters, POST data - } - catch (Exception e) - { - SecondLife.LogStatic(e.ToString(), Helpers.LogLevel.Error); - } - } - protected void RequestStreamCallback(IAsyncResult result) { try diff --git a/libsecondlife/CapsEventQueue.cs b/libsecondlife/CapsEventQueue.cs index d447db60..b714a02c 100644 --- a/libsecondlife/CapsEventQueue.cs +++ b/libsecondlife/CapsEventQueue.cs @@ -30,7 +30,7 @@ using System.Net; using System.Text; using System.IO; using System.Threading; -using libsecondlife.LLSD; +using libsecondlife.StructuredData; namespace libsecondlife { @@ -62,9 +62,9 @@ namespace libsecondlife public new void MakeRequest() { // Create an EventQueueGet request - Dictionary request = new Dictionary(); - request["ack"] = null; - request["done"] = false; + LLSDMap request = new LLSDMap(); + request["ack"] = new LLSD(); + request["done"] = LLSD.FromBoolean(false); byte[] postData = LLSDParser.SerializeXmlBytes(request); @@ -234,7 +234,7 @@ namespace libsecondlife protected override void RequestReply(HttpRequestState state, bool success, WebException exception) { - List events = null; + LLSDArray events = null; int ack = 0; #region Exception Handling @@ -266,13 +266,13 @@ namespace libsecondlife // Decode successful replies from the event queue if (success) { - Dictionary response = (Dictionary)LLSDParser.DeserializeXml(state.ResponseData); + LLSDMap response = (LLSDMap)LLSDParser.DeserializeXml(state.ResponseData); if (response != null) { // Parse any events returned by the event queue - events = (List)response["events"]; - ack = (int)response["id"]; + events = (LLSDArray)response["events"]; + ack = response["id"].AsInteger(); } } @@ -282,10 +282,10 @@ namespace libsecondlife if (_Running) { - Dictionary request = new Dictionary(); - if (ack != 0) request["ack"] = ack; - else request["ack"] = null; - request["done"] = _Dead; + LLSDMap request = new LLSDMap(); + if (ack != 0) request["ack"] = LLSD.FromInteger(ack); + else request["ack"] = new LLSD(); + request["done"] = LLSD.FromBoolean(_Dead); byte[] postData = LLSDParser.SerializeXmlBytes(request); @@ -307,10 +307,10 @@ namespace libsecondlife if (events != null && events.Count > 0) { // Fire callbacks for each event received - foreach (Dictionary evt in events) + foreach (LLSDMap evt in events) { - string msg = (string)evt["message"]; - Dictionary body = (Dictionary)evt["body"]; + string msg = evt["message"].AsString(); + LLSDMap body = (LLSDMap)evt["body"]; //Simulator.Client.DebugLog( // String.Format("[{0}] Event {1}: {2}{3}", Simulator, msg, Helpers.NewLine, LLSD.LLSDDump(body, 0))); diff --git a/libsecondlife/CapsRequest.cs b/libsecondlife/CapsRequest.cs index cdfc8dfd..b7e05f0a 100644 --- a/libsecondlife/CapsRequest.cs +++ b/libsecondlife/CapsRequest.cs @@ -28,13 +28,13 @@ using System; using System.Collections; using System.Net; using System.Text; -using libsecondlife.LLSD; +using libsecondlife.StructuredData; namespace libsecondlife { public class CapsRequest : HttpBase { - public delegate void CapsResponseCallback(object response, HttpRequestState state); + public delegate void CapsResponseCallback(LLSD response, HttpRequestState state); public event CapsResponseCallback OnCapsResponse; @@ -73,7 +73,7 @@ namespace libsecondlife protected override void RequestReply(HttpRequestState state, bool success, WebException exception) { - object response = null; + LLSD response = null; if (success) { diff --git a/libsecondlife/CapsToPacket.cs b/libsecondlife/CapsToPacket.cs index 3b8679ad..e0e0b587 100644 --- a/libsecondlife/CapsToPacket.cs +++ b/libsecondlife/CapsToPacket.cs @@ -28,7 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; -using libsecondlife.LLSD; +using libsecondlife.StructuredData; namespace libsecondlife.Packets { @@ -39,9 +39,9 @@ namespace libsecondlife.Packets return LLSDParser.SerializeXmlString(SerializeToLLSD(packet)); } - public static object SerializeToLLSD(Packet packet) + public static LLSD SerializeToLLSD(Packet packet) { - Dictionary body = new Dictionary(); + LLSDMap body = new LLSDMap(); Type type = packet.GetType(); foreach (FieldInfo field in type.GetFields()) @@ -54,7 +54,7 @@ namespace libsecondlife.Packets { object blockArray = field.GetValue(packet); Array array = (Array)blockArray; - List blockList = new List(array.Length); + LLSDArray blockList = new LLSDArray(array.Length); IEnumerator ie = array.GetEnumerator(); while (ie.MoveNext()) @@ -88,7 +88,7 @@ namespace libsecondlife.Packets /// 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, Dictionary body) + public static Packet BuildPacket(string capsEventName, LLSDMap body) { Assembly assembly = Assembly.GetExecutingAssembly(); @@ -113,22 +113,22 @@ namespace libsecondlife.Packets if (blockType.IsArray) { - List array = (List)body[field.Name]; + LLSDArray array = (LLSDArray)body[field.Name]; Type elementType = blockType.GetElementType(); object[] blockArray = (object[])Array.CreateInstance(elementType, array.Count); for (int i = 0; i < array.Count; i++) { - Dictionary hashtable = (Dictionary)array[i]; - blockArray[i] = ParseLLSDBlock(hashtable, elementType); + LLSDMap map = (LLSDMap)array[i]; + blockArray[i] = ParseLLSDBlock(map, elementType); } field.SetValue(packet, blockArray); } else { - Dictionary hashtable = (Dictionary)((List)body[field.Name])[0]; - field.SetValue(packet, ParseLLSDBlock(hashtable, blockType)); + LLSDMap map = (LLSDMap)((LLSDArray)body[field.Name])[0]; + field.SetValue(packet, ParseLLSDBlock(map, blockType)); } } } @@ -141,7 +141,7 @@ namespace libsecondlife.Packets return (Packet)packet; } - private static object ParseLLSDBlock(Dictionary blockData, Type blockType) + private static object ParseLLSDBlock(LLSDMap blockData, Type blockType) { object block = Activator.CreateInstance(blockType); @@ -155,34 +155,66 @@ namespace libsecondlife.Packets if (fieldType == typeof(ulong)) { // ulongs come in as a byte array, convert it manually here - byte[] bytes = (byte[])blockData[field.Name]; + byte[] bytes = blockData[field.Name].AsBinary(); ulong value = Helpers.BytesToUInt64(bytes); field.SetValue(block, value); } else if (fieldType == typeof(uint)) { // uints come in as a byte array, convert it manually here - byte[] bytes = (byte[])blockData[field.Name]; + byte[] bytes = blockData[field.Name].AsBinary(); uint value = Helpers.BytesToUIntBig(bytes); field.SetValue(block, value); } else if (fieldType == typeof(ushort)) { // Just need a bit of manual typecasting love here - field.SetValue(block, (ushort)(int)blockData[field.Name]); + 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)(int)blockData[field.Name]); + field.SetValue(block, (byte)blockData[field.Name].AsInteger()); } else if (fieldType == typeof(short)) { - field.SetValue(block, (short)(int)blockData[field.Name]); + field.SetValue(block, (short)blockData[field.Name].AsInteger()); } - else + else if (fieldType == typeof(LLUUID)) { - field.SetValue(block, blockData[field.Name]); + field.SetValue(block, blockData[field.Name].AsUUID()); + } + else if (fieldType == typeof(LLVector3)) + { + field.SetValue(block, LLVector3.FromLLSD(blockData[field.Name])); + } + else if (fieldType == typeof(LLVector4)) + { + field.SetValue(block, LLVector4.FromLLSD(blockData[field.Name])); + } + else if (fieldType == typeof(LLQuaternion)) + { + field.SetValue(block, LLQuaternion.FromLLSD(blockData[field.Name])); + } + 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()); } } } @@ -193,35 +225,33 @@ namespace libsecondlife.Packets if (blockData.ContainsKey(property.Name)) { MethodInfo set = property.GetSetMethod(); - set.Invoke(block, new object[] { Helpers.StringToField((string)blockData[property.Name]) }); + set.Invoke(block, new object[] { Helpers.StringToField(blockData[property.Name].AsString()) }); } } return block; } - private static Dictionary BuildLLSDBlock(object block) + private static LLSD BuildLLSDBlock(object block) { - Dictionary dict = new Dictionary(); + LLSDMap map = new LLSDMap(); Type blockType = block.GetType(); foreach (FieldInfo field in blockType.GetFields()) { if (field.IsPublic) - { - dict[field.Name] = field.GetValue(block); - } + map[field.Name] = LLSD.FromObject(field.GetValue(block)); } foreach (PropertyInfo property in blockType.GetProperties()) { if (property.Name != "Length") { - dict[property.Name] = property.GetValue(block, null); + map[property.Name] = LLSD.FromObject(property.GetValue(block, null)); } } - return dict; + return map; } } } diff --git a/libsecondlife/EventDictionary.cs b/libsecondlife/EventDictionary.cs index 6a5671d2..f84747f1 100644 --- a/libsecondlife/EventDictionary.cs +++ b/libsecondlife/EventDictionary.cs @@ -163,7 +163,7 @@ namespace libsecondlife /// Name of the CAPS event public string CapsEvent; /// Decoded body of the CAPS event - public Dictionary Body; + public StructuredData.LLSD Body; /// Reference to the event queue that generated this event public CapsEventQueue EventQueue; } @@ -225,7 +225,7 @@ namespace libsecondlife /// Decoded event body /// Reference to the event queue that /// generated this event - internal void RaiseEvent(string capsEvent, Dictionary body, CapsEventQueue eventQueue) + internal void RaiseEvent(string capsEvent, StructuredData.LLSD body, CapsEventQueue eventQueue) { bool specialHandler = false; Capabilities.EventQueueCallback callback; @@ -241,17 +241,21 @@ namespace libsecondlife } // Generic parser next - Packet packet = Packet.BuildPacket(capsEvent, body); - if (packet != null) + if (body.Type == StructuredData.LLSDType.Map) { - NetworkManager.IncomingPacket incomingPacket; - incomingPacket.Simulator = eventQueue.Simulator; - incomingPacket.Packet = packet; + StructuredData.LLSDMap map = (StructuredData.LLSDMap)body; + Packet packet = Packet.BuildPacket(capsEvent, map); + if (packet != null) + { + NetworkManager.IncomingPacket incomingPacket; + incomingPacket.Simulator = eventQueue.Simulator; + incomingPacket.Packet = packet; - Client.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler"); + Client.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler"); - Client.Network.PacketInbox.Enqueue(incomingPacket); - specialHandler = true; + Client.Network.PacketInbox.Enqueue(incomingPacket); + specialHandler = true; + } } // Explicit handler next @@ -274,7 +278,7 @@ namespace libsecondlife /// Decoded event body /// Reference to the event queue that /// generated this event - internal void BeginRaiseEvent(string capsEvent, Dictionary body, CapsEventQueue eventQueue) + internal void BeginRaiseEvent(string capsEvent, StructuredData.LLSD body, CapsEventQueue eventQueue) { bool specialHandler = false; Capabilities.EventQueueCallback callback; @@ -294,17 +298,21 @@ namespace libsecondlife } // Generic parser next - Packet packet = Packet.BuildPacket(capsEvent, body); - if (packet != null) + if (body.Type == StructuredData.LLSDType.Map) { - NetworkManager.IncomingPacket incomingPacket; - incomingPacket.Simulator = eventQueue.Simulator; - incomingPacket.Packet = packet; + StructuredData.LLSDMap map = (StructuredData.LLSDMap)body; + Packet packet = Packet.BuildPacket(capsEvent, map); + if (packet != null) + { + NetworkManager.IncomingPacket incomingPacket; + incomingPacket.Simulator = eventQueue.Simulator; + incomingPacket.Packet = packet; - Client.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler"); + Client.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler"); - Client.Network.PacketInbox.Enqueue(incomingPacket); - specialHandler = true; + Client.Network.PacketInbox.Enqueue(incomingPacket); + specialHandler = true; + } } // Explicit handler next diff --git a/libsecondlife/GridManager.cs b/libsecondlife/GridManager.cs index f6e7bf7b..5e2c37fd 100644 --- a/libsecondlife/GridManager.cs +++ b/libsecondlife/GridManager.cs @@ -192,12 +192,11 @@ namespace libsecondlife /// public delegate void GridItemsCallback(GridItemType type, List items); - - /// - /// Triggered when a new region is discovered through GridManager - /// + /// Triggered when a new region is discovered through GridManager public event GridRegionCallback OnGridRegion; + /// public event GridLayerCallback OnGridLayer; + /// public event GridItemsCallback OnGridItems; /// Unknown @@ -213,10 +212,9 @@ namespace libsecondlife internal Dictionary RegionsByHandle = new Dictionary(); private SecondLife Client; - private float sunPhase = 0.0f; - private LLVector3 sunDirection = LLVector3.Zero; - private LLVector3 sunAngVelocity = LLVector3.Zero; - private Dictionary RequestingRegions = new Dictionary(); + private float sunPhase; + private LLVector3 sunDirection; + private LLVector3 sunAngVelocity; /// /// Constructor @@ -232,6 +230,10 @@ namespace libsecondlife Client.Network.RegisterCallback(PacketType.CoarseLocationUpdate, new NetworkManager.PacketCallback(CoarseLocationHandler)); } + /// + /// + /// + /// public void RequestMapLayer(GridLayerType layer) { string url = Client.Network.CurrentSim.Caps.CapabilityURI("MapLayer"); @@ -246,6 +248,11 @@ namespace libsecondlife } } + /// + /// + /// + /// + /// public void RequestMapRegion(string regionName, GridLayerType layer) { MapNameRequestPacket request = new MapNameRequestPacket(); @@ -260,6 +267,15 @@ namespace libsecondlife Client.Network.SendPacket(request); } + /// + /// + /// + /// + /// + /// + /// + /// + /// public void RequestMapBlocks(GridLayerType layer, ushort minX, ushort minY, ushort maxX, ushort maxY, bool returnNonExistent) { @@ -280,6 +296,14 @@ namespace libsecondlife Client.Network.SendPacket(request); } + /// + /// + /// + /// + /// + /// + /// + /// public List MapItems(ulong regionHandle, GridItemType item, GridLayerType layer, int timeoutMS) { List itemList = null; @@ -305,6 +329,12 @@ namespace libsecondlife return itemList; } + /// + /// + /// + /// + /// + /// public void RequestMapItems(ulong regionHandle, GridItemType item, GridLayerType layer) { MapItemRequestPacket request = new MapItemRequestPacket(); @@ -340,6 +370,14 @@ namespace libsecondlife /// false public bool GetGridRegion(string name, GridLayerType layer, out GridRegion region) { + if (String.IsNullOrEmpty(name)) + { + Client.Log("GetGridRegion called with a null or empty region name", Helpers.LogLevel.Error); + region = new GridRegion(); + return false; + } + + // All lookups are done using lowercase sim names name = name.ToLower(); if (Regions.ContainsKey(name)) @@ -350,29 +388,19 @@ namespace libsecondlife } else { - ManualResetEvent requestEvent = new ManualResetEvent(false); + AutoResetEvent regionEvent = new AutoResetEvent(false); + GridRegionCallback callback = + delegate(GridRegion gridRegion) + { + if (gridRegion.Name == name) + regionEvent.Set(); + }; + OnGridRegion += callback; - if (RequestingRegions.ContainsKey(name)) - { - Client.Log("GetGridRegion called for " + name + " multiple times, ignoring", - Helpers.LogLevel.Warning); - region = new GridRegion(); - return false; - } - else - { - // Add this region request to the list of requests we are tracking - lock (RequestingRegions) RequestingRegions.Add(name, requestEvent); - } - - // Make the request RequestMapRegion(name, layer); + regionEvent.WaitOne(Client.Settings.MAP_REQUEST_TIMEOUT, false); - // Wait until an answer is retrieved - requestEvent.WaitOne(Client.Settings.MAP_REQUEST_TIMEOUT, false); - - // Remove the dictionary entry for this lookup - lock (RequestingRegions) RequestingRegions.Remove(name); + OnGridRegion -= callback; if (Regions.ContainsKey(name)) { @@ -445,12 +473,10 @@ namespace libsecondlife region.MapImageID = block.MapImageID; region.RegionHandle = Helpers.UIntsToLong((uint)(region.X * 256), (uint)(region.Y * 256)); - lock (Regions) Regions[region.Name.ToLower()] = region; - lock (RegionsByHandle) RegionsByHandle[region.RegionHandle] = region; - lock (RequestingRegions) + lock (Regions) { - if (RequestingRegions.ContainsKey(region.Name.ToLower())) - RequestingRegions[region.Name.ToLower()].Set(); + Regions[region.Name.ToLower()] = region; + RegionsByHandle[region.RegionHandle] = region; } if (OnGridRegion != null) @@ -530,7 +556,7 @@ namespace libsecondlife sunPhase = time.TimeInfo.SunPhase; sunDirection = time.TimeInfo.SunDirection; sunAngVelocity = time.TimeInfo.SunAngVelocity; - + // TODO: Does anyone have a use for the time stuff? } diff --git a/libsecondlife/Helpers.cs b/libsecondlife/Helpers.cs index 26ff1f10..af93b272 100644 --- a/libsecondlife/Helpers.cs +++ b/libsecondlife/Helpers.cs @@ -36,6 +36,23 @@ namespace libsecondlife /// public class Helpers { + /// + /// Operating system enumeration + /// + public enum Platform + { + /// Unknown + Unknown, + /// Microsoft Windows + Windows, + /// Microsoft Windows CE + WindowsCE, + /// Linux + Linux, + /// Apple OSX + OSX + } + /// 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 @@ -1051,6 +1068,64 @@ namespace libsecondlife return null; } + 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; + } + } + } + + /// + /// 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 Dictionary PrimListToLLSD(List prims) + { + Dictionary llsd = new Dictionary(prims.Count); + + for (int i = 0; i < prims.Count; i++) + llsd.Add(prims[i].LocalID.ToString(), prims[i].ToLLSD()); + + return llsd; + } + + public static List LLSDToPrimList(Dictionary llsd) + { + List prims = new List(); + + foreach (object obj in llsd.Values) + { + Dictionary primLLSD = (Dictionary)obj; + ; + } + + //FIXME: + return null; + } + + #region Platform Helper Functions + public static bool TryParse(string s, out DateTime result) { #if PocketPC @@ -1167,5 +1242,7 @@ namespace libsecondlife return false; } } + + #endregion Platform Helper Functions } } diff --git a/libsecondlife/InventoryManager.cs b/libsecondlife/InventoryManager.cs index 4782e9e6..0f3c230f 100644 --- a/libsecondlife/InventoryManager.cs +++ b/libsecondlife/InventoryManager.cs @@ -30,6 +30,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Text; using libsecondlife; +using libsecondlife.StructuredData; using libsecondlife.Packets; namespace libsecondlife @@ -1160,14 +1161,14 @@ namespace libsecondlife if (url != String.Empty) { - Dictionary query = new Dictionary(); - query.Add("folder_id", folderID); - query.Add("asset_type", AssetTypeToString(assetType)); - query.Add("inventory_type", InventoryTypeToString(invType)); - query.Add("name", name); - query.Add("description", description); + LLSDMap query = new LLSDMap(); + query.Add("folder_id", LLSD.FromUUID(folderID)); + query.Add("asset_type", LLSD.FromString(AssetTypeToString(assetType))); + query.Add("inventory_type", LLSD.FromString(InventoryTypeToString(invType))); + query.Add("name", LLSD.FromString(name)); + query.Add("description", LLSD.FromString(description)); - byte[] postData = LLSD.LLSDParser.SerializeXmlBytes(query); + byte[] postData = StructuredData.LLSDParser.SerializeXmlBytes(query); // Make the request CapsRequest request = new CapsRequest(url, _Client.Network.CurrentSim); diff --git a/libsecondlife/LLSD/BinaryLLSD.cs b/libsecondlife/LLSD/BinaryLLSD.cs index 76517dca..e0e43019 100644 --- a/libsecondlife/LLSD/BinaryLLSD.cs +++ b/libsecondlife/LLSD/BinaryLLSD.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text; -namespace libsecondlife.LLSD +namespace libsecondlife.StructuredData { public static partial class LLSDParser { diff --git a/libsecondlife/LLSD/LLSD.cs b/libsecondlife/LLSD/LLSD.cs index 14e99166..cc0dfcee 100644 --- a/libsecondlife/LLSD/LLSD.cs +++ b/libsecondlife/LLSD/LLSD.cs @@ -1,13 +1,448 @@ using System; +using System.Collections; +using System.Collections.Generic; -namespace libsecondlife.LLSD +namespace libsecondlife.StructuredData { + public enum LLSDType + { + Unknown, + Boolean, + Integer, + Real, + String, + UUID, + Date, + URI, + Binary, + Map, + Array + } + public class LLSDException : Exception { public LLSDException(string message) : base(message) { } } - public static partial class LLSDParser + public partial class LLSD { + public virtual LLSDType Type { get { return LLSDType.Unknown; } } + + public virtual bool AsBoolean() { return false; } + public virtual int AsInteger() { return 0; } + public virtual double AsReal() { return 0d; } + public virtual string AsString() { return String.Empty; } + public virtual LLUUID AsUUID() { return LLUUID.Zero; } + public virtual DateTime AsDate() { return Helpers.Epoch; } + public virtual Uri AsUri() { return new Uri(String.Empty); } + public virtual byte[] AsBinary() { return new byte[0]; } + + public static LLSD FromBoolean(bool value) { return new LLSDBoolean(value); } + public static LLSD FromInteger(int value) { return new LLSDInteger(value); } + public static LLSD FromInteger(uint value) { return new LLSDInteger((int)value); } + public static LLSD FromInteger(short value) { return new LLSDInteger((int)value); } + public static LLSD FromInteger(ushort value) { return new LLSDInteger((int)value); } + public static LLSD FromInteger(sbyte value) { return new LLSDInteger((int)value); } + public static LLSD FromInteger(byte value) { return new LLSDInteger((int)value); } + public static LLSD FromReal(double value) { return new LLSDReal(value); } + public static LLSD FromReal(float value) { return new LLSDReal((double)value); } + public static LLSD FromString(string value) { return new LLSDString(value); } + public static LLSD FromUUID(LLUUID value) { return new LLSDUUID(value); } + public static LLSD FromDate(DateTime value) { return new LLSDDate(value); } + public static LLSD FromUri(Uri value) { return new LLSDURI(value); } + public static LLSD FromBinary(byte[] value) { return new LLSDBinary(value); } + public static LLSD FromBinary(long value) { return new LLSDBinary(value); } + public static LLSD FromBinary(ulong value) { return new LLSDBinary(value); } + public static LLSD FromObject(object value) + { + if (value == null) { return new LLSD(); } + else if (value is bool) { return new LLSDBoolean((bool)value); } + else if (value is int) { return new LLSDInteger((int)value); } + else if (value is uint) { return new LLSDInteger((int)(uint)value); } + else if (value is short) { return new LLSDInteger((int)(short)value); } + else if (value is ushort) { return new LLSDInteger((int)(ushort)value); } + else if (value is sbyte) { return new LLSDInteger((int)(sbyte)value); } + else if (value is byte) { return new LLSDInteger((int)(byte)value); } + else if (value is double) { return new LLSDReal((double)value); } + else if (value is float) { return new LLSDReal((double)(float)value); } + else if (value is string) { return new LLSDString((string)value); } + else if (value is LLUUID) { return new LLSDUUID((LLUUID)value); } + else if (value is DateTime) { return new LLSDDate((DateTime)value); } + else if (value is Uri) { return new LLSDURI((Uri)value); } + else if (value is byte[]) { return new LLSDBinary((byte[])value); } + else if (value is long) { return new LLSDBinary((long)value); } + else if (value is ulong) { return new LLSDBinary((ulong)value); } + else return new LLSD(); + } + } + + public class LLSDBoolean : LLSD + { + private bool value; + + public override LLSDType Type { get { return LLSDType.Boolean; } } + + public LLSDBoolean(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 class LLSDInteger : LLSD + { + private int value; + + public override LLSDType Type { get { return LLSDType.Integer; } } + + public LLSDInteger(int value) + { + this.value = value; + } + + public override bool AsBoolean() { return value != 0; } + public override int AsInteger() { return value; } + public override double AsReal() { return (double)value; } + public override string AsString() { return value.ToString(); } + } + + public class LLSDReal : LLSD + { + private double value; + + public override LLSDType Type { get { return LLSDType.Real; } } + + public LLSDReal(double value) + { + this.value = value; + } + + public override bool AsBoolean() { return (!Double.IsNaN(value) && value != 0d); } + public override int AsInteger() { return Double.IsNaN(value) ? (int)value : 0; } + public override double AsReal() { return value; } + public override string AsString() { return value.ToString(Helpers.EnUsCulture); } + } + + public class LLSDString : LLSD + { + private string value; + + public override LLSDType Type { get { return LLSDType.String; } } + + public LLSDString(string value) + { + this.value = value; + } + + public override bool AsBoolean() { return !String.IsNullOrEmpty(value); } + public override int AsInteger() + { + double dbl; + if (Double.TryParse(value, out dbl)) + return (int)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 LLUUID AsUUID() + { + LLUUID uuid; + if (LLUUID.TryParse(value, out uuid)) + return uuid; + else + return LLUUID.Zero; + } + public override DateTime AsDate() + { + DateTime dt; + if (DateTime.TryParse(value, out dt)) + return dt; + else + return Helpers.Epoch; + } + public override Uri AsUri() { return new Uri(value); } + } + + public class LLSDUUID : LLSD + { + private LLUUID value; + + public override LLSDType Type { get { return LLSDType.UUID; } } + + public LLSDUUID(LLUUID value) + { + this.value = value; + } + + public override string AsString() { return value.ToStringHyphenated(); } + public override LLUUID AsUUID() { return value; } + } + + public class LLSDDate : LLSD + { + private DateTime value; + + public override LLSDType Type { get { return LLSDType.Date; } } + + public LLSDDate(DateTime value) + { + this.value = value; + } + + public override string AsString() { return value.ToString(); } + public override DateTime AsDate() { return value; } + } + + public class LLSDURI : LLSD + { + private Uri value; + + public override LLSDType Type { get { return LLSDType.URI; } } + + public LLSDURI(Uri value) + { + this.value = value; + } + + public override string AsString() { return value.ToString(); } + public override Uri AsUri() { return value; } + } + + public class LLSDBinary : LLSD + { + private byte[] value; + + public override LLSDType Type { get { return LLSDType.Binary; } } + + public LLSDBinary(byte[] value) + { + if (value != null) + this.value = value; + else + this.value = new byte[0]; + } + + public LLSDBinary(long value) + { + this.value = BitConverter.GetBytes(value); + } + + public LLSDBinary(ulong value) + { + this.value = BitConverter.GetBytes(value); + } + + public override string AsString() { return Convert.ToBase64String(value); } + public override byte[] AsBinary() { return value; } + } + + public class LLSDMap : LLSD, IDictionary + { + private Dictionary value; + + public override LLSDType Type { get { return LLSDType.Map; } } + + public LLSDMap() + { + value = new Dictionary(); + } + + public LLSDMap(int capacity) + { + value = new Dictionary(capacity); + } + + public LLSDMap(Dictionary value) + { + if (value != null) + this.value = value; + else + this.value = new Dictionary(); + } + + public override bool AsBoolean() { return value.Count > 0; } + + #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 LLSD this[string key] + { + get { return value[key]; } + set { this.value[key] = value; } + } + + public bool ContainsKey(string key) + { + return value.ContainsKey(key); + } + + public void Add(string key, LLSD 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 LLSD 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 class LLSDArray : LLSD, IList + { + private List value; + + public override LLSDType Type { get { return LLSDType.Array; } } + + public LLSDArray() + { + value = new List(); + } + + public LLSDArray(int capacity) + { + value = new List(capacity); + } + + public LLSDArray(List value) + { + if (value != null) + this.value = value; + else + this.value = new List(); + } + + public override bool AsBoolean() { return value.Count > 0; } + + #region IList Implementation + + public int Count { get { return value.Count; } } + public bool IsReadOnly { get { return false; } } + public LLSD this[int index] + { + get { return value[index]; } + set { this.value[index] = value; } + } + + public int IndexOf(LLSD llsd) + { + return value.IndexOf(llsd); + } + + public void Insert(int index, LLSD llsd) + { + value.Insert(index, llsd); + } + + public void RemoveAt(int index) + { + value.RemoveAt(index); + } + + public void Add(LLSD llsd) + { + value.Add(llsd); + } + + public void Add(string str) + { + // This is so common that we throw a little helper in here + value.Add(LLSD.FromString(str)); + } + + public void Clear() + { + value.Clear(); + } + + public bool Contains(LLSD llsd) + { + return value.Contains(llsd); + } + + public void CopyTo(LLSD[] array, int index) + { + throw new NotImplementedException(); + } + + public bool Remove(LLSD llsd) + { + return value.Remove(llsd); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return value.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return value.GetEnumerator(); + } + + #endregion IList Implementation } } diff --git a/libsecondlife/LLSD/NotationLLSD.cs b/libsecondlife/LLSD/NotationLLSD.cs index 5a8ae64e..7a14b4b3 100644 --- a/libsecondlife/LLSD/NotationLLSD.cs +++ b/libsecondlife/LLSD/NotationLLSD.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text; -namespace libsecondlife.LLSD +namespace libsecondlife.StructuredData { public static partial class LLSDParser { diff --git a/libsecondlife/LLSD/XmlLLSD.cs b/libsecondlife/LLSD/XmlLLSD.cs index 6d821b22..2407173b 100644 --- a/libsecondlife/LLSD/XmlLLSD.cs +++ b/libsecondlife/LLSD/XmlLLSD.cs @@ -5,7 +5,7 @@ using System.Xml; using System.Xml.Schema; using System.Text; -namespace libsecondlife.LLSD +namespace libsecondlife.StructuredData { public static partial class LLSDParser { @@ -14,28 +14,28 @@ namespace libsecondlife.LLSD private static string LastXmlErrors = String.Empty; private static object XmlValidationLock = new object(); - public static object DeserializeXml(byte[] xmlData) + public static LLSD DeserializeXml(byte[] xmlData) { return DeserializeXml(new XmlTextReader(new MemoryStream(xmlData, false))); } - public static object DeserializeXml(XmlTextReader xmlData) + public static LLSD DeserializeXml(XmlTextReader xmlData) { xmlData.Read(); SkipWhitespace(xmlData); xmlData.Read(); - object ret = ParseXmlElement(xmlData); + LLSD ret = ParseXmlElement(xmlData); return ret; } - public static byte[] SerializeXmlBytes(object data) + public static byte[] SerializeXmlBytes(LLSD data) { return Encoding.UTF8.GetBytes(SerializeXmlString(data)); } - public static string SerializeXmlString(object data) + public static string SerializeXmlString(LLSD data) { StringWriter sw = new StringWriter(); XmlTextWriter writer = new XmlTextWriter(sw); @@ -50,164 +50,79 @@ namespace libsecondlife.LLSD return sw.ToString(); } - public static void SerializeXmlElement(XmlTextWriter writer, object obj) + public static void SerializeXmlElement(XmlTextWriter writer, LLSD data) { - if (obj == null) + switch (data.Type) { - writer.WriteStartElement(String.Empty, "undef", String.Empty); - writer.WriteEndElement(); - } - else if (obj is string) - { - writer.WriteStartElement(String.Empty, "string", String.Empty); - writer.WriteString((string)obj); - writer.WriteEndElement(); - } - else if (obj is int || obj is uint || obj is short || obj is ushort || obj is byte || obj is sbyte) - { - writer.WriteStartElement(String.Empty, "integer", String.Empty); - writer.WriteString(obj.ToString()); - writer.WriteEndElement(); - } - else if (obj is double) - { - double value = (double)obj; - - writer.WriteStartElement(String.Empty, "real", String.Empty); - writer.WriteString(value.ToString(Helpers.EnUsCulture)); - writer.WriteEndElement(); - } - else if (obj is float) - { - float value = (float)obj; - - writer.WriteStartElement(String.Empty, "real", String.Empty); - writer.WriteString(value.ToString(Helpers.EnUsCulture)); - writer.WriteEndElement(); - } - else if (obj is long) - { - // 64-bit integers are not natively supported in LLSD, so we convert to a byte array - long value = (long)obj; - - byte[] bytes = BitConverter.GetBytes(value); - - writer.WriteStartElement(String.Empty, "binary", String.Empty); - - writer.WriteStartAttribute(String.Empty, "encoding", String.Empty); - writer.WriteString("base64"); - writer.WriteEndAttribute(); - - writer.WriteString(Convert.ToBase64String(bytes)); - writer.WriteEndElement(); - } - else if (obj is ulong) - { - // 64-bit integers are not natively supported in LLSD, so we convert to a byte array - ulong value = (ulong)obj; - - byte[] bytes = BitConverter.GetBytes(value); - - writer.WriteStartElement(String.Empty, "binary", String.Empty); - - writer.WriteStartAttribute(String.Empty, "encoding", String.Empty); - writer.WriteString("base64"); - writer.WriteEndAttribute(); - - writer.WriteString(Convert.ToBase64String(bytes)); - writer.WriteEndElement(); - } - else if (obj is bool) - { - bool b = (bool)obj; - writer.WriteStartElement(String.Empty, "boolean", String.Empty); - writer.WriteString(b ? "1" : "0"); - writer.WriteEndElement(); - } - else if (obj is LLUUID) - { - LLUUID u = (LLUUID)obj; - writer.WriteStartElement(String.Empty, "uuid", String.Empty); - writer.WriteString(u.ToStringHyphenated()); - writer.WriteEndElement(); - } - else if (obj is Dictionary) - { - Dictionary d = obj as Dictionary; - - writer.WriteStartElement(String.Empty, "map", String.Empty); - foreach (string key in d.Keys) - { - writer.WriteStartElement(String.Empty, "key", String.Empty); - writer.WriteString(key); + case LLSDType.Unknown: + writer.WriteStartElement(String.Empty, "undef", String.Empty); writer.WriteEndElement(); - - SerializeXmlElement(writer, d[key]); - } - writer.WriteEndElement(); - } - else if (obj is System.Collections.Hashtable) - { - System.Collections.Hashtable h = obj as System.Collections.Hashtable; - - writer.WriteStartElement(String.Empty, "map", String.Empty); - foreach (string key in h.Keys) - { - writer.WriteStartElement(String.Empty, "key", String.Empty); - writer.WriteString(key); + break; + case LLSDType.Boolean: + writer.WriteStartElement(String.Empty, "boolean", String.Empty); + writer.WriteString(data.AsString()); writer.WriteEndElement(); + break; + case LLSDType.Integer: + writer.WriteStartElement(String.Empty, "integer", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case LLSDType.Real: + writer.WriteStartElement(String.Empty, "real", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case LLSDType.String: + writer.WriteStartElement(String.Empty, "string", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case LLSDType.UUID: + writer.WriteStartElement(String.Empty, "uuid", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case LLSDType.Date: + writer.WriteStartElement(String.Empty, "date", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case LLSDType.URI: + writer.WriteStartElement(String.Empty, "uri", String.Empty); + writer.WriteString(data.AsString()); + writer.WriteEndElement(); + break; + case LLSDType.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 LLSDType.Map: + LLSDMap map = (LLSDMap)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(); - SerializeXmlElement(writer, h[key]); - } - writer.WriteEndElement(); - } - else if (obj is List) - { - List l = obj as List; - - writer.WriteStartElement(String.Empty, "array", String.Empty); - for (int i = 0; i < l.Count; i++) - { - SerializeXmlElement(writer, l[i]); - } - writer.WriteEndElement(); - } - else if (obj is System.Collections.ArrayList) - { - System.Collections.ArrayList a = obj as System.Collections.ArrayList; - - writer.WriteStartElement(String.Empty, "array", String.Empty); - for (int i = 0; i < a.Count; i++) - { - SerializeXmlElement(writer, a[i]); - } - writer.WriteEndElement(); - } - else if (obj is byte[]) - { - writer.WriteStartElement(String.Empty, "binary", String.Empty); - - writer.WriteStartAttribute(String.Empty, "encoding", String.Empty); - writer.WriteString("base64"); - writer.WriteEndAttribute(); - - writer.WriteString(Convert.ToBase64String((byte[])obj)); - writer.WriteEndElement(); - } - else if (obj.GetType().IsArray) - { - Array a = (Array)obj; - - writer.WriteStartElement(String.Empty, "array", String.Empty); - for (int i = 0; i < a.Length; i++) - { - SerializeXmlElement(writer, a.GetValue(i)); - } - writer.WriteEndElement(); - } - else - { - throw new LLSDException("Unknown type " + obj.GetType().Name); + SerializeXmlElement(writer, kvp.Value); + } + writer.WriteEndElement(); + break; + case LLSDType.Array: + LLSDArray array = (LLSDArray)data; + writer.WriteStartElement(String.Empty, "array", String.Empty); + for (int i = 0; i < array.Count; i++) + { + SerializeXmlElement(writer, array[i]); + } + writer.WriteEndElement(); + break; } } @@ -250,7 +165,7 @@ namespace libsecondlife.LLSD } } - private static object ParseXmlElement(XmlTextReader reader) + private static LLSD ParseXmlElement(XmlTextReader reader) { SkipWhitespace(reader); @@ -258,7 +173,7 @@ namespace libsecondlife.LLSD throw new LLSDException("Expected an element"); string type = reader.LocalName; - object ret = null; + LLSD ret; switch (type) { @@ -266,18 +181,18 @@ namespace libsecondlife.LLSD if (reader.IsEmptyElement) { reader.Read(); - return null; + return new LLSD(); } reader.Read(); SkipWhitespace(reader); - ret = null; + ret = new LLSD(); break; case "boolean": if (reader.IsEmptyElement) { reader.Read(); - return false; + return LLSD.FromBoolean(false); } if (reader.Read()) @@ -286,35 +201,35 @@ namespace libsecondlife.LLSD if (!String.IsNullOrEmpty(s) && (s == "true" || s == "1")) { - ret = true; + ret = LLSD.FromBoolean(true); break; } } - ret = false; + ret = LLSD.FromBoolean(false); break; case "integer": if (reader.IsEmptyElement) { reader.Read(); - return 0; + return LLSD.FromInteger(0); } if (reader.Read()) { int value = 0; Helpers.TryParse(reader.ReadString().Trim(), out value); - ret = value; + ret = LLSD.FromInteger(value); break; } - ret = 0; + ret = LLSD.FromInteger(0); break; case "real": if (reader.IsEmptyElement) { reader.Read(); - return 0d; + return LLSD.FromReal(0d); } if (reader.Read()) @@ -327,66 +242,66 @@ namespace libsecondlife.LLSD else Helpers.TryParse(str, out value); - ret = value; + ret = LLSD.FromReal(value); break; } - ret = 0d; + ret = LLSD.FromReal(0d); break; case "uuid": if (reader.IsEmptyElement) { reader.Read(); - return LLUUID.Zero; + return LLSD.FromUUID(LLUUID.Zero); } if (reader.Read()) { LLUUID value = LLUUID.Zero; LLUUID.TryParse(reader.ReadString().Trim(), out value); - ret = value; + ret = LLSD.FromUUID(value); break; } - ret = LLUUID.Zero; + ret = LLSD.FromUUID(LLUUID.Zero); break; case "date": if (reader.IsEmptyElement) { reader.Read(); - return Helpers.Epoch; + return LLSD.FromDate(Helpers.Epoch); } if (reader.Read()) { DateTime value = Helpers.Epoch; Helpers.TryParse(reader.ReadString().Trim(), out value); - ret = value; + ret = LLSD.FromDate(value); break; } - ret = Helpers.Epoch; + ret = LLSD.FromDate(Helpers.Epoch); break; case "string": if (reader.IsEmptyElement) { reader.Read(); - return String.Empty; + return LLSD.FromString(String.Empty); } if (reader.Read()) { - ret = reader.ReadString(); + ret = LLSD.FromString(reader.ReadString()); break; } - ret = String.Empty; + ret = LLSD.FromString(String.Empty); break; case "binary": if (reader.IsEmptyElement) { reader.Read(); - return new byte[0]; + return LLSD.FromBinary(new byte[0]); } if (reader.GetAttribute("encoding") != null && reader.GetAttribute("encoding") != "base64") @@ -396,7 +311,7 @@ namespace libsecondlife.LLSD { try { - ret = Convert.FromBase64String(reader.ReadString().Trim()); + ret = LLSD.FromBinary(Convert.FromBase64String(reader.ReadString().Trim())); break; } catch (FormatException ex) @@ -405,7 +320,7 @@ namespace libsecondlife.LLSD } } - ret = new byte[0]; + ret = LLSD.FromBinary(new byte[0]); break; case "map": return ParseXmlMap(reader); @@ -428,23 +343,17 @@ namespace libsecondlife.LLSD } } - private static Dictionary ParseXmlMap(XmlTextReader reader) + private static LLSDMap ParseXmlMap(XmlTextReader reader) { - Dictionary dict = new Dictionary(); - if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "map") throw new NotImplementedException("Expected "); - //while (reader.NodeType != XmlNodeType.Element && reader.LocalName != "map") - //{ - // if (!reader.Read()) - // throw new LLSDException("Couldn't find a map to parse"); - //} + LLSDMap map = new LLSDMap(); if (reader.IsEmptyElement) { reader.Read(); - return dict; + return map; } if (reader.Read()) @@ -468,32 +377,26 @@ namespace libsecondlife.LLSD throw new LLSDException("Expected "); if (reader.Read()) - dict[key] = ParseXmlElement(reader); + map[key] = ParseXmlElement(reader); else throw new LLSDException("Failed to parse a value for key " + key); } } - return dict; + return map; } - private static List ParseXmlArray(XmlTextReader reader) + private static LLSDArray ParseXmlArray(XmlTextReader reader) { - List list = new List(); - if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "array") throw new LLSDException("Expected "); - //while (reader.NodeType != XmlNodeType.Element && reader.LocalName != "array") - //{ - // if (!reader.Read()) - // throw new LLSDException("Couldn't find an array to parse"); - //} + LLSDArray array = new LLSDArray(); if (reader.IsEmptyElement) { reader.Read(); - return list; + return array; } if (reader.Read()) @@ -508,11 +411,11 @@ namespace libsecondlife.LLSD break; } - list.Add(ParseXmlElement(reader)); + array.Add(ParseXmlElement(reader)); } } - return list; + return array; } private static void SkipWhitespace(XmlTextReader reader) diff --git a/libsecondlife/Login.cs b/libsecondlife/Login.cs index 80fe09b9..fa71c5f5 100644 --- a/libsecondlife/Login.cs +++ b/libsecondlife/Login.cs @@ -30,7 +30,7 @@ using System.Threading; using System.IO; using System.Net; using System.Security.Cryptography.X509Certificates; -using libsecondlife.LLSD; +using libsecondlife.StructuredData; using libsecondlife.Packets; using CookComputing.XmlRpc; @@ -113,10 +113,6 @@ namespace libsecondlife /// public string ViewerDigest; /// - public string UserAgent; - /// - public string Author; - /// public List Options; } @@ -328,11 +324,11 @@ namespace libsecondlife /// Account first name /// Account last name /// Account password - /// Client application name and version - /// Client application author + /// Client application name + /// Client application version /// public LoginParams DefaultLoginParams(string firstName, string lastName, string password, - string userAgent, string author) + string userAgent, string userVersion) { List options = new List(); options.Add("inventory-root"); @@ -359,13 +355,11 @@ namespace libsecondlife loginParams.LastName = lastName; loginParams.Password = password; loginParams.Start = "last"; - loginParams.Channel = "libsecondlife"; - loginParams.Version = Client.Settings.VERSION; + loginParams.Channel = userAgent + " (libsecondlife)"; + loginParams.Version = userVersion; loginParams.Platform = "Win"; loginParams.MAC = String.Empty; loginParams.ViewerDigest = String.Empty; - loginParams.UserAgent = userAgent; - loginParams.Author = author; loginParams.Options = options; return loginParams; @@ -445,8 +439,6 @@ namespace libsecondlife CurrentContext.Params.ViewerDigest = String.Empty; if (CurrentContext.Params.Version == null) CurrentContext.Params.Version = String.Empty; - if (CurrentContext.Params.UserAgent == null) - CurrentContext.Params.UserAgent = String.Empty; if (CurrentContext.Params.Platform == null) CurrentContext.Params.Platform = String.Empty; if (CurrentContext.Params.Options == null) @@ -478,8 +470,6 @@ namespace libsecondlife loginParams.version = CurrentContext.Params.Version; loginParams.platform = CurrentContext.Params.Platform; loginParams.mac = CurrentContext.Params.MAC; - loginParams.user_agent = CurrentContext.Params.UserAgent; - loginParams.author = CurrentContext.Params.Author; loginParams.agree_to_tos = "true"; loginParams.read_critical = "true"; loginParams.viewer_digest = CurrentContext.Params.ViewerDigest; @@ -803,9 +793,6 @@ namespace libsecondlife public string version; public string platform; public string mac; - [XmlRpcMember("user-agent")] - public string user_agent; - public string author; public string agree_to_tos; public string read_critical; public string viewer_digest; diff --git a/libsecondlife/Prims.cs b/libsecondlife/Prims.cs index 580df7ac..e0d8370b 100644 --- a/libsecondlife/Prims.cs +++ b/libsecondlife/Prims.cs @@ -26,6 +26,7 @@ using System; using System.Collections.Generic; +using libsecondlife.StructuredData; namespace libsecondlife { @@ -443,6 +444,64 @@ namespace libsecondlife return prim; } + public static Primitive FromLLSD(LLSD llsd) + { + Primitive prim = new Primitive(); + LLObject.ObjectData data = new ObjectData(); + + LLSDMap map = (LLSDMap)llsd; + LLSDMap volume = (LLSDMap)map["volume"]; + LLSDMap path = (LLSDMap)volume["path"]; + LLSDMap profile = (LLSDMap)volume["profile"]; + + #region Path/Profile + + data.PathBegin = (float)path["begin"].AsReal(); + data.PathCurve = (PathCurve)path["curve"].AsReal(); + 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 = path["twist"].AsInteger(); + data.PathTwistBegin = path["twist_begin"].AsInteger(); + + data.ProfileBegin = (float)profile["begin"].AsReal(); + data.ProfileCurve = (ProfileCurve)profile["curve"].AsReal(); + data.ProfileEnd = (float)profile["end"].AsReal(); + data.ProfileHollow = (float)profile["hollow"].AsReal(); + + #endregion Path/Profile + + prim.Data = data; + + if (map["phantom"].AsBoolean()) + prim.Flags |= ObjectFlags.Phantom; + + if (map["physical"].AsBoolean()) + prim.Flags |= ObjectFlags.Physics; + + if (map["shadows"].AsBoolean()) + prim.Flags |= ObjectFlags.CastShadows; + + prim.Position = LLVector3.FromLLSD(map["position"]); + prim.Rotation = LLQuaternion.FromLLSD(map["rotation"]); + prim.Scale = LLVector3.FromLLSD(map["scale"]); + + prim.Textures = TextureEntry.FromLLSD(map["textures"]); + + LLSD parentID; + if (map.TryGetValue("parentid", out parentID)) + prim.ParentID = (uint)parentID.AsInteger(); + + return prim; + } + internal int SetExtraParamsFromBytes(byte[] data, int pos) { int i = pos; diff --git a/libsecondlife/Settings.cs b/libsecondlife/Settings.cs index 2ce2cd7a..1afc980d 100644 --- a/libsecondlife/Settings.cs +++ b/libsecondlife/Settings.cs @@ -42,8 +42,6 @@ namespace libsecondlife public const string AGNI_LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; public const string ADITI_LOGIN_SERVER = "https://login.aditi.lindenlab.com/cgi-bin/login.cgi"; - /// The version of libsecondlife (not the SL protocol itself) - public string VERSION = "libsecondlife 0.0.9"; /// XML-RPC login server to connect to public string LOGIN_SERVER = AGNI_LOGIN_SERVER; /// The relative directory where files needed for baking are kept diff --git a/libsecondlife/TextureEntry.cs b/libsecondlife/TextureEntry.cs index f702cc96..981a82d7 100644 --- a/libsecondlife/TextureEntry.cs +++ b/libsecondlife/TextureEntry.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.IO; +using libsecondlife.StructuredData; namespace libsecondlife { @@ -410,22 +411,41 @@ namespace libsecondlife hasAttribute = TextureAttributes.None; } - public Dictionary ToLLSD() + public LLSD ToLLSD() { - Dictionary tex = new Dictionary(10); - tex["bump"] = (int)Bump; + LLSDMap tex = new LLSDMap(10); + tex["bump"] = LLSD.FromInteger((int)Bump); tex["colors"] = RGBA.ToLLSD(); - tex["fullbright"] = Fullbright; - tex["imageid"] = TextureID; - tex["imagerot"] = Rotation; - tex["media_flags"] = MediaFlags; - tex["offsets"] = OffsetU; - tex["offsett"] = OffsetV; - tex["scales"] = RepeatU; - tex["scalet"] = RepeatV; + tex["fullbright"] = LLSD.FromBoolean(Fullbright); + tex["imageid"] = LLSD.FromUUID(TextureID); + tex["imagerot"] = LLSD.FromReal(Rotation); + tex["media_flags"] = LLSD.FromInteger(Convert.ToInt32(MediaFlags)); + tex["offsets"] = LLSD.FromReal(OffsetU); + tex["offsett"] = LLSD.FromReal(OffsetV); + tex["scales"] = LLSD.FromReal(RepeatU); + tex["scalet"] = LLSD.FromReal(RepeatV); return tex; } + public static TextureEntryFace FromLLSD(LLSD llsd, TextureEntryFace defaultFace) + { + LLSDMap map = (LLSDMap)llsd; + + TextureEntryFace face = new TextureEntryFace(defaultFace); + face.Bump = (Bumpiness)map["bump"].AsInteger(); + face.RGBA = LLColor.FromLLSD(map["colors"]); + face.Fullbright = map["fullbright"].AsBoolean(); + face.TextureID = map["imageid"].AsUUID(); + face.Rotation = (float)map["imagerot"].AsReal(); + face.MediaFlags = map["media_flags"].AsBoolean(); + face.OffsetU = (float)map["offsets"].AsReal(); + face.OffsetV = (float)map["offsett"].AsReal(); + face.RepeatU = (float)map["scales"].AsReal(); + face.RepeatV = (float)map["scalet"].AsReal(); + + return face; + } + /// /// /// @@ -466,6 +486,28 @@ namespace libsecondlife 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.Shiny = defaultFace.Shiny; + DefaultTexture.TexMapType = defaultFace.TexMapType; + DefaultTexture.TextureID = defaultFace.TextureID; + } + /// /// Constructor that creates the TextureEntry class from a byte array /// @@ -516,17 +558,41 @@ namespace libsecondlife /// /// /// - public List ToLLSD() + public LLSD ToLLSD() { - List te = new List(); + LLSDArray array = new LLSDArray(); for (int i = 0; i < MAX_FACES; i++) { if (FaceTextures[i] != null) - te.Add(FaceTextures[i].ToLLSD()); + array.Add(FaceTextures[i].ToLLSD()); } - return te; + return array; + } + + public static TextureEntry FromLLSD(LLSD llsd) + { + LLSDArray array = (LLSDArray)llsd; + LLSDMap faceLLSD; + + if (array.Count > 0) + { + faceLLSD = (LLSDMap)array[0]; + TextureEntryFace defaultFace = TextureEntryFace.FromLLSD(faceLLSD, null); + TextureEntry te = new TextureEntry(defaultFace); + + for (int i = 0; i < array.Count; i++) + { + te.FaceTextures[i] = TextureEntryFace.FromLLSD(array[i], defaultFace); + } + + return te; + } + else + { + throw new ArgumentException("LLSD contains no elements"); + } } private void FromBytes(byte[] data, int pos, int length) diff --git a/libsecondlife/Types.cs b/libsecondlife/Types.cs index a99ee135..79c14108 100644 --- a/libsecondlife/Types.cs +++ b/libsecondlife/Types.cs @@ -26,6 +26,7 @@ using System; using System.Collections.Generic; +using libsecondlife.StructuredData; namespace libsecondlife { @@ -460,12 +461,12 @@ namespace libsecondlife return byteArray; } - public float[] ToLLSD() + public LLSD ToLLSD() { - float[] array = new float[3]; - array[0] = X; - array[1] = Y; - array[2] = Z; + LLSDArray array = new LLSDArray(); + array.Add(LLSD.FromReal(X)); + array.Add(LLSD.FromReal(Y)); + array.Add(LLSD.FromReal(Z)); return array; } @@ -473,6 +474,21 @@ namespace libsecondlife #region Static Methods + public static LLVector3 FromLLSD(LLSD llsd) + { + if (llsd.Type == LLSDType.Array) + { + LLSDArray array = (LLSDArray)llsd; + + if (array.Count == 3) + { + return new LLVector3((float)array[0].AsReal(), (float)array[1].AsReal(), (float)array[2].AsReal()); + } + } + + return LLVector3.Zero; + } + /// /// Calculate the magnitude of the supplied vector /// @@ -833,12 +849,12 @@ namespace libsecondlife return byteArray; } - public double[] ToLLSD() + public LLSD ToLLSD() { - double[] array = new double[3]; - array[0] = X; - array[1] = Y; - array[2] = Z; + LLSDArray array = new LLSDArray(); + array.Add(LLSD.FromReal(X)); + array.Add(LLSD.FromReal(Y)); + array.Add(LLSD.FromReal(Z)); return array; } @@ -846,6 +862,21 @@ namespace libsecondlife #region Static Methods + public static LLVector3d FromLLSD(LLSD llsd) + { + if (llsd.Type == LLSDType.Array) + { + LLSDArray array = (LLSDArray)llsd; + + if (array.Count == 3) + { + return new LLVector3d(array[0].AsReal(), array[1].AsReal(), array[2].AsReal()); + } + } + + return LLVector3d.Zero; + } + /// /// Calculates the distance between two vectors /// @@ -1015,18 +1046,41 @@ namespace libsecondlife return byteArray; } - public float[] ToLLSD() + public LLSD ToLLSD() { - float[] array = new float[4]; - array[0] = X; - array[1] = Y; - array[2] = Z; - array[3] = S; + LLSDArray array = new LLSDArray(); + array.Add(LLSD.FromReal(X)); + array.Add(LLSD.FromReal(Y)); + array.Add(LLSD.FromReal(Z)); + array.Add(LLSD.FromReal(S)); return array; } #endregion Public Methods + #region Static Methods + + public static LLVector4 FromLLSD(LLSD llsd) + { + if (llsd.Type == LLSDType.Array) + { + LLSDArray array = (LLSDArray)llsd; + + if (array.Count == 3) + { + return new LLVector4( + (float)array[0].AsReal(), + (float)array[1].AsReal(), + (float)array[2].AsReal(), + (float)array[3].AsReal()); + } + } + + return LLVector4.Zero; + } + + #endregion Static Methods + #region Overrides /// @@ -1060,7 +1114,7 @@ namespace libsecondlife #endregion Overrides - #region Operators + #region Operators /// /// @@ -1133,8 +1187,8 @@ namespace libsecondlife return new LLVector4(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z, lhs.S * rhs.S); } - #endregion Operators + /// An LLVector4 with a value of 0,0,0,0 public readonly static LLVector4 Zero = new LLVector4(); } @@ -1172,6 +1226,15 @@ namespace libsecondlife A = (float)a * quanta; } + public LLColor(float r, float g, float b, float a) + { + // Valid range is from 0.0 to 1.0 + R = Helpers.Clamp(r, 0f, 1f); + G = Helpers.Clamp(g, 0f, 1f); + B = Helpers.Clamp(b, 0f, 1f); + A = Helpers.Clamp(a, 0f, 1f); + } + /// /// /// @@ -1220,18 +1283,41 @@ namespace libsecondlife /// /// /// - public float[] ToLLSD() + public LLSD ToLLSD() { - float[] array = new float[4]; - array[0] = R; - array[1] = G; - array[2] = B; - array[3] = A; + LLSDArray array = new LLSDArray(); + array.Add(LLSD.FromReal(R)); + array.Add(LLSD.FromReal(G)); + array.Add(LLSD.FromReal(B)); + array.Add(LLSD.FromReal(A)); return array; } #endregion Public Methods + #region Static Methods + + public static LLColor FromLLSD(LLSD llsd) + { + if (llsd.Type == LLSDType.Array) + { + LLSDArray array = (LLSDArray)llsd; + + if (array.Count == 3) + { + return new LLColor( + (float)array[0].AsReal(), + (float)array[1].AsReal(), + (float)array[2].AsReal(), + (float)array[3].AsReal()); + } + } + + return LLColor.Black; + } + + #endregion Static Methods + #region Overrides /// @@ -1469,13 +1555,13 @@ namespace libsecondlife return bytes; } - public float[] ToLLSD() + public LLSD ToLLSD() { - float[] array = new float[4]; - array[0] = X; - array[1] = Y; - array[2] = Z; - array[3] = W; + LLSDArray array = new LLSDArray(); + array.Add(LLSD.FromReal(X)); + array.Add(LLSD.FromReal(Y)); + array.Add(LLSD.FromReal(Z)); + array.Add(LLSD.FromReal(W)); return array; } @@ -1483,6 +1569,25 @@ namespace libsecondlife #region Static Methods + public static LLQuaternion FromLLSD(LLSD llsd) + { + if (llsd.Type == LLSDType.Array) + { + LLSDArray array = (LLSDArray)llsd; + + if (array.Count == 4) + { + return new LLQuaternion( + (float)array[0].AsReal(), + (float)array[1].AsReal(), + (float)array[2].AsReal(), + (float)array[3].AsReal()); + } + } + + return LLQuaternion.Identity; + } + /// /// Calculate the magnitude of the supplied quaternion /// diff --git a/libsecondlife/libsecondlife.Utilities/RegistrationApi.cs b/libsecondlife/libsecondlife.Utilities/RegistrationApi.cs index 60ee2ce0..81b3de87 100644 --- a/libsecondlife/libsecondlife.Utilities/RegistrationApi.cs +++ b/libsecondlife/libsecondlife.Utilities/RegistrationApi.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Text; -using libsecondlife.LLSD; +using libsecondlife.StructuredData; namespace libsecondlife { @@ -217,9 +217,9 @@ namespace libsecondlife throw new InvalidOperationException("access denied; only approved developers have access to the registration api"); // Create the POST data - Dictionary query = new Dictionary(); - query.Add("username", firstName); - query.Add("last_name_id", lastName.ID); + LLSDMap query = new LLSDMap(); + query.Add("username", LLSD.FromString(firstName)); + query.Add("last_name_id", LLSD.FromInteger(lastName.ID)); byte[] postData = LLSDParser.SerializeXmlBytes(query); CapsRequest request = new CapsRequest(_caps.CheckName.AbsoluteUri, String.Empty, null); @@ -258,31 +258,31 @@ namespace libsecondlife throw new InvalidOperationException("access denied; only approved developers have access to the registration api"); // Create the POST data - Dictionary query = new Dictionary(); - query.Add("username", user.FirstName); - query.Add("last_name_id", user.LastName.ID); - query.Add("email", user.Email); - query.Add("password", user.Password); - query.Add("dob", user.Birthdate.ToString("yyyy-MM-dd")); + LLSDMap query = new LLSDMap(); + query.Add("username", LLSD.FromString(user.FirstName)); + query.Add("last_name_id", LLSD.FromInteger(user.LastName.ID)); + query.Add("email", LLSD.FromString(user.Email)); + query.Add("password", LLSD.FromString(user.Password)); + query.Add("dob", LLSD.FromString(user.Birthdate.ToString("yyyy-MM-dd"))); if (user.LimitedToEstate != null) - query.Add("limited_to_estate", user.LimitedToEstate.Value); + query.Add("limited_to_estate", LLSD.FromInteger(user.LimitedToEstate.Value)); if (!string.IsNullOrEmpty(user.StartRegionName)) - query.Add("start_region_name", user.LimitedToEstate.Value); + query.Add("start_region_name", LLSD.FromInteger(user.LimitedToEstate.Value)); if (user.StartLocation != null) { - query.Add("start_local_x", user.StartLocation.Value.X); - query.Add("start_local_y", user.StartLocation.Value.Y); - query.Add("start_local_z", user.StartLocation.Value.Z); + query.Add("start_local_x", LLSD.FromReal(user.StartLocation.Value.X)); + query.Add("start_local_y", LLSD.FromReal(user.StartLocation.Value.Y)); + query.Add("start_local_z", LLSD.FromReal(user.StartLocation.Value.Z)); } if (user.StartLookAt != null) { - query.Add("start_look_at_x", user.StartLookAt.Value.X); - query.Add("start_look_at_y", user.StartLookAt.Value.Y); - query.Add("start_look_at_z", user.StartLookAt.Value.Z); + query.Add("start_look_at_x", LLSD.FromReal(user.StartLookAt.Value.X)); + query.Add("start_look_at_y", LLSD.FromReal(user.StartLookAt.Value.Y)); + query.Add("start_look_at_z", LLSD.FromReal(user.StartLookAt.Value.Z)); } byte[] postData = LLSDParser.SerializeXmlBytes(query); diff --git a/libsecondlife/libsecondlife.Utilities/Utilities.cs b/libsecondlife/libsecondlife.Utilities/Utilities.cs index 347b3fb5..403b28c5 100644 --- a/libsecondlife/libsecondlife.Utilities/Utilities.cs +++ b/libsecondlife/libsecondlife.Utilities/Utilities.cs @@ -22,36 +22,6 @@ namespace libsecondlife.Utilities Underwater } - public enum Platform - { - Unknown, - Windows, - Linux, - OSX - } - - public static class SLPlatformTools - { - public const string OSX_CHECK_FILE = "/Library/Extensions.kextcache"; - - public static Platform GetRunningPlatform() - { - 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; - } - } - } - public static class Realism { /// diff --git a/libsecondlife/libsecondlife.Utilities/VoiceManager.cs b/libsecondlife/libsecondlife.Utilities/VoiceManager.cs index 3a84bbce..14590b9f 100644 --- a/libsecondlife/libsecondlife.Utilities/VoiceManager.cs +++ b/libsecondlife/libsecondlife.Utilities/VoiceManager.cs @@ -32,6 +32,7 @@ using System.IO; using System.Xml; using System.Threading; using libsecondlife; +using libsecondlife.StructuredData; namespace libsecondlife.Utilities { @@ -503,11 +504,13 @@ namespace libsecondlife.Utilities #region Callbacks - private void RequiredVoiceVersionEventHandler(string message, Dictionary body, CapsEventQueue caps) + private void RequiredVoiceVersionEventHandler(string message, LLSD llsd, CapsEventQueue caps) { + LLSDMap body = (LLSDMap)llsd; + if (body.ContainsKey("major_version")) { - int majorVersion = (int)body["major_version"]; + int majorVersion = body["major_version"].AsInteger(); if (VOICE_MAJOR_VERSION != majorVersion) {