diff --git a/Assets/Plugins/LibreMetaverse/AgentManager.cs b/Assets/Plugins/LibreMetaverse/AgentManager.cs index a88a259..04ee90d 100644 --- a/Assets/Plugins/LibreMetaverse/AgentManager.cs +++ b/Assets/Plugins/LibreMetaverse/AgentManager.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2019-2022, Sjofn LLC * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -1047,7 +1048,7 @@ namespace OpenMetaverse remove { lock (m_GroupChatJoinedLock) { m_GroupChatJoined -= value; } } } - /// The event subscribers. null if no subcribers + /// The event subscribers. null if no subscribers private EventHandler m_AlertMessage; /// Raises the AlertMessage event @@ -1270,24 +1271,24 @@ namespace OpenMetaverse /// Your (client) avatars /// "client", "agent", and "avatar" all represent the same thing - public UUID AgentID => id; + public UUID AgentID { get; private set; } /// Temporary assigned to this session, used for /// verifying our identity in packets - public UUID SessionID => sessionID; + public UUID SessionID { get; private set; } /// Shared secret that is never sent over the wire - public UUID SecureSessionID => secureSessionID; + public UUID SecureSessionID { get; private set; } /// Your (client) avatar ID, local to the current region/sim public uint LocalID => localID; /// Where the avatar started at login. Can be "last", "home" /// or a login - public string StartLocation => startLocation; + public string StartLocation { get; private set; } = string.Empty; /// The access level of this agent, usually M, PG or A - public string AgentAccess => agentAccess; + public string AgentAccess { get; private set; } = string.Empty; /// The CollisionPlane of Agent public Vector4 CollisionPlane => collisionPlane; @@ -1301,21 +1302,24 @@ namespace OpenMetaverse /// A which specifies the angular speed, and axis about which an Avatar is rotating. public Vector3 AngularVelocity => angularVelocity; + /// Region handle for 'home' region + public ulong HomeRegionHandle => home.RegionHandle; + /// Position avatar client will goto when login to 'home' or during /// teleport request to 'home' region. - public Vector3 HomePosition => homePosition; + public Vector3 HomePosition => home.Position; /// LookAt point saved/restored with HomePosition - public Vector3 HomeLookAt => homeLookAt; + public Vector3 HomeLookAt => home.LookAt; /// Avatar First Name (i.e. Philip) - public string FirstName => firstName; + public string FirstName { get; private set; } = string.Empty; /// Avatar Last Name (i.e. Linden) - public string LastName => lastName; + public string LastName { get; private set; } = string.Empty; /// LookAt point received with the login response message - public Vector3 LookAt => lookAt; + public Vector3 LookAt { get; private set; } /// Avatar Full Name (i.e. Philip Linden) public string Name @@ -1325,28 +1329,28 @@ namespace OpenMetaverse // 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 = $"{firstName} {lastName}"; + fullName = $"{FirstName} {LastName}"; return fullName; } } /// Gets the health of the agent - public float Health => health; + public float Health { get; private set; } /// Gets the current balance of the agent - public int Balance => balance; + public int Balance { get; private set; } /// Gets the local ID of the prim the agent is sitting on, /// zero if the avatar is not currently sitting public uint SittingOn => sittingOn; /// Gets the of the agents active group. - public UUID ActiveGroup => activeGroup; + public UUID ActiveGroup { get; private set; } /// Gets the Agents powers in the currently active group - public GroupPowers ActiveGroupPowers => activeGroupPowers; + public GroupPowers ActiveGroupPowers { get; private set; } /// Current status message for teleporting - public string TeleportMessage => teleportMessage; + public string TeleportMessage { get; private set; } = string.Empty; /// Current position of the agent as a relative offset from /// the simulator, or the parent object if we are sitting on something @@ -1466,25 +1470,11 @@ namespace OpenMetaverse #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 HomeInfo home; 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 @@ -1549,6 +1539,7 @@ namespace OpenMetaverse Client.Network.RegisterLoginResponseCallback(Network_OnLoginResponse); // Alert Messages Client.Network.RegisterCallback(PacketType.AlertMessage, AlertMessageHandler); + Client.Network.RegisterCallback(PacketType.AgentAlertMessage, AgentAlertMessageHandler); // 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: @@ -1578,17 +1569,17 @@ namespace OpenMetaverse { int group_id = message_chunk_group_id; message_chunk_group_id++; - if (message_chunk_group_id > 500) message_chunk_group_id = 1; + if (message_chunk_group_id > 500) { message_chunk_group_id = 1; } string[] chunks = message.SplitBy(900).ToArray(); int chunkid = 1; - foreach(string C in chunks) + foreach(string chunk in chunks) { string chunk_grouping = ""; if(hide_chunk_grouping == false) { - chunk_grouping = "[" + group_id.ToString() + "|" + chunkid.ToString() + "|"+chunks.Length.ToString()+"]"; + chunk_grouping = $"[{group_id}|{chunkid}|{chunks.Length}]"; } - Chat(""+ chunk_grouping+"" + C + "", channel, type, false); + Chat($"{chunk_grouping}{chunk}", channel, type, false); chunkid++; } } @@ -1598,7 +1589,7 @@ namespace OpenMetaverse { AgentData = { - AgentID = id, + AgentID = AgentID, SessionID = Client.Self.SessionID }, ChatData = @@ -1616,6 +1607,26 @@ namespace OpenMetaverse /// Request any instant messages sent while the client was offline to be resent. /// public void RetrieveInstantMessages() + { + Uri offlineMsgsCap = Client.Network.CurrentSim.Caps.CapabilityURI("ReadOfflineMsgs"); + if (offlineMsgsCap == null + || Client.Network.CurrentSim.Caps.CapabilityURI("AcceptFriendship") == null + || Client.Network.CurrentSim.Caps.CapabilityURI("AcceptGroupInvite") == null) + { + // fallback to lludp + RetrieveInstantMessagesLegacy(); + return; + } + + var request = new CapsClient(offlineMsgsCap); + request.OnComplete += OfflineMessageHandlerCallback; + request.GetRequestAsync(Client.Settings.CAPS_TIMEOUT); + } + + /// + /// Request offline instant messages via the legacy LLUDP packet + /// + private void RetrieveInstantMessagesLegacy() { RetrieveInstantMessagesPacket p = new RetrieveInstantMessagesPacket { @@ -1902,7 +1913,7 @@ namespace OpenMetaverse if (request != null) { ChatSessionAcceptInvitation acceptInvite = new ChatSessionAcceptInvitation {SessionID = session_id}; - request.BeginGetResponse(acceptInvite.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(acceptInvite.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); lock (GroupChatSessions.Dictionary) if (!GroupChatSessions.ContainsKey(session_id)) @@ -1941,7 +1952,7 @@ namespace OpenMetaverse startConference.SessionID = tmp_session_id; - request.BeginGetResponse(startConference.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(startConference.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2490,8 +2501,8 @@ namespace OpenMetaverse /// /// The Objects Simulator Local ID /// - /// - /// + /// + /// public void DeGrab(uint objectLocalID) { DeGrab(objectLocalID, TOUCH_INVALID_TEXCOORD, TOUCH_INVALID_TEXCOORD, @@ -2658,14 +2669,14 @@ namespace OpenMetaverse { AgentData = { - AgentID = id, + AgentID = AgentID, SessionID = Client.Self.SessionID }, MoneyData = { Description = Utils.StringToBytes(description), DestID = target, - SourceID = id, + SourceID = AgentID, TransactionType = (int) type, AggregatePermInventory = 0, AggregatePermNextOwner = 0, @@ -2957,7 +2968,7 @@ namespace OpenMetaverse teleportStat == TeleportStatus.Start || teleportStat == TeleportStatus.Progress) { - teleportMessage = "Teleport timed out."; + TeleportMessage = "Teleport timed out."; teleportStat = TeleportStatus.Failed; } @@ -3004,7 +3015,7 @@ namespace OpenMetaverse } else { - teleportMessage = "Unable to resolve name: " + simName; + TeleportMessage = "Unable to resolve name: " + simName; teleportStat = TeleportStatus.Failed; return false; } @@ -3067,7 +3078,7 @@ namespace OpenMetaverse teleportStat == TeleportStatus.Start || teleportStat == TeleportStatus.Progress) { - teleportMessage = "Teleport timed out."; + TeleportMessage = "Teleport timed out."; teleportStat = TeleportStatus.Failed; } @@ -3109,7 +3120,7 @@ namespace OpenMetaverse } else { - teleportMessage = "CAPS event queue is not running"; + TeleportMessage = "CAPS event queue is not running"; teleportEvent.Set(); teleportStat = TeleportStatus.Failed; } @@ -3153,7 +3164,7 @@ namespace OpenMetaverse { AgentData = { - AgentID = Client.Self.id, + AgentID = Client.Self.AgentID, SessionID = Client.Self.SessionID }, Info = @@ -3236,8 +3247,8 @@ namespace OpenMetaverse { AgentData = { - AgentID = id, - SessionID = sessionID + AgentID = AgentID, + SessionID = SessionID }, PropertiesData = { @@ -3255,7 +3266,7 @@ namespace OpenMetaverse } /// - /// Update agents profile interests + /// Update agent's profile interests /// /// selection of interests from struct public void UpdateInterests(Avatar.Interests interests) @@ -3264,8 +3275,8 @@ namespace OpenMetaverse { AgentData = { - AgentID = id, - SessionID = sessionID + AgentID = AgentID, + SessionID = SessionID }, PropertiesData = { @@ -3280,6 +3291,29 @@ namespace OpenMetaverse Client.Network.SendPacket(aiup); } + /// + /// Update agent's private notes for target avatar + /// + /// target avatar for notes + /// notes to store + public void UpdateProfileNotes(UUID target, string notes) + { + AvatarNotesUpdatePacket anup = new AvatarNotesUpdatePacket + { + AgentData = + { + AgentID = AgentID, + SessionID = SessionID + }, + Data = + { + TargetID = target, + Notes = Utils.StringToBytes(notes) + } + }; + Client.Network.SendPacket(anup); + } + /// /// 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 @@ -3583,7 +3617,7 @@ namespace OpenMetaverse AgentData = { AgentID = Client.Self.AgentID, - SessionID = Client.Self.sessionID + SessionID = Client.Self.SessionID }, Data = {PickID = pickID} }; @@ -3693,7 +3727,7 @@ namespace OpenMetaverse } }; - request.BeginGetResponse(Client.Settings.CAPS_TIMEOUT); + request.GetRequestAsync(Client.Settings.CAPS_TIMEOUT); } catch (Exception ex) { @@ -3731,7 +3765,7 @@ namespace OpenMetaverse NewDisplayName = newName }; - request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } /// @@ -3750,7 +3784,7 @@ namespace OpenMetaverse }; CapsClient request = Client.Network.CurrentSim.Caps.CreateCapsClient("UpdateAgentLanguage"); - request?.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request?.PostRequestAsync(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } catch (Exception ex) { @@ -3785,15 +3819,15 @@ namespace OpenMetaverse { bool success = true; - if (error == null && result is OSDMap) + if (error == null && result is OSDMap osdMap) { - var map = ((OSDMap)result)["access_prefs"]; - agentAccess = ((OSDMap)map)["max"]; - Logger.Log($"Max maturity access set to {agentAccess}", Helpers.LogLevel.Info, Client ); + var map = osdMap["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); + Logger.Log($"Max maturity unchanged at {AgentAccess}", Helpers.LogLevel.Info, Client); } else { @@ -3803,16 +3837,20 @@ namespace OpenMetaverse if (callback != null) { - try { callback(new AgentAccessEventArgs(success, agentAccess)); } + try { callback(new AgentAccessEventArgs(success, AgentAccess)); } catch { } // *TODO: So gross } }; - OSDMap req = new OSDMap(); - OSDMap prefs = new OSDMap {["max"] = access}; - req["access_prefs"] = prefs; + OSDMap req = new OSDMap + { + ["access_prefs"] = new OSDMap { ["max"] = access } + }; + //OSDMap req = new OSDMap(); + //OSDMap prefs = new OSDMap {["max"] = access}; + //req["access_prefs"] = prefs; - request.BeginGetResponse(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } /// @@ -3851,7 +3889,7 @@ namespace OpenMetaverse var postData = new OSDMap { ["hover_height"] = hoverHeight }; - request.BeginGetResponse(postData, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(postData, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } #endregion Misc @@ -3894,6 +3932,57 @@ namespace OpenMetaverse } } + protected void OfflineMessageHandlerCallback(CapsClient client, OSD response, Exception error) + { + if (error != null) { + Logger.Log($"Failed to retrieve offline messages from the simulator: {error.Message}", + Helpers.LogLevel.Warning); + RetrieveInstantMessagesLegacy(); + return; + } + + if (m_InstantMessage == null) return; // don't bother if we don't have any listeners + + if (!(response is OSDMap respMap) || respMap.Count == 0 || respMap.ContainsKey("messages")) + { + Logger.Log("Failed to retrieve offline messages because the capability returned some goofy shit.", + Helpers.LogLevel.Warning); + RetrieveInstantMessagesLegacy(); + return; + } + + if (respMap["messages"] is OSDArray msgArray) + { + foreach (var osd in msgArray) + { + var msg = (OSDMap)osd; + + InstantMessage message; + message.FromAgentID = msg["from_agent_id"].AsUUID(); + message.FromAgentName = msg["from_agent_name"].AsString(); + message.ToAgentID = msg["to_agent_id"].AsUUID(); + message.RegionID = msg["region_id"].AsUUID(); + message.Dialog = (InstantMessageDialog)msg["dialog"].AsInteger(); + message.IMSessionID = msg["transaction-id"].AsUUID(); + message.Timestamp = new DateTime(msg["timestamp"].AsInteger()); + message.Message = msg["message"].AsString(); + message.Offline = msg.ContainsKey("offline") + ? (InstantMessageOnline)msg["offline"].AsInteger() + : InstantMessageOnline.Offline; + message.ParentEstateID = msg.ContainsKey("parent_estate_id") + ? msg["parent_estate_id"].AsUInteger() : 1; + message.Position = msg.ContainsKey("position") + ? msg["position"].AsVector3() + : new Vector3(msg["local_x"], msg["local_y"], msg["local_z"]); + message.BinaryBucket = msg.ContainsKey("binary_bucket") + ? msg["binary_bucket"].AsBinary() : new byte[] { 0 }; + message.GroupIM = msg.ContainsKey("from_group") && msg["from_group"].AsBoolean(); + + OnInstantMessage(new InstantMessageEventArgs(message, null)); + } + } + } + /// /// Take an incoming Chat packet, auto-parse, and if OnChat is defined call /// that with the appropriate arguments. @@ -4036,7 +4125,7 @@ namespace OpenMetaverse protected void HealthHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; - health = ((HealthMessagePacket)packet).HealthData.Health; + Health = ((HealthMessagePacket)packet).HealthData.Health; } /// Process an incoming packet and raise the appropriate events @@ -4051,17 +4140,17 @@ namespace OpenMetaverse 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; + 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) return; string groupTitle = Utils.BytesToString(p.AgentData.GroupTitle); string groupName = Utils.BytesToString(p.AgentData.GroupName); - OnAgentData(new AgentDataReplyEventArgs(firstName, lastName, activeGroup, groupTitle, activeGroupPowers, groupName)); + OnAgentData(new AgentDataReplyEventArgs(FirstName, LastName, ActiveGroup, groupTitle, ActiveGroupPowers, groupName)); } else { @@ -4080,7 +4169,7 @@ namespace OpenMetaverse if (packet.Type == PacketType.MoneyBalanceReply) { MoneyBalanceReplyPacket reply = (MoneyBalanceReplyPacket)packet; - this.balance = reply.MoneyData.MoneyBalance; + this.Balance = reply.MoneyData.MoneyBalance; if (m_MoneyBalance != null) { @@ -4107,7 +4196,7 @@ namespace OpenMetaverse if (m_Balance != null) { - OnBalance(new BalanceEventArgs(balance)); + OnBalance(new BalanceEventArgs(Balance)); } } @@ -4223,7 +4312,7 @@ namespace OpenMetaverse { TeleportStartPacket start = (TeleportStartPacket)packet; - teleportMessage = "Teleport started"; + TeleportMessage = "Teleport started"; flags = (TeleportFlags)start.Info.TeleportFlags; teleportStat = TeleportStatus.Start; @@ -4233,21 +4322,21 @@ namespace OpenMetaverse { TeleportProgressPacket progress = (TeleportProgressPacket)packet; - teleportMessage = Utils.BytesToString(progress.Info.Message); + TeleportMessage = Utils.BytesToString(progress.Info.Message); flags = (TeleportFlags)progress.Info.TeleportFlags; teleportStat = TeleportStatus.Progress; - Logger.DebugLog($"TeleportProgress received, Message: {teleportMessage}, Flags: {flags}", Client); + Logger.DebugLog($"TeleportProgress received, Message: {TeleportMessage}, Flags: {flags}", Client); } else if (packet.Type == PacketType.TeleportFailed) { TeleportFailedPacket failed = (TeleportFailedPacket)packet; - teleportMessage = Utils.BytesToString(failed.Info.Reason); + TeleportMessage = Utils.BytesToString(failed.Info.Reason); teleportStat = TeleportStatus.Failed; finished = true; - Logger.DebugLog($"TeleportFailed received, Reason: {teleportMessage}", Client); + Logger.DebugLog($"TeleportFailed received, Reason: {TeleportMessage}", Client); } else if (packet.Type == PacketType.TeleportFinish) { @@ -4266,25 +4355,25 @@ namespace OpenMetaverse if (newSimulator != null) { - teleportMessage = "Teleport finished"; + TeleportMessage = "Teleport finished"; teleportStat = TeleportStatus.Finished; Logger.Log($"Moved to new sim {newSimulator}", Helpers.LogLevel.Info, Client); } else { - teleportMessage = "Failed to connect to the new sim after a teleport"; + 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); + Logger.Log(TeleportMessage, Helpers.LogLevel.Error, Client); } } else if (packet.Type == PacketType.TeleportCancel) { //TeleportCancelPacket cancel = (TeleportCancelPacket)packet; - teleportMessage = "Cancelled"; + TeleportMessage = "Cancelled"; teleportStat = TeleportStatus.Cancelled; finished = true; @@ -4294,7 +4383,7 @@ namespace OpenMetaverse { TeleportLocalPacket local = (TeleportLocalPacket)packet; - teleportMessage = "Teleport finished"; + TeleportMessage = "Teleport finished"; flags = (TeleportFlags)local.Info.TeleportFlags; teleportStat = TeleportStatus.Finished; relativePosition = local.Info.Position; @@ -4308,7 +4397,7 @@ namespace OpenMetaverse if (m_Teleport != null) { - OnTeleport(new TeleportEventArgs(teleportMessage, teleportStat, flags)); + OnTeleport(new TeleportEventArgs(TeleportMessage, teleportStat, flags)); } if (finished) teleportEvent.Set(); @@ -4394,17 +4483,16 @@ namespace OpenMetaverse 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; + AgentID = 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; + home = reply.Home; + LookAt = reply.LookAt; if (reply.Gestures != null) { @@ -4671,7 +4759,7 @@ namespace OpenMetaverse AgentID = memberID }; - request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -4689,7 +4777,31 @@ namespace OpenMetaverse AlertMessagePacket alert = (AlertMessagePacket)packet; - OnAlertMessage(new AlertMessageEventArgs(Utils.BytesToString(alert.AlertData.Message))); + string message = Utils.BytesToString(alert.AlertData.Message); + + if (alert.AlertInfo.Length > 0) + { + string notificationid = Utils.BytesToString(alert.AlertInfo[0].Message); + OSDMap extra = (alert.AlertInfo[0].ExtraParams != null && alert.AlertInfo[0].ExtraParams.Length > 0) + ? OSDParser.Deserialize(alert.AlertInfo[0].ExtraParams) as OSDMap + : null; + OnAlertMessage(new AlertMessageEventArgs(message, notificationid, extra)); + } + else + { + OnAlertMessage(new AlertMessageEventArgs(message, null, null)); + } + } + + protected void AgentAlertMessageHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AlertMessage == null) return; + Packet packet = e.Packet; + + AgentAlertMessagePacket alert = (AgentAlertMessagePacket)packet; + // HACK: Agent alerts support modal and Generic Alerts do not, but it's all the same for + // my simplified ass right now. + OnAlertMessage(new AlertMessageEventArgs(Utils.BytesToString(alert.AlertData.Message), null, null)); } /// Process an incoming packet and raise the appropriate events @@ -5309,14 +5421,20 @@ namespace OpenMetaverse { /// Get the alert message public string Message { get; } + public string NotificationId { get; } + public OSDMap ExtraParams { get; } /// /// Construct a new instance of the AlertMessageEventArgs class /// - /// The alert message - public AlertMessageEventArgs(string message) + /// user readable message + /// notification id for alert, may be null + /// any extra params in OSD format, may be null + public AlertMessageEventArgs(string message, string notificationid, OSDMap extraparams) { Message = message; + NotificationId = notificationid; + ExtraParams = extraparams; } } diff --git a/Assets/Plugins/LibreMetaverse/AgentManagerMovement.cs b/Assets/Plugins/LibreMetaverse/AgentManagerMovement.cs index bfd42e7..10ac4ed 100644 --- a/Assets/Plugins/LibreMetaverse/AgentManagerMovement.cs +++ b/Assets/Plugins/LibreMetaverse/AgentManagerMovement.cs @@ -27,7 +27,6 @@ using System; using System.Threading; using OpenMetaverse.Packets; -using UnityEngine; namespace OpenMetaverse { @@ -378,10 +377,7 @@ namespace OpenMetaverse } } /// The current value of the agent control flags - public uint AgentControls - { - get { return agentControls; } - } + public uint AgentControls { get; private set; } /// Gets or sets the interval in milliseconds at which /// AgentUpdate packets are sent to the current simulator. Setting @@ -421,11 +417,7 @@ namespace OpenMetaverse } /// Reset movement controls every time we send an update - public bool AutoResetControls - { - get { return autoResetControls; } - set { autoResetControls = value; } - } + public bool AutoResetControls { get; set; } #endregion Properties @@ -460,13 +452,11 @@ namespace OpenMetaverse 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) @@ -599,8 +589,6 @@ namespace OpenMetaverse /// Simulator to send the update to public void SendUpdate(bool reliable, Simulator simulator) { - Debug.Log("sending movement packet."); - // 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)) @@ -612,7 +600,7 @@ namespace OpenMetaverse Vector3 zAxis = Camera.UpAxis; // Attempted to sort these in a rough order of how often they might change - if (agentControls == 0 && + if (AgentControls == 0 && yAxis == LastCameraYAxis && origin == LastCameraCenter && State == lastState && @@ -655,13 +643,13 @@ namespace OpenMetaverse update.AgentData.CameraUpAxis = zAxis; update.AgentData.Far = Camera.Far; update.AgentData.State = (byte)State; - update.AgentData.ControlFlags = agentControls; + update.AgentData.ControlFlags = AgentControls; update.AgentData.Flags = (byte)Flags; Client.Network.SendPacket(update, simulator); - Logger.DebugLog("sent packet of agent movement!"); + Logger.DebugLog("sent out a packet of agent movement!"); - if (autoResetControls) { + if (AutoResetControls) { ResetControlFlags(); } } @@ -714,20 +702,20 @@ namespace OpenMetaverse private bool GetControlFlag(ControlFlags flag) { - return (agentControls & (uint)flag) != 0; + return (AgentControls & (uint)flag) != 0; } private void SetControlFlag(ControlFlags flag, bool value) { - if (value) agentControls |= (uint)flag; - else agentControls &= ~((uint)flag); + 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 &= + AgentControls &= (uint)(ControlFlags.AGENT_CONTROL_AWAY | ControlFlags.AGENT_CONTROL_FLY | ControlFlags.AGENT_CONTROL_MOUSELOOK | diff --git a/Assets/Plugins/LibreMetaverse/AppearanceManager.cs b/Assets/Plugins/LibreMetaverse/AppearanceManager.cs index 3f84da4..a05c21a 100644 --- a/Assets/Plugins/LibreMetaverse/AppearanceManager.cs +++ b/Assets/Plugins/LibreMetaverse/AppearanceManager.cs @@ -30,7 +30,6 @@ using System.Collections.Generic; using System.Threading; using System.Linq; using System.Threading.Tasks; -using LibreMetaverse; using Microsoft.Collections.Extensions; using OpenMetaverse.Packets; using OpenMetaverse.Imaging; @@ -367,7 +366,7 @@ namespace OpenMetaverse /// Visual parameters last sent to the sim public byte[] MyVisualParameters; - + /// Textures about this client sent to the sim public Primitive.TextureEntry MyTextures; @@ -414,7 +413,7 @@ namespace OpenMetaverse { MaxDegreeOfParallelism = MAX_CONCURRENT_DOWNLOADS }; - + #endregion Private Members /// @@ -485,7 +484,7 @@ namespace OpenMetaverse // This is the first time setting appearance, run through the entire sequence AppearanceThread = new Thread( - delegate() + delegate () { var cancellationToken = CancellationTokenSource.Token; bool success = true; @@ -495,7 +494,7 @@ namespace OpenMetaverse { // 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; + Textures[(int)BakeTypeToAgentTextureIndex((BakeType)bakedIndex)].TextureID = UUID.Zero; } // FIXME: we really need to make this better... @@ -700,7 +699,7 @@ namespace OpenMetaverse new AgentCachedTexturePacket.WearableDataBlock { ID = hash, - TextureIndex = (byte) bakedIndex + TextureIndex = (byte)bakedIndex }; hashes.Add(block); @@ -737,8 +736,8 @@ namespace OpenMetaverse [Obsolete] public UUID GetWearableAsset(WearableType type) { - return Wearables.TryGetValue(type, out var wearableList) - ? wearableList.First().AssetID + return Wearables.TryGetValue(type, out var wearableList) + ? wearableList.First().AssetID : UUID.Zero; } @@ -804,7 +803,8 @@ namespace OpenMetaverse ItemID = wearableItem.UUID, WearableType = wearableItem.WearableType }; - if (replace || wearableItem.AssetType == AssetType.Bodypart) { + if (replace || wearableItem.AssetType == AssetType.Bodypart) + { // Dump everything from the key Wearables.Remove(wearableItem.WearableType); } @@ -830,7 +830,7 @@ namespace OpenMetaverse /// Wearable to be removed from the outfit public void RemoveFromOutfit(InventoryItem wearableItem) { - List wearableItems = new List {wearableItem}; + List wearableItems = new List { wearableItem }; RemoveFromOutfit(wearableItems); } @@ -915,7 +915,7 @@ namespace OpenMetaverse for (int i = 0; i < WEARABLE_COUNT; i++) { WearableType wearableType = (WearableType)i; - if (WearableTypeToAssetType(wearableType) == AssetType.Bodypart + if (WearableTypeToAssetType(wearableType) == AssetType.Bodypart && !Wearables.ContainsKey(wearableType)) { needsCurrentWearables = true; @@ -998,8 +998,8 @@ namespace OpenMetaverse } /// - /// Calls either or - /// depending on the value of + /// Calls either or + /// depending on the value of /// replaceItems /// /// List of wearable inventory items to add @@ -1060,15 +1060,15 @@ namespace OpenMetaverse { AttachmentPt = replace - ? (byte) attachment.AttachmentPoint - : (byte) (ATTACHMENT_ADD | (byte) attachment.AttachmentPoint), - EveryoneMask = (uint) attachment.Permissions.EveryoneMask, - GroupMask = (uint) attachment.Permissions.GroupMask, - ItemFlags = (uint) attachment.Flags, + ? (byte)attachment.AttachmentPoint + : (byte)(ATTACHMENT_ADD | (byte)attachment.AttachmentPoint), + EveryoneMask = (uint)attachment.Permissions.EveryoneMask, + GroupMask = (uint)attachment.Permissions.GroupMask, + ItemFlags = (uint)attachment.Flags, ItemID = attachment.UUID, Name = Utils.StringToBytes(attachment.Name), Description = Utils.StringToBytes(attachment.Description), - NextOwnerMask = (uint) attachment.Permissions.NextOwnerMask, + NextOwnerMask = (uint)attachment.Permissions.NextOwnerMask, OwnerID = attachment.OwnerID }; @@ -1081,14 +1081,14 @@ namespace OpenMetaverse InventoryObject attachment = (InventoryObject)attachments[i]; attachmentsPacket.ObjectData[i] = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock { - AttachmentPt = replace ? (byte) 0 : ATTACHMENT_ADD, - EveryoneMask = (uint) attachment.Permissions.EveryoneMask, - GroupMask = (uint) attachment.Permissions.GroupMask, - ItemFlags = (uint) attachment.Flags, + AttachmentPt = replace ? (byte)0 : ATTACHMENT_ADD, + EveryoneMask = (uint)attachment.Permissions.EveryoneMask, + GroupMask = (uint)attachment.Permissions.GroupMask, + ItemFlags = (uint)attachment.Flags, ItemID = attachment.UUID, Name = Utils.StringToBytes(attachment.Name), Description = Utils.StringToBytes(attachment.Description), - NextOwnerMask = (uint) attachment.Permissions.NextOwnerMask, + NextOwnerMask = (uint)attachment.Permissions.NextOwnerMask, OwnerID = attachment.OwnerID }; @@ -1365,7 +1365,7 @@ namespace OpenMetaverse WearableType type = (WearableType)i; wearing.WearableData[i] = new AgentIsNowWearingPacket.WearableDataBlock { - WearableType = (byte) i, + WearableType = (byte)i, // This appears to be hacked on SL server side to support multi-layers ItemID = Wearables.ContainsKey(type) ? (Wearables[type].First()?.ItemID ?? UUID.Zero) @@ -1414,9 +1414,12 @@ namespace OpenMetaverse WearableType = wearableItem.WearableType }; // Body cannot be layered. Overwrite when multiple are selected. - if (wearableItem.AssetType == AssetType.Bodypart) { + if (wearableItem.AssetType == AssetType.Bodypart) + { bodyparts[wearableItem.WearableType] = wd; - } else { + } + else + { newWearables.Add(wearableItem.WearableType, wd); } } @@ -1428,7 +1431,7 @@ namespace OpenMetaverse } // heavy handed body part sanity check - if (newWearables.ContainsKey(WearableType.Shape) && + if (newWearables.ContainsKey(WearableType.Shape) && newWearables.ContainsKey(WearableType.Skin) && newWearables.ContainsKey(WearableType.Eyes) && newWearables.ContainsKey(WearableType.Hair)) @@ -1741,7 +1744,7 @@ namespace OpenMetaverse foreach (var wearable in wearables) { if (wearable.Asset == null) continue; - + DecodeWearableParams(wearable, ref Textures); --pendingWearables; } @@ -1750,7 +1753,7 @@ namespace OpenMetaverse return true; Logger.DebugLog("Downloading " + pendingWearables + " wearable assets"); - + Parallel.ForEach(wearables, _parallelOptions, wearable => { @@ -1759,7 +1762,7 @@ namespace OpenMetaverse // Fetch this wearable asset Client.Assets.RequestAsset(wearable.AssetID, wearable.AssetType, true, - delegate(AssetDownload transfer, Asset asset) + delegate (AssetDownload transfer, Asset asset) { if (transfer.Success && asset is AssetWearable assetWearable) { @@ -1862,7 +1865,7 @@ namespace OpenMetaverse AutoResetEvent downloadEvent = new AutoResetEvent(false); Client.Assets.RequestImage(textureId, - delegate(TextureRequestState state, AssetTexture assetTexture) + delegate (TextureRequestState state, AssetTexture assetTexture) { if (state == TextureRequestState.Finished) { @@ -1889,7 +1892,7 @@ namespace OpenMetaverse catch (Exception e) { Logger.Log( - $"Download of texture {textureId} failed with exception {e}", + $"Download of texture {textureId} failed with exception {e}", Helpers.LogLevel.Warning, Client); } } @@ -1911,14 +1914,23 @@ namespace OpenMetaverse { 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)) + { + Logger.DebugLog("texture: " + (AvatarTextureIndex)textureIndex + " skipping not attached"); continue; - + } + Logger.DebugLog("texture: " + (AvatarTextureIndex)textureIndex + " is needed adding to pending Bakes"); pendingBakes.Add((BakeType)bakedIndex); } + else + { + Logger.DebugLog("texture: " + (AvatarTextureIndex)textureIndex + " is ready"); + } } if (pendingBakes.Any()) @@ -1939,7 +1951,7 @@ namespace OpenMetaverse { Textures[i].Texture = null; } - + return success; } @@ -1975,7 +1987,10 @@ namespace OpenMetaverse --retries; } - Textures[(int)BakeTypeToAgentTextureIndex(bakeType)].TextureID = newAssetID; + int bakeIndex = (int)BakeTypeToAgentTextureIndex(bakeType); + Logger.DebugLog("Saving back to " + (AvatarTextureIndex)bakeIndex); + + Textures[bakeIndex].TextureID = newAssetID; if (newAssetID == UUID.Zero) { @@ -1997,7 +2012,7 @@ namespace OpenMetaverse var uploadEvent = new AutoResetEvent(false); Client.Assets.RequestUploadBakedTexture(textureData, - delegate(UUID newAssetID) + delegate (UUID newAssetID) { bakeID = newAssetID; uploadEvent.Set(); @@ -2082,11 +2097,11 @@ namespace OpenMetaverse // TODO: create Current Outfit Folder } - OSDMap request = new OSDMap(1) {["cof_version"] = COF.Version}; + OSDMap request = new OSDMap(1) { ["cof_version"] = COF.Version }; string msg = "Setting server side baking failed"; - OSD res = capsRequest.GetResponse(request, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT * 2); + OSD res = capsRequest.PostRequest(request, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT * 2); if (res is OSDMap result) { @@ -2196,16 +2211,16 @@ namespace OpenMetaverse bool found = false; foreach (var wearableList in Wearables) { - if(wearableList.Value.Any(wearable => wearable.Asset != null && - wearable.Asset.Params - .TryGetValue(vp.ParamID, out paramValue))) + if (wearableList.Value.Any(wearable => wearable.Asset != null && + wearable.Asset.Params + .TryGetValue(vp.ParamID, out paramValue))) { found = true; break; } } - + // Try and find this value in our collection of downloaded wearables @@ -2249,13 +2264,16 @@ namespace OpenMetaverse break; } - if (vpIndex <= nrParams) 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; + if (set.VisualParam[i] != null) + { + MyVisualParameters[i] = set.VisualParam[i].ParamValue; + } } #endregion VisualParam @@ -2267,8 +2285,15 @@ namespace OpenMetaverse for (uint i = 0; i < Textures.Length; i++) { Primitive.TextureEntryFace face = te.CreateFace(i); - face.TextureID = Textures[i].TextureID; - Logger.DebugLog("Sending texture entry for " + (AvatarTextureIndex)i + " to " + Textures[i].TextureID, Client); + if (Textures[i].TextureID != UUID.Zero) + { + face.TextureID = Textures[i].TextureID; + Logger.DebugLog("Sending texture entry for " + (AvatarTextureIndex)i + " to " + Textures[i].TextureID, Client); + } + else + { + Logger.DebugLog("Skipping texture entry for " + (AvatarTextureIndex)i + " its null", Client); + } } set.ObjectData.TextureEntry = te.GetBytes(); @@ -2562,7 +2587,7 @@ namespace OpenMetaverse CancellationTokenSource.Dispose(); CancellationTokenSource = null; } - + if (AppearanceThread != null) { AppearanceThread = null; diff --git a/Assets/Plugins/LibreMetaverse/AssetManager.cs b/Assets/Plugins/LibreMetaverse/AssetManager.cs index d2db58f..c86ac65 100644 --- a/Assets/Plugins/LibreMetaverse/AssetManager.cs +++ b/Assets/Plugins/LibreMetaverse/AssetManager.cs @@ -28,7 +28,6 @@ using System; using System.Collections.Generic; using System.Threading; -using System.Net; using OpenMetaverse.Packets; using OpenMetaverse.Assets; using OpenMetaverse.Http; @@ -163,7 +162,7 @@ namespace OpenMetaverse { public UUID ID; public int Size; - public byte[] AssetData = Utils.EmptyBytes; + public byte[] AssetData; public int Transferred; public bool Success; public AssetType AssetType; @@ -637,16 +636,6 @@ namespace OpenMetaverse catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } return; - } else - { - //not in asset cache and not connected. big oopsie :o - if (Client.Network.Connected == false) - { - - Logger.Log("Assetmanager : Cache miss and DISCONNECTED!", Helpers.LogLevel.Error); - return; - } - } // If ViewerAsset capability exists, use that, if not, fallback to UDP (which is obsoleted on Second Life.) @@ -859,8 +848,6 @@ namespace OpenMetaverse /// /// Use UUID.Zero if you do not have the /// asset ID but have all the necessary permissions - /// - /// Whether to prioritize this asset download or not /// /// private void RequestInventoryAssetHTTP(UUID assetID, AssetDownload transfer, AssetReceivedCallback callback) @@ -1143,7 +1130,7 @@ namespace OpenMetaverse 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); + upload.PostRequestAsync(textureData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); return; } } @@ -1152,7 +1139,7 @@ namespace OpenMetaverse 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); + request.PostRequestAsync(new OSDMap(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { diff --git a/Assets/Plugins/LibreMetaverse/Assets/Archiving/ArchiveConstants.cs b/Assets/Plugins/LibreMetaverse/Assets/Archiving/ArchiveConstants.cs index e8ff762..b550d8a 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/Archiving/ArchiveConstants.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/Archiving/ArchiveConstants.cs @@ -25,7 +25,6 @@ */ using System.Collections.Generic; -using OpenMetaverse; namespace OpenMetaverse.Assets { diff --git a/Assets/Plugins/LibreMetaverse/Assets/Archiving/AssetsArchiver.cs b/Assets/Plugins/LibreMetaverse/Assets/Archiving/AssetsArchiver.cs index d7b458c..1297956 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/Archiving/AssetsArchiver.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/Archiving/AssetsArchiver.cs @@ -27,9 +27,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Reflection; using System.Xml; -using OpenMetaverse; namespace OpenMetaverse.Assets { diff --git a/Assets/Plugins/LibreMetaverse/Assets/Archiving/OarFile.cs b/Assets/Plugins/LibreMetaverse/Assets/Archiving/OarFile.cs index 4bfa4ab..318695d 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/Archiving/OarFile.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/Archiving/OarFile.cs @@ -28,10 +28,8 @@ 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 { @@ -435,7 +433,10 @@ namespace OpenMetaverse.Assets xtw.WriteElementString("SnapshotID", parcel.SnapshotID.ToString()); xtw.WriteElementString("UserLocation", parcel.UserLocation.ToString()); xtw.WriteElementString("UserLookAt", parcel.UserLookAt.ToString()); - xtw.WriteElementString("Dwell", "0"); + xtw.WriteElementString("Dwell", parcel.Dwell.ToString()); + xtw.WriteElementString("SeeAVs", parcel.SeeAVs.ToString()); + xtw.WriteElementString("AnyAVSounds", parcel.AnyAVSounds.ToString()); + xtw.WriteElementString("GroupAVSounds", parcel.GroupAVSounds.ToString()); xtw.WriteElementString("OtherCleanTime", Convert.ToString(parcel.OtherCleanTime)); xtw.WriteEndElement(); @@ -534,9 +535,8 @@ namespace OpenMetaverse.Assets if (prim.Textures.FaceTextures != null) { - for (int i = 0; i < prim.Textures.FaceTextures.Length; i++) + foreach (var face in prim.Textures.FaceTextures) { - Primitive.TextureEntryFace face = prim.Textures.FaceTextures[i]; if (face != null) textureList[face.TextureID] = face.TextureID; } diff --git a/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveReader.cs b/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveReader.cs index b62d6cf..60acc68 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveReader.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveReader.cs @@ -26,7 +26,6 @@ using System; using System.IO; -using System.Reflection; using System.Text; namespace OpenMetaverse.Assets diff --git a/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveWriter.cs b/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveWriter.cs index 01c398b..4d5505b 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveWriter.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/Archiving/TarArchiveWriter.cs @@ -25,7 +25,6 @@ */ using System; -using System.Collections.Generic; using System.IO; using System.Text; diff --git a/Assets/Plugins/LibreMetaverse/Assets/Asset.cs b/Assets/Plugins/LibreMetaverse/Assets/Asset.cs index 9e13f74..ec72fc6 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/Asset.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/Asset.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; - namespace OpenMetaverse.Assets { /// diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetAnimation.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetAnimation.cs index d216151..e7d09d8 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetAnimation.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetAnimation.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; - namespace OpenMetaverse.Assets { /// diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetBodypart.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetBodypart.cs index a4bb437..29aafd5 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetBodypart.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetBodypart.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; - namespace OpenMetaverse.Assets { /// diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetCallingCard.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetCallingCard.cs index ef1ca4d..f5aa73b 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetCallingCard.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetCallingCard.cs @@ -25,7 +25,6 @@ */ using System; -using OpenMetaverse; namespace OpenMetaverse.Assets { diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetClothing.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetClothing.cs index 80c6dd7..b3d485f 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetClothing.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetClothing.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; - namespace OpenMetaverse.Assets { /// diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetGesture.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetGesture.cs index bc1de30..4026298 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetGesture.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetGesture.cs @@ -27,8 +27,6 @@ using System; using System.Collections.Generic; using System.Text; -using System.Text.RegularExpressions; -using OpenMetaverse; namespace OpenMetaverse.Assets { diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetLandmark.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetLandmark.cs index 67813af..42e0906 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetLandmark.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetLandmark.cs @@ -25,7 +25,6 @@ */ using System; -using OpenMetaverse; namespace OpenMetaverse.Assets { diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetMutable.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetMutable.cs index 0933a80..1337ecb 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetMutable.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetMutable.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; - namespace OpenMetaverse.Assets { /// diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetNotecard.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetNotecard.cs index a53e0ee..f54e5cf 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetNotecard.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetNotecard.cs @@ -28,7 +28,6 @@ using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; -using OpenMetaverse; namespace OpenMetaverse.Assets { diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetPrim.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetPrim.cs index 6ce2aa3..8805207 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetPrim.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetPrim.cs @@ -28,7 +28,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Xml; -using OpenMetaverse; using OpenMetaverse.StructuredData; namespace OpenMetaverse.Assets @@ -782,8 +781,9 @@ namespace OpenMetaverse.Assets if (Items != null) { OSDArray array = new OSDArray(Items.Length); - for (int i = 0; i < Items.Length; i++) - array.Add(Items[i].Serialize()); + foreach (var i in Items) + array.Add(i.Serialize()); + map["items"] = array; } diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptBinary.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptBinary.cs index 59ac8b5..07ce864 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptBinary.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptBinary.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; - namespace OpenMetaverse.Assets { /// diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptText.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptText.cs index 565ad5d..6683712 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptText.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetScriptText.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; - namespace OpenMetaverse.Assets { /// diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetSound.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetSound.cs index 5a17ad9..ba88f42 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetSound.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetSound.cs @@ -24,8 +24,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +using OggVorbisEncoder; using System; -using OpenMetaverse; +using System.IO; namespace OpenMetaverse.Assets { @@ -46,17 +47,162 @@ namespace OpenMetaverse.Assets public AssetSound(UUID assetID, byte[] assetData) : base(assetID, assetData) { + if ((assetID != UUID.Zero) && (assetData.Length > 0)) + { + encodedAudio = true; + } + } + + protected bool encodedAudio = false; + + /// + /// Converts a byte data for a wave PCM file @ 44100 to a OGG encoding + /// + public override void Encode() + { + if (encodedAudio == false) + { + encodedAudio = true; + AssetData = ConvertRawPCMFile(44100, 1, AssetData, PcmSample.SixteenBit, 44100, 2); + } } /// - /// TODO: Encodes a sound file - /// - public override void Encode() { } - - /// - /// TODO: Decode a sound file + /// its already ogg just play it or convert it yourself /// /// true public override bool Decode() { return true; } + + + private static byte[] ConvertRawPCMFile(int outputSampleRate, int outputChannels, byte[] pcmSamples, PcmSample pcmSampleSize, int pcmSampleRate, int pcmChannels) + { + int numPcmSamples = (pcmSamples.Length / (int)pcmSampleSize / pcmChannels); + float pcmDuraton = numPcmSamples / (float)pcmSampleRate; + + int numOutputSamples = (int)(pcmDuraton * outputSampleRate); + //Ensure that samble buffer is aligned to write chunk size + numOutputSamples = (numOutputSamples / WriteBufferSize) * WriteBufferSize; + + float[][] outSamples = new float[outputChannels][]; + + for (int ch = 0; ch < outputChannels; ch++) + { + outSamples[ch] = new float[numOutputSamples]; + } + + for (int sampleNumber = 0; sampleNumber < numOutputSamples; sampleNumber++) + { + float rawSample = 0.0f; + + for (int ch = 0; ch < outputChannels; ch++) + { + int sampleIndex = (sampleNumber * pcmChannels) * (int)pcmSampleSize; + + if (ch < pcmChannels) sampleIndex += (ch * (int)pcmSampleSize); + + switch (pcmSampleSize) + { + case PcmSample.EightBit: + rawSample = ByteToSample(pcmSamples[sampleIndex]); + break; + case PcmSample.SixteenBit: + rawSample = ShortToSample((short)(pcmSamples[sampleIndex + 1] << 8 | pcmSamples[sampleIndex])); + break; + } + + outSamples[ch][sampleNumber] = rawSample; + } + } + + return GenerateFile(outSamples, outputSampleRate, outputChannels); + } + + private static float ByteToSample(short pcmValue) + { + return pcmValue / 128f; + } + + private static float ShortToSample(short pcmValue) + { + return pcmValue / 32768f; + } + + private static readonly int WriteBufferSize = 512; + private static byte[] GenerateFile(float[][] floatSamples, int sampleRate, int channels) + { + MemoryStream outputData = new MemoryStream(); + + // Stores all the static vorbis bitstream settings + var info = VorbisInfo.InitVariableBitRate(channels, sampleRate, 0.5f); + + // set up our packet->stream encoder + var serial = new Random().Next(); + var oggStream = new OggStream(serial); + + // ========================================================= + // HEADER + // ========================================================= + // Vorbis streams begin with three headers; the initial header (with + // most of the codec setup parameters) which is mandated by the Ogg + // bitstream spec. The second header holds any comment fields. The + // third header holds the bitstream codebook. + + var comments = new Comments(); + comments.AddTag("ARTIST", "TEST"); + + var infoPacket = HeaderPacketBuilder.BuildInfoPacket(info); + var commentsPacket = HeaderPacketBuilder.BuildCommentsPacket(comments); + var booksPacket = HeaderPacketBuilder.BuildBooksPacket(info); + + oggStream.PacketIn(infoPacket); + oggStream.PacketIn(commentsPacket); + oggStream.PacketIn(booksPacket); + + // Flush to force audio data onto its own page per the spec + FlushPages(oggStream, outputData, true); + + // ========================================================= + // BODY (Audio Data) + // ========================================================= + var processingState = ProcessingState.Create(info); + + for (int readIndex = 0; readIndex <= floatSamples[0].Length; readIndex += WriteBufferSize) + { + if (readIndex == floatSamples[0].Length) + { + processingState.WriteEndOfStream(); + } + else + { + processingState.WriteData(floatSamples, WriteBufferSize, readIndex); + } + + while (!oggStream.Finished && processingState.PacketOut(out OggPacket packet)) + { + oggStream.PacketIn(packet); + + FlushPages(oggStream, outputData, false); + } + } + + FlushPages(oggStream, outputData, true); + + return outputData.ToArray(); + } + + private static void FlushPages(OggStream oggStream, Stream output, bool force) + { + while (oggStream.PageOut(out OggPage page, force)) + { + output.Write(page.Header, 0, page.Header.Length); + output.Write(page.Body, 0, page.Body.Length); + } + } + + enum PcmSample : int + { + EightBit = 1, + SixteenBit = 2 + } } } diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs index 8c1f233..41ca8cd 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -24,8 +25,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using OpenMetaverse; using OpenMetaverse.Imaging; namespace OpenMetaverse.Assets @@ -41,9 +40,6 @@ namespace OpenMetaverse.Assets /// A object containing image data public ManagedImage Image; - /// - public OpenJPEG.J2KLayerInfo[] LayerInfo; - /// public int Components; @@ -81,7 +77,10 @@ namespace OpenMetaverse.Assets /// public override void Encode() { - AssetData = OpenJPEG.Encode(Image); + using (var writer = new OpenJpegDotNet.IO.Writer(Image.ExportTex2D())) + { + AssetData = writer.Encode(); + } } /// @@ -91,36 +90,27 @@ namespace OpenMetaverse.Assets /// True if the decoding was successful, otherwise false public override bool Decode() { - if (AssetData != null && AssetData.Length > 0) + if (AssetData == null || AssetData.Length <= 0) { return false; } + + this.Components = 0; + + using (var reader = new OpenJpegDotNet.IO.Reader(AssetData)) { - 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; - } + // *hack: decode from ManagedImage directly or better yet, get rid of ManagedImage entirely! + if (!reader.ReadHeader()) { return false; } + Image = new ManagedImage(reader.DecodeToBitmap()); } - return false; - } + 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; - /// - /// 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); + return true; } } } diff --git a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetWearable.cs b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetWearable.cs index c1f3411..67a8c6e 100644 --- a/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetWearable.cs +++ b/Assets/Plugins/LibreMetaverse/Assets/AssetTypes/AssetWearable.cs @@ -27,7 +27,6 @@ using System; using System.Collections.Generic; using System.Text; -using OpenMetaverse; namespace OpenMetaverse.Assets { diff --git a/Assets/Plugins/LibreMetaverse/AvatarManager.cs b/Assets/Plugins/LibreMetaverse/AvatarManager.cs index 2d59de4..c287647 100644 --- a/Assets/Plugins/LibreMetaverse/AvatarManager.cs +++ b/Assets/Plugins/LibreMetaverse/AvatarManager.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -279,6 +280,29 @@ namespace OpenMetaverse remove { lock (m_AvatarInterestsReplyLock) { m_AvatarInterestsReply -= value; } } } + /// The event subscribers, null of no subscribers + private EventHandler m_AvatarNotesReply; + + ///Raises the AvatarNotesReply Event + /// A AvatarNotesReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnAvatarNotesReply(AvatarNotesReplyEventArgs e) + { + EventHandler handler = m_AvatarNotesReply; + handler?.Invoke(this, e); + } + + /// Thread sync lock object + private readonly object m_AvatarNotesReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// the private notes listed in an agents profile + public event EventHandler AvatarNotesReply + { + add { lock (m_AvatarNotesReplyLock) { m_AvatarNotesReply += value; } } + remove { lock (m_AvatarNotesReplyLock) { m_AvatarNotesReply -= value; } } + } + /// The event subscribers, null of no subscribers private EventHandler m_AvatarPropertiesReply; @@ -561,6 +585,7 @@ namespace OpenMetaverse Client.Network.RegisterCallback(PacketType.AvatarPropertiesReply, AvatarPropertiesHandler); // Client.Network.RegisterCallback(PacketType.AvatarStatisticsReply, AvatarStatisticsHandler); Client.Network.RegisterCallback(PacketType.AvatarInterestsReply, AvatarInterestsHandler); + Client.Network.RegisterCallback(PacketType.AvatarNotesReply, AvatarNotesHandler); // Avatar group callback Client.Network.RegisterCallback(PacketType.AvatarGroupsReply, AvatarGroupsReplyHandler); @@ -709,7 +734,7 @@ namespace OpenMetaverse callback(false, null, null); } }; - cap.BeginGetResponse(null, string.Empty, Client.Settings.CAPS_TIMEOUT); + cap.GetRequestAsync(Client.Settings.CAPS_TIMEOUT); } /// @@ -752,6 +777,36 @@ namespace OpenMetaverse Client.Network.SendPacket(aprp); } + /// + /// Request avatar notes from simulator + /// + /// Target agent UUID + public void RequestAvatarNotes(UUID avatarid) + { + GenericMessagePacket gmp = new GenericMessagePacket + { + AgentData = + { + AgentID = Client.Self.AgentID, + SessionID = Client.Self.SessionID, + TransactionID = UUID.Zero + }, + MethodData = + { + Method = Utils.StringToBytes("avatarnotesrequest"), + Invoice = UUID.Zero + }, + ParamList = new GenericMessagePacket.ParamListBlock[1] + }; + + gmp.ParamList[0] = + new GenericMessagePacket.ParamListBlock + { + Parameter = Utils.StringToBytes(avatarid.ToString()) + }; + Client.Network.SendPacket(gmp); + } + /// /// Start a request for Avatar Picks /// @@ -991,21 +1046,27 @@ namespace OpenMetaverse BornOn = Utils.BytesToString(reply.PropertiesData.BornOn) }; - //properties.CharterMember = Utils.BytesToString(reply.PropertiesData.CharterMember); - uint charter = Utils.BytesToUInt(reply.PropertiesData.CharterMember); - if (charter == 0) + if (reply.PropertiesData.CharterMember.Length == 1) { - properties.CharterMember = "Resident"; + uint charter = Utils.BytesToUInt(reply.PropertiesData.CharterMember); + if (charter == 0) + { + properties.CharterMember = "Resident"; + } + else if (charter == 1) + { + properties.CharterMember = "Trial"; + } + else if (charter == 2) + { + properties.CharterMember = "Charter"; + } + else if (charter == 3) + { + properties.CharterMember = "Employee"; + } } - else if (charter == 2) - { - properties.CharterMember = "Charter"; - } - else if (charter == 3) - { - properties.CharterMember = "Linden"; - } - else + else if (reply.PropertiesData.CharterMember.Length > 1) { properties.CharterMember = Utils.BytesToString(reply.PropertiesData.CharterMember); } @@ -1038,6 +1099,18 @@ namespace OpenMetaverse } } + protected void AvatarNotesHandler(object sender, PacketReceivedEventArgs e) + { + if (m_AvatarNotesReply != null) + { + Packet packet = e.Packet; + AvatarNotesReplyPacket anrp = (AvatarNotesReplyPacket)packet; + string notes = Utils.BytesToString(anrp.Data.Notes); + + OnAvatarNotesReply(new AvatarNotesReplyEventArgs(anrp.Data.TargetID, notes)); + } + } + /// /// EQ Message fired when someone nearby changes their display name /// @@ -1492,6 +1565,22 @@ namespace OpenMetaverse } } + /// Represents the private notes from the profile of an agent + public class AvatarNotesReplyEventArgs : EventArgs + { + /// Get the ID of the agent + public UUID AvatarID { get; } + + /// Get the interests of the agent + public string Notes { get; } + + public AvatarNotesReplyEventArgs(UUID avatarID, string notes) + { + this.AvatarID = avatarID; + this.Notes = notes; + } + } + /// The properties of an agent public class AvatarPropertiesReplyEventArgs : EventArgs { diff --git a/Assets/Plugins/LibreMetaverse/BitPack.cs b/Assets/Plugins/LibreMetaverse/BitPack.cs index 8134a36..65cb070 100644 --- a/Assets/Plugins/LibreMetaverse/BitPack.cs +++ b/Assets/Plugins/LibreMetaverse/BitPack.cs @@ -43,14 +43,14 @@ namespace OpenMetaverse { get { - if (bytePos != 0 && bitPos == 0) + if (bytePos != 0 && BitPos == 0) return bytePos - 1; return bytePos; } } /// - public int BitPos => bitPos; + public int BitPos { get; private set; } private const int MAX_BITS = 8; @@ -58,8 +58,7 @@ namespace OpenMetaverse private static readonly byte[] Off = { 0 }; private int bytePos; - private int bitPos; - + /// /// Default constructor, initialize the bit packer / bit unpacker /// with a byte array and starting position @@ -301,7 +300,7 @@ namespace OpenMetaverse public string UnpackString(int size) { - if (bitPos != 0 || bytePos + size > Data.Length) throw new IndexOutOfRangeException(); + if (BitPos != 0 || bytePos + size > Data.Length) throw new IndexOutOfRangeException(); string str = System.Text.Encoding.UTF8.GetString(Data, bytePos, size); bytePos += size; @@ -310,7 +309,7 @@ namespace OpenMetaverse public UUID UnpackUUID() { - if (bitPos != 0) throw new IndexOutOfRangeException(); + if (BitPos != 0) throw new IndexOutOfRangeException(); UUID val = new UUID(Data, bytePos); bytePos += 16; @@ -338,7 +337,7 @@ namespace OpenMetaverse while (count > 0) { - byte curBit = (byte)(0x80 >> bitPos); + byte curBit = (byte)(0x80 >> BitPos); if ((data[curBytePos] & (0x01 << (count - 1))) != 0) Data[bytePos] |= curBit; @@ -346,12 +345,12 @@ namespace OpenMetaverse Data[bytePos] &= (byte)~curBit; --count; - ++bitPos; + ++BitPos; ++curBitPos; - if (bitPos >= MAX_BITS) + if (BitPos >= MAX_BITS) { - bitPos = 0; + BitPos = 0; ++bytePos; } if (curBitPos >= MAX_BITS) @@ -389,15 +388,15 @@ namespace OpenMetaverse output[curBytePos] <<= 1; // Grab one bit - if ((Data[bytePos] & (0x80 >> bitPos++)) != 0) + if ((Data[bytePos] & (0x80 >> BitPos++)) != 0) ++output[curBytePos]; --count; ++curBitPos; - if (bitPos >= MAX_BITS) + if (BitPos >= MAX_BITS) { - bitPos = 0; + BitPos = 0; ++bytePos; } if (curBitPos >= MAX_BITS) diff --git a/Assets/Plugins/LibreMetaverse/Capabilities/CapsBase.cs b/Assets/Plugins/LibreMetaverse/Capabilities/CapsBase.cs index c297169..efb3ae0 100644 --- a/Assets/Plugins/LibreMetaverse/Capabilities/CapsBase.cs +++ b/Assets/Plugins/LibreMetaverse/Capabilities/CapsBase.cs @@ -1,6 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co - * Copyright (c) 2019, Cinderblocks Design Co. + * Copyright (c) 2019-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -30,12 +30,19 @@ using System.Net; using System.IO; using System.Threading; using System.Security.Cryptography.X509Certificates; -using UnityEngine; namespace OpenMetaverse.Http { public static class CapsBase { + #region http methods + public const string GET = "GET"; + public const string POST = "POST"; + public const string PUT = "PUT"; + public const string DELETE = "DELETE"; + public const string PATCH = "PATCH"; // rfc 5789 + #endregion http methods + 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); @@ -66,7 +73,17 @@ namespace OpenMetaverse.Http } } - public static HttpWebRequest UploadDataAsync(Uri address, X509Certificate2 clientCert, string contentType, byte[] data, + public static HttpWebRequest GetStringAsync(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 HttpWebRequest PostDataAsync(Uri address, X509Certificate2 clientCert, string contentType, byte[] data, int millisecondsTimeout, OpenWriteEventHandler openWriteCallback, DownloadProgressEventHandler downloadProgressCallback, RequestCompletedEventHandler completedCallback) { @@ -75,7 +92,29 @@ namespace OpenMetaverse.Http request.ContentLength = data.Length; if (!string.IsNullOrEmpty(contentType)) request.ContentType = contentType; - request.Method = "POST"; + request.Method = POST; + + // Create an object to hold all of the state for this request + var 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 PutDataAsync(Uri address, X509Certificate2 clientCert, string contentType, byte[] data, + int millisecondsTimeout, OpenWriteEventHandler openWriteCallback, DownloadProgressEventHandler downloadProgressCallback, + RequestCompletedEventHandler completedCallback) + { + // Create the request + var request = SetupRequest(address, clientCert); + request.ContentLength = data.Length; + if (!string.IsNullOrEmpty(contentType)) + request.ContentType = contentType; + request.Method = PUT; // Create an object to hold all of the state for this request var state = new RequestState(request, data, millisecondsTimeout, openWriteCallback, @@ -89,13 +128,49 @@ namespace OpenMetaverse.Http return request; } - public static HttpWebRequest DownloadStringAsync(Uri address, X509Certificate2 clientCert, int millisecondsTimeout, - DownloadProgressEventHandler downloadProgressCallback, RequestCompletedEventHandler completedCallback) + public static HttpWebRequest DeleteDataAsync(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.Method = "GET"; - DownloadDataAsync(request, millisecondsTimeout, downloadProgressCallback, completedCallback); + var request = SetupRequest(address, clientCert); + request.ContentLength = data.Length; + if (!string.IsNullOrEmpty(contentType)) + request.ContentType = contentType; + request.Method = DELETE; + + // Create an object to hold all of the state for this request + var 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 PatchDataAsync(Uri address, X509Certificate2 clientCert, string contentType, byte[] data, + int millisecondsTimeout, OpenWriteEventHandler openWriteCallback, DownloadProgressEventHandler downloadProgressCallback, + RequestCompletedEventHandler completedCallback) + { + // Create the request + var request = SetupRequest(address, clientCert); + request.ContentLength = data.Length; + if (!string.IsNullOrEmpty(contentType)) + request.ContentType = contentType; + request.Method = PATCH; + + // Create an object to hold all of the state for this request + var 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; } @@ -108,7 +183,6 @@ namespace OpenMetaverse.Http // 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); } @@ -135,8 +209,8 @@ namespace OpenMetaverse.Http { Logger.Log( string.Format( - "In CapsBase.SetupRequest() setting conn limit for {0}:{1} to {2}", - address.Host, address.Port, Settings.MAX_HTTP_CONNECTIONS), + "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; } @@ -205,7 +279,7 @@ namespace OpenMetaverse.Http int totalBytesRead = 0; int totalSize = nolength ? 0 : size; - while ((bytesRead = responseStream.Read(buffer, offset, size)) != 0) + while (responseStream != null && (bytesRead = responseStream.Read(buffer, offset, size)) != 0) { totalBytesRead += bytesRead; diff --git a/Assets/Plugins/LibreMetaverse/Capabilities/CapsClient.cs b/Assets/Plugins/LibreMetaverse/Capabilities/CapsClient.cs index d427e38..faa3c96 100644 --- a/Assets/Plugins/LibreMetaverse/Capabilities/CapsClient.cs +++ b/Assets/Plugins/LibreMetaverse/Capabilities/CapsClient.cs @@ -52,16 +52,33 @@ namespace OpenMetaverse.Http protected OSD _Response; protected AutoResetEvent _ResponseEvent = new AutoResetEvent(false); + #region Constructors + + /// + /// CapsClient Ctor + /// + /// for simulator capability public CapsClient(Uri capability) : this(capability, null, null) { } + /// + /// CapsClient Ctor with name + /// + /// for simulator capability + /// Simulator capability name public CapsClient(Uri capability, string cap_name) : this(capability, cap_name, null) { } + /// + /// CapsClient Ctor with name and certificate + /// + /// for simulator capability + /// Simulator capability name + /// client certificate public CapsClient(Uri capability, string cap_name, X509Certificate2 clientCert) { _Address = capability; @@ -69,37 +86,48 @@ namespace OpenMetaverse.Http _ClientCert = clientCert; } - public void BeginGetResponse(int millisecondsTimeout) - { - BeginGetResponse(null, null, millisecondsTimeout); - } + #endregion Constructors - public void BeginGetResponse(OSD data, OSDFormat format, int millisecondsTimeout) - { - byte[] postData; - string contentType; + #region GET requests - switch (format) + public void GetRequestAsync(int msTimeout) + { + if (_Request != null) { - 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; + _Request.Abort(); + _Request = null; } - - BeginGetResponse(postData, contentType, millisecondsTimeout); + // GET + Logger.DebugLog("[CapsClient] GET " + _Address); + _Request = CapsBase.GetStringAsync(_Address, _ClientCert, msTimeout, DownloadProgressHandler, + RequestCompletedHandler); } - public void BeginGetResponse(byte[] postData, string contentType, int millisecondsTimeout) + public OSD GetRequest(int msTimeout) + { + GetRequestAsync(msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); + return _Response; + } + + #endregion GET requests + + #region POST requests + + public void PostRequestAsync(OSD data, OSDFormat format, int msTimeout) + { + serializeData(data, format, out byte[] serializedData, out string contentType); + PostRequestAsync(serializedData, contentType, msTimeout); + } + + public OSD PostRequest(OSD data, OSDFormat format, int msTimeout) + { + PostRequestAsync(data, format, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); + return _Response; + } + + public void PostRequestAsync(byte[] postData, string contentType, int msTimeout) { _PostData = postData; _ContentType = contentType; @@ -109,44 +137,143 @@ namespace OpenMetaverse.Http _Request.Abort(); _Request = null; } + // POST + Logger.DebugLog("[CapsClient] POST (" + postData.Length + " bytes) " + _Address); - if (postData == null) + _Request = CapsBase.PostDataAsync(_Address, _ClientCert, contentType, postData, msTimeout, + null, DownloadProgressHandler, RequestCompletedHandler); + } + + public OSD PostRequest(byte[] postData, string contentType, int msTimeout) + { + PostRequestAsync(postData, contentType, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); + return _Response; + } + + #endregion POST requests + + #region PUT requests + + public void PutRequestAsync(OSD data, OSDFormat format, int msTimeout) + { + serializeData(data, format, out byte[] serializedData, out string contentType); + PutRequestAsync(serializedData, contentType, msTimeout); + } + + public OSD PutRequest(OSD data, OSDFormat format, int msTimeout) + { + PutRequestAsync(data, format, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); + return _Response; + } + + public void PutRequestAsync(byte[] postData, string contentType, int msTimeout) + { + _PostData = postData; + _ContentType = contentType; + + if (_Request != null) { - // GET - Logger.DebugLog("[CapsClient] GET " + _Address); - _Request = CapsBase.DownloadStringAsync(_Address, _ClientCert, millisecondsTimeout, DownloadProgressHandler, - RequestCompletedHandler); + _Request.Abort(); + _Request = null; } - else + // PUT + Logger.DebugLog("[CapsClient] PUT " + _Address); + + _Request = CapsBase.PutDataAsync(_Address, _ClientCert, contentType, postData, msTimeout, + null, DownloadProgressHandler, RequestCompletedHandler); + } + + public OSD PutRequest(byte[] postData, string contentType, int msTimeout) + { + PutRequestAsync(postData, contentType, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); + return _Response; + } + + #endregion PUT requests + + #region PATCH requests + + public void PatchRequestAsync(OSD data, OSDFormat format, int msTimeout) + { + serializeData(data, format, out byte[] serializedData, out string contentType); + PatchRequestAsync(serializedData, contentType, msTimeout); + } + + public OSD PatchRequest(OSD data, OSDFormat format, int msTimeout) + { + PatchRequestAsync(data, format, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); + return _Response; + } + + public void PatchRequestAsync(byte[] postData, string contentType, int msTimeout) + { + _PostData = postData; + _ContentType = contentType; + + if (_Request != null) { - // POST - Logger.DebugLog("[CapsClient] POST (" + postData.Length + " bytes) " + _Address); - _Request = CapsBase.UploadDataAsync(_Address, _ClientCert, contentType, postData, millisecondsTimeout, null, - DownloadProgressHandler, RequestCompletedHandler); + _Request.Abort(); + _Request = null; } + // PATCH + Logger.DebugLog("[CapsClient] PATCH " + _Address); + _Request = CapsBase.PatchDataAsync(_Address, _ClientCert, contentType, postData, msTimeout, + null, DownloadProgressHandler, RequestCompletedHandler); } - public OSD GetResponse(int millisecondsTimeout) + public OSD PatchRequest(byte[] postData, string contentType, int msTimeout) { - BeginGetResponse(millisecondsTimeout); - _ResponseEvent.WaitOne(millisecondsTimeout, false); + PatchRequestAsync(postData, contentType, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); return _Response; } - public OSD GetResponse(OSD data, OSDFormat format, int millisecondsTimeout) + #endregion PATCH requests + + #region DELETE requests + + public void DeleteRequestAsync(OSD data, OSDFormat format, int msTimeout) { - BeginGetResponse(data, format, millisecondsTimeout); - _ResponseEvent.WaitOne(millisecondsTimeout, false); + serializeData(data, format, out byte[] serializedData, out string contentType); + DeleteRequestAsync(serializedData, contentType, msTimeout); + } + + public OSD DeleteRequest(OSD data, OSDFormat format, int msTimeout) + { + DeleteRequestAsync(data, format, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); return _Response; } - public OSD GetResponse(byte[] postData, string contentType, int millisecondsTimeout) + public void DeleteRequestAsync(byte[] postData, string contentType, int msTimeout) { - BeginGetResponse(postData, contentType, millisecondsTimeout); - _ResponseEvent.WaitOne(millisecondsTimeout, false); + _PostData = postData; + _ContentType = contentType; + + if (_Request != null) + { + _Request.Abort(); + _Request = null; + } + // DELETE + Logger.DebugLog("[CapsClient] DELETE " + _Address); + _Request = CapsBase.DeleteDataAsync(_Address, _ClientCert, contentType, postData, msTimeout, + null, DownloadProgressHandler, RequestCompletedHandler); + } + + public OSD DeleteRequest(byte[] postData, string contentType, int msTimeout) + { + PatchRequestAsync(postData, contentType, msTimeout); + _ResponseEvent.WaitOne(msTimeout, false); return _Response; } + #endregion DELETE requests + public void Cancel() { _Request?.Abort(); @@ -181,6 +308,33 @@ namespace OpenMetaverse.Http FireCompleteCallback(result, error); } + /// + /// Serializes OSD data for http request + /// + /// formatted data for input + /// Format to serialize data to + /// Output serialized data as byte array + /// content-type string of serialized data + private void serializeData(OSD data, OSDFormat format, out byte[] serializedData, out string contentType) + { + switch (format) + { + case OSDFormat.Xml: + serializedData = OSDParser.SerializeLLSDXmlBytes(data); + contentType = "application/llsd+xml"; + break; + case OSDFormat.Binary: + serializedData = OSDParser.SerializeLLSDBinary(data); + contentType = "application/llsd+binary"; + break; + case OSDFormat.Json: + default: + serializedData = System.Text.Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(data)); + contentType = "application/llsd+json"; + break; + } + } + private void FireCompleteCallback(OSD result, Exception error) { CompleteCallback callback = OnComplete; diff --git a/Assets/Plugins/LibreMetaverse/Capabilities/EventQueueClient.cs b/Assets/Plugins/LibreMetaverse/Capabilities/EventQueueClient.cs index 99e1fb8..154511f 100644 --- a/Assets/Plugins/LibreMetaverse/Capabilities/EventQueueClient.cs +++ b/Assets/Plugins/LibreMetaverse/Capabilities/EventQueueClient.cs @@ -73,7 +73,7 @@ namespace OpenMetaverse.Http byte[] postData = OSDParser.SerializeLLSDXmlBytes(request); - _Request = CapsBase.UploadDataAsync(_Address, null, REQUEST_CONTENT_TYPE, postData, REQUEST_TIMEOUT, OpenWriteHandler, null, RequestCompletedHandler); + _Request = CapsBase.PostDataAsync(_Address, null, REQUEST_CONTENT_TYPE, postData, REQUEST_TIMEOUT, OpenWriteHandler, null, RequestCompletedHandler); } public void Stop(bool immediate) @@ -211,7 +211,7 @@ namespace OpenMetaverse.Http // Resume the connection. The event handler for the connection opening // just sets class _Request variable to the current HttpWebRequest - CapsBase.UploadDataAsync(_Address, null, REQUEST_CONTENT_TYPE, postData, REQUEST_TIMEOUT, + CapsBase.PostDataAsync(_Address, null, REQUEST_CONTENT_TYPE, postData, REQUEST_TIMEOUT, delegate(HttpWebRequest newRequest) { _Request = newRequest; }, null, RequestCompletedHandler); // If the event queue is dead at this point, turn it off since diff --git a/Assets/Plugins/LibreMetaverse/Caps.cs b/Assets/Plugins/LibreMetaverse/Caps.cs index def9b7c..146fa98 100644 --- a/Assets/Plugins/LibreMetaverse/Caps.cs +++ b/Assets/Plugins/LibreMetaverse/Caps.cs @@ -172,9 +172,7 @@ namespace OpenMetaverse "EnvironmentSettings", "EstateChangeInfo", "EventQueueGet", - "FacebookConnect", - "FlickrConnect", - "TwitterConnect", + "ExtEnvironment", "FetchLib2", "FetchLibDescendents2", "FetchInventory2", @@ -193,6 +191,7 @@ namespace OpenMetaverse "IsExperienceAdmin", "IsExperienceContributor", "RegionExperiences", + "ExperienceQuery", "GetMesh", "GetMesh2", "GetMetadata", @@ -221,7 +220,6 @@ namespace OpenMetaverse "RemoteParcelRequest", "RenderMaterials", "RequestTextureDownload", - "RequiredVoiceVersion", "ResourceCostSelected", "RetrieveNavMeshSrc", "SearchStatRequest", @@ -249,6 +247,7 @@ namespace OpenMetaverse "UploadBakedTexture", "UserInfo", "ViewerAsset", + "ViewerBenefits", "ViewerMetrics", "ViewerStartAuction", "ViewerStats", @@ -259,7 +258,7 @@ namespace OpenMetaverse _SeedRequest = new CapsClient(new Uri(_SeedCapsURI), "SeedCaps"); _SeedRequest.OnComplete += SeedRequestCompleteHandler; - _SeedRequest.BeginGetResponse(req, OSDFormat.Xml, Simulator.Client.Settings.CAPS_TIMEOUT); + _SeedRequest.PostRequestAsync(req, OSDFormat.Xml, Simulator.Client.Settings.CAPS_TIMEOUT); } private void SeedRequestCompleteHandler(CapsClient client, OSD result, Exception error) diff --git a/Assets/Plugins/LibreMetaverse/DirectoryManager.cs b/Assets/Plugins/LibreMetaverse/DirectoryManager.cs index 01798d9..fdc964d 100644 --- a/Assets/Plugins/LibreMetaverse/DirectoryManager.cs +++ b/Assets/Plugins/LibreMetaverse/DirectoryManager.cs @@ -355,7 +355,7 @@ namespace OpenMetaverse } /// - /// Parcel information returned from a request + /// 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 @@ -514,8 +514,7 @@ namespace OpenMetaverse protected virtual void OnEventInfo(EventInfoReplyEventArgs e) { EventHandler handler = m_EventInfoReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -537,21 +536,20 @@ namespace OpenMetaverse protected virtual void OnDirEvents(DirEventsReplyEventArgs e) { EventHandler handler = m_DirEvents; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object private readonly object m_DirEventsLock = new object(); - /// Raised when the data server responds to a request. + /// 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 + /// The event subscribers. null if no subscribers private EventHandler m_Places; /// Raises the PlacesReply event @@ -560,21 +558,20 @@ namespace OpenMetaverse protected virtual void OnPlaces(PlacesReplyEventArgs e) { EventHandler handler = m_Places; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object private readonly object m_PlacesLock = new object(); - /// Raised when the data server responds to a request. + /// 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 + /// The event subscribers. null if no subscribers private EventHandler m_DirPlaces; /// Raises the DirPlacesReply event @@ -583,14 +580,13 @@ namespace OpenMetaverse protected virtual void OnDirPlaces(DirPlacesReplyEventArgs e) { EventHandler handler = m_DirPlaces; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object private readonly object m_DirPlacesLock = new object(); - /// Raised when the data server responds to a request. + /// Raised when the data server responds to a request. public event EventHandler DirPlacesReply { add { lock (m_DirPlacesLock) { m_DirPlaces += value; } } @@ -606,14 +602,13 @@ namespace OpenMetaverse protected virtual void OnDirClassifieds(DirClassifiedsReplyEventArgs e) { EventHandler handler = m_DirClassifieds; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object private readonly object m_DirClassifiedsLock = new object(); - /// Raised when the data server responds to a request. + /// Raised when the data server responds to a request. public event EventHandler DirClassifiedsReply { add { lock (m_DirClassifiedsLock) { m_DirClassifieds += value; } } @@ -629,14 +624,13 @@ namespace OpenMetaverse protected virtual void OnDirGroups(DirGroupsReplyEventArgs e) { EventHandler handler = m_DirGroups; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object private readonly object m_DirGroupsLock = new object(); - /// Raised when the data server responds to a request. + /// Raised when the data server responds to a request. public event EventHandler DirGroupsReply { add { lock (m_DirGroupsLock) { m_DirGroups += value; } } @@ -652,14 +646,13 @@ namespace OpenMetaverse protected virtual void OnDirPeople(DirPeopleReplyEventArgs e) { EventHandler handler = m_DirPeople; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object private readonly object m_DirPeopleLock = new object(); - /// Raised when the data server responds to a request. + /// Raised when the data server responds to a request. public event EventHandler DirPeopleReply { add { lock (m_DirPeopleLock) { m_DirPeople += value; } } @@ -675,14 +668,13 @@ namespace OpenMetaverse protected virtual void OnDirLand(DirLandReplyEventArgs e) { EventHandler handler = m_DirLandReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object private readonly object m_DirLandLock = new object(); - /// Raised when the data server responds to a request. + /// Raised when the data server responds to a request. public event EventHandler DirLandReply { add { lock (m_DirLandLock) { m_DirLandReply += value; } } @@ -1446,32 +1438,27 @@ namespace OpenMetaverse /// 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; } } + public DirectoryManager.EventInfo MatchedEvent { get; } /// 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; + this.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; + public UUID QueryID { get; } /// A list of "Events" returned by the data server - public List MatchedEvents { get { return m_matchedEvents; } } + public List MatchedEvents { get; } /// Construct a new instance of the DirEventsReplyEventArgs class /// The ID of the query returned by the data server. @@ -1479,22 +1466,19 @@ namespace OpenMetaverse /// A list containing the "Events" returned by the search query public DirEventsReplyEventArgs(UUID queryID, List matchedEvents) { - this.m_QueryID = queryID; - this.m_matchedEvents = matchedEvents; + this.QueryID = queryID; + this.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; + public UUID QueryID { get; } /// A list of "Places" returned by the data server - public List MatchedPlaces { get { return m_MatchedPlaces; } } + public List MatchedPlaces { get; } /// Construct a new instance of PlacesReplyEventArgs class /// The ID of the query returned by the data server. @@ -1502,60 +1486,53 @@ namespace OpenMetaverse /// 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; + this.QueryID = queryID; + this.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; + public UUID QueryID { get; } /// A list containing Places data returned by the data server - public List MatchedParcels { get { return m_MatchedParcels; } } - + public List MatchedParcels { get; } + /// 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; + this.QueryID = queryID; + this.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; } } + public List Classifieds { get; } /// 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; + this.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; + public UUID QueryID { get; } /// A list containing Groups data returned by the data server - public List MatchedGroups { get { return m_matchedGroups; } } + public List MatchedGroups { get; } /// Construct a new instance of the DirGroupsReplyEventArgs class /// The ID of the query returned by the data server. @@ -1563,22 +1540,19 @@ namespace OpenMetaverse /// A list of groups data returned by the data server public DirGroupsReplyEventArgs(UUID queryID, List matchedGroups) { - this.m_QueryID = queryID; - this.m_matchedGroups = matchedGroups; + this.QueryID = queryID; + this.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; + public UUID QueryID { get; } /// A list containing People data returned by the data server - public List MatchedPeople { get { return m_MatchedPeople; } } + public List MatchedPeople { get; } /// Construct a new instance of the DirPeopleReplyEventArgs class /// The ID of the query returned by the data server. @@ -1586,24 +1560,22 @@ namespace OpenMetaverse /// A list of people data returned by the data server public DirPeopleReplyEventArgs(UUID queryID, List matchedPeople) { - this.m_QueryID = queryID; - this.m_MatchedPeople = matchedPeople; + this.QueryID = queryID; + this.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; } } + public List DirParcels { get; } /// 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; + this.DirParcels = dirParcels; } } #endregion diff --git a/Assets/Plugins/LibreMetaverse/EstateTools.cs b/Assets/Plugins/LibreMetaverse/EstateTools.cs index 1930e74..a498e8d 100644 --- a/Assets/Plugins/LibreMetaverse/EstateTools.cs +++ b/Assets/Plugins/LibreMetaverse/EstateTools.cs @@ -984,72 +984,66 @@ namespace OpenMetaverse /// 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; } } + public int ObjectCount { get; } + /// /// A Dictionary of Object UUIDs to tasks returned in LandStatReply /// - public Dictionary Tasks { get { return m_Tasks; } } + public Dictionary Tasks { get; } /// 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; + this.ObjectCount = objectCount; + this.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; } } + public int ObjectCount { get; } + /// /// A Dictionary of Object UUIDs to tasks returned in LandStatReply /// - public Dictionary Tasks { get { return m_Tasks; } } + public Dictionary Tasks { get; } /// 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; + this.ObjectCount = objectCount; + this.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; } } + public uint EstateID { get; } + /// /// The number of returned itmes /// - public int Count { get { return m_count; } } + public int Count { get; } + /// /// List of UUIDs of Banned Users /// - public List Banned { get { return m_banned; } } + public List Banned { get; } /// Construct a new instance of the EstateBansReplyEventArgs class /// The estate's identifier on the grid @@ -1057,31 +1051,29 @@ namespace OpenMetaverse /// User UUIDs banned public EstateBansReplyEventArgs(uint estateID, int count, List banned) { - this.m_estateID = estateID; - this.m_count = count; - this.m_banned = banned; + this.EstateID = estateID; + this.Count = count; + this.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; } } + public uint EstateID { get; } + /// /// The number of returned items /// - public int Count { get { return m_count; } } + public int Count { get; } + /// /// List of UUIDs of Allowed Users /// - public List AllowedUsers { get { return m_allowedUsers; } } + public List AllowedUsers { get; } /// Construct a new instance of the EstateUsersReplyEventArgs class /// The estate's identifier on the grid @@ -1089,31 +1081,29 @@ namespace OpenMetaverse /// Allowed users UUIDs public EstateUsersReplyEventArgs(uint estateID, int count, List allowedUsers) { - this.m_estateID = estateID; - this.m_count = count; - this.m_allowedUsers = allowedUsers; + this.EstateID = estateID; + this.Count = count; + this.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; } } + public uint EstateID { get; } + /// /// The number of returned items /// - public int Count { get { return m_count; } } + public int Count { get; } + /// /// List of UUIDs of Allowed Groups /// - public List AllowedGroups { get { return m_allowedGroups; } } + public List AllowedGroups { get; } /// Construct a new instance of the EstateGroupsReplyEventArgs class /// The estate's identifier on the grid @@ -1121,31 +1111,29 @@ namespace OpenMetaverse /// Allowed Groups UUIDs public EstateGroupsReplyEventArgs(uint estateID, int count, List allowedGroups) { - this.m_estateID = estateID; - this.m_count = count; - this.m_allowedGroups = allowedGroups; + this.EstateID = estateID; + this.Count = count; + this.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; } } + public uint EstateID { get; } + /// /// The number of returned items /// - public int Count { get { return m_count; } } + public int Count { get; } + /// /// List of UUIDs of the Estate's Managers /// - public List Managers { get { return m_Managers; } } + public List Managers { get; } /// Construct a new instance of the EstateManagersReplyEventArgs class /// The estate's identifier on the grid @@ -1153,36 +1141,34 @@ namespace OpenMetaverse /// Managers UUIDs public EstateManagersReplyEventArgs(uint estateID, int count, List managers) { - this.m_estateID = estateID; - this.m_count = count; - this.m_Managers = managers; + this.EstateID = estateID; + this.Count = count; + this.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; } } + public UUID CovenantID { get; } + /// /// The timestamp /// - public long Timestamp { get { return m_timestamp; } } + public long Timestamp { get; } + /// /// The Estate name /// - public String EstateName { get { return m_estateName; } } + public String EstateName { get; } + /// /// The Estate Owner's ID (can be a GroupID) /// - public UUID EstateOwnerID { get { return m_estateOwnerID; } } + public UUID EstateOwnerID { get; } /// Construct a new instance of the EstateCovenantReplyEventArgs class /// The Covenant ID @@ -1191,10 +1177,10 @@ namespace OpenMetaverse /// 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; + this.CovenantID = covenantID; + this.Timestamp = timestamp; + this.EstateName = estateName; + this.EstateOwnerID = estateOwnerID; } } @@ -1203,25 +1189,23 @@ namespace OpenMetaverse /// 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; } } + public String EstateName { get; } + /// /// The Estate Owner's ID (can be a GroupID) /// - public UUID EstateOwner { get { return m_estateOwner; } } + public UUID EstateOwner { get; } + /// /// The identifier of the estate on the grid /// - public uint EstateID { get { return m_estateID; } } + public uint EstateID { get; } + /// - public bool DenyNoPaymentInfo { get { return m_denyNoPaymentInfo; } } + public bool DenyNoPaymentInfo { get; } /// Construct a new instance of the EstateUpdateInfoReplyEventArgs class /// The estate's name @@ -1230,10 +1214,10 @@ namespace OpenMetaverse /// 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; + this.EstateName = estateName; + this.EstateOwner = estateOwner; + this.EstateID = estateID; + this.DenyNoPaymentInfo = denyNoPaymentInfo; } } diff --git a/Assets/Plugins/LibreMetaverse/FriendsManager.cs b/Assets/Plugins/LibreMetaverse/FriendsManager.cs index a6188fb..90c6d14 100644 --- a/Assets/Plugins/LibreMetaverse/FriendsManager.cs +++ b/Assets/Plugins/LibreMetaverse/FriendsManager.cs @@ -25,7 +25,9 @@ using System; using System.Collections.Generic; +using OpenMetaverse.Http; using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; namespace OpenMetaverse { @@ -53,40 +55,25 @@ namespace OpenMetaverse /// 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; } } + public UUID UUID { get; } /// /// full name of the avatar /// - public string Name - { - get { return m_name; } - set { m_name = value; } - } + public string Name { get; set; } /// /// True if the avatar is online /// - public bool IsOnline - { - get { return m_isOnline; } - set { m_isOnline = value; } - } + public bool IsOnline { get; set; } /// /// True if the friend can see if I am online @@ -121,26 +108,22 @@ namespace OpenMetaverse /// /// True if the freind can modify my objects /// - public bool CanModifyMyObjects - { - get { return m_canModifyMyObjects; } - set { m_canModifyMyObjects = value; } - } + public bool CanModifyMyObjects { get; set; } /// /// True if I can see if my friend is online /// - public bool CanSeeThemOnline { get { return m_canSeeThemOnline; } } + public bool CanSeeThemOnline { get; private set; } /// /// True if I can see if my friend is on the map /// - public bool CanSeeThemOnMap { get { return m_canSeeThemOnMap; } } + public bool CanSeeThemOnMap { get; private set; } /// /// True if I can modify my friend's objects /// - public bool CanModifyTheirObjects { get { return m_canModifyTheirObjects; } } + public bool CanModifyTheirObjects { get; private set; } /// /// My friend's rights represented as bitmapped flags @@ -154,7 +137,7 @@ namespace OpenMetaverse results |= FriendRights.CanSeeOnline; if (m_canSeeMeOnMap) results |= FriendRights.CanSeeOnMap; - if (m_canModifyMyObjects) + if (CanModifyMyObjects) results |= FriendRights.CanModifyObjects; return results; @@ -163,7 +146,7 @@ namespace OpenMetaverse { m_canSeeMeOnline = (value & FriendRights.CanSeeOnline) != 0; m_canSeeMeOnMap = (value & FriendRights.CanSeeOnMap) != 0; - m_canModifyMyObjects = (value & FriendRights.CanModifyObjects) != 0; + CanModifyMyObjects = (value & FriendRights.CanModifyObjects) != 0; } } @@ -175,20 +158,20 @@ namespace OpenMetaverse get { FriendRights results = FriendRights.None; - if (m_canSeeThemOnline) + if (CanSeeThemOnline) results |= FriendRights.CanSeeOnline; - if (m_canSeeThemOnMap) + if (CanSeeThemOnMap) results |= FriendRights.CanSeeOnMap; - if (m_canModifyTheirObjects) + if (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; + CanSeeThemOnline = (value & FriendRights.CanSeeOnline) != 0; + CanSeeThemOnMap = (value & FriendRights.CanSeeOnMap) != 0; + CanModifyTheirObjects = (value & FriendRights.CanModifyObjects) != 0; } } @@ -202,14 +185,14 @@ namespace OpenMetaverse /// Rights you have to see your friend online and to modify their objects internal FriendInfo(UUID id, FriendRights theirRights, FriendRights myRights) { - m_id = id; + UUID = id; m_canSeeMeOnline = (theirRights & FriendRights.CanSeeOnline) != 0; m_canSeeMeOnMap = (theirRights & FriendRights.CanSeeOnMap) != 0; - m_canModifyMyObjects = (theirRights & FriendRights.CanModifyObjects) != 0; + CanModifyMyObjects = (theirRights & FriendRights.CanModifyObjects) != 0; - m_canSeeThemOnline = (myRights & FriendRights.CanSeeOnline) != 0; - m_canSeeThemOnMap = (myRights & FriendRights.CanSeeOnMap) != 0; - m_canModifyTheirObjects = (myRights & FriendRights.CanModifyObjects) != 0; + CanSeeThemOnline = (myRights & FriendRights.CanSeeOnline) != 0; + CanSeeThemOnMap = (myRights & FriendRights.CanSeeOnMap) != 0; + CanModifyTheirObjects = (myRights & FriendRights.CanModifyObjects) != 0; } /// @@ -218,11 +201,11 @@ namespace OpenMetaverse /// 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, + if (!String.IsNullOrEmpty(Name)) + return String.Format("{0} (Their Rights: {1}, My Rights: {2})", Name, TheirFriendRights, MyFriendRights); else - return String.Format("{0} (Their Rights: {1}, My Rights: {2})", m_id, TheirFriendRights, + return String.Format("{0} (Their Rights: {1}, My Rights: {2})", UUID, TheirFriendRights, MyFriendRights); } } @@ -489,7 +472,7 @@ namespace OpenMetaverse /// /// Accept a friendship request /// - /// agentID of avatatar to form friendship with + /// agentID of avatar to form friendship with /// imSessionID of the friendship request message public void AcceptFriendship(UUID fromAgentID, UUID imSessionID) { @@ -517,6 +500,63 @@ namespace OpenMetaverse Client.Avatars.RequestAvatarName(fromAgentID); } + /// + /// Accept friendship request. Only to be used if request was sent via Offline Msg cap + /// This can be determined by the presence of a + /// value in + /// + /// agentID of avatar to form friendship with + public void AcceptFriendshipCapability(UUID fromAgentID) + { + Uri acceptFriendshipCap = Client.Network.CurrentSim.Caps.CapabilityURI("AcceptFriendship"); + if (acceptFriendshipCap == null) + { + Logger.Log("AcceptFriendship capability not found.", Helpers.LogLevel.Warning); + return; + } + UriBuilder builder = new UriBuilder(acceptFriendshipCap) + { + // Second Life has some infintely stupid escaped agent name as part of the uri query. + // Hopefully we don't need it because it makes no goddamn sense at all. Period, but just in case: + // ?from={fromAgentID}&agent_name=\"This%20Sucks\" + Query = $"from={fromAgentID}" + }; + acceptFriendshipCap = builder.Uri; + + var request = new CapsClient(acceptFriendshipCap); + var body = new OSD(); + request.OnComplete += delegate(CapsClient client, OSD result, Exception error) + { + if (error != null) + { + Logger.Log($"AcceptFriendship failed for {fromAgentID}. ({error.Message})", + Helpers.LogLevel.Warning); + return; + } + + if (result != null) + { + if (result is OSDMap resMap + && !(resMap.ContainsKey("success") && resMap["success"].AsBoolean())) { return; } + + 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); + } + + + }; + request.PostRequestAsync(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + /// /// Decline a friendship request /// @@ -534,6 +574,53 @@ namespace OpenMetaverse FriendRequests.Remove(fromAgentID); } + /// + /// Decline friendship request. Only to be used if request was sent via Offline Msg cap + /// This can be determined by the presence of a + /// value in + /// + /// of friend + public void DeclineFriendshipCap(UUID fromAgentID) + { + Uri declineFriendshipCap = Client.Network.CurrentSim.Caps.CapabilityURI("DeclineFriendship"); + if (declineFriendshipCap == null) + { + Logger.Log("DeclineFriendship capability not found.", Helpers.LogLevel.Warning); + return; + } + UriBuilder builder = new UriBuilder(declineFriendshipCap) + { + Query = $"from={fromAgentID}" + }; + declineFriendshipCap = builder.Uri; + + var request = new CapsClient(declineFriendshipCap); + var body = new OSD(); + request.OnComplete += delegate (CapsClient client, OSD result, Exception error) + { + if (error != null) + { + Logger.Log($"AcceptFriendship failed for {fromAgentID}. ({error.Message})", + Helpers.LogLevel.Warning); + return; + } + + if (result != null) + { + if (result is OSDMap resMap && + !(resMap.ContainsKey("success") && resMap["success"].AsBoolean())) { return; } + + if (FriendRequests.ContainsKey(fromAgentID)) + { + FriendRequests.Remove(fromAgentID); + } + } + + + }; + request.DeleteRequestAsync(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } + /// /// Overload: Offer friendship to an avatar. /// @@ -945,29 +1032,26 @@ namespace OpenMetaverse public class FriendsReadyEventArgs : EventArgs { - private readonly int m_count; - /// Number of friends we have - public int Count { get { return m_count; } } + public int Count { get; } + /// Get the name of the agent we requested a friendship with /// /// Construct a new instance of the FriendsReadyEventArgs class /// - /// The total number of people loaded into the friend list. + /// The total number of people loaded into the friend list. public FriendsReadyEventArgs(int count) { - this.m_count = count; + this.Count = count; } } /// 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; } } + public FriendInfo Friend { get; } /// /// Construct a new instance of the FriendInfoEventArgs class @@ -975,18 +1059,16 @@ namespace OpenMetaverse /// The FriendInfo public FriendInfoEventArgs(FriendInfo friend) { - this.m_Friend = friend; + this.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; } } + public Dictionary Names { get; } /// /// Construct a new instance of the FriendNamesEventArgs class @@ -995,24 +1077,22 @@ namespace OpenMetaverse /// and the Value is a string containing their name public FriendNamesEventArgs(Dictionary names) { - this.m_Names = names; + this.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; } } + public UUID AgentID { get; } + /// Get the name of the agent requesting friendship - public string AgentName { get { return m_AgentName; } } + public string AgentName { get; } + /// Get the ID of the session, used in accepting or declining the /// friendship offer - public UUID SessionID { get { return m_SessionID; } } + public UUID SessionID { get; } /// /// Construct a new instance of the FriendshipOfferedEventArgs class @@ -1023,25 +1103,23 @@ namespace OpenMetaverse /// friendship offer public FriendshipOfferedEventArgs(UUID agentID, string agentName, UUID imSessionID) { - this.m_AgentID = agentID; - this.m_AgentName = agentName; - this.m_SessionID = imSessionID; + this.AgentID = agentID; + this.AgentName = agentName; + this.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; } } + public UUID AgentID { get; } + /// Get the name of the agent we requested a friendship with - public string AgentName { get { return m_AgentName; } } + public string AgentName { get; } + /// true if the agent accepted our friendship offer - public bool Accepted { get { return m_Accepted; } } + public bool Accepted { get; } /// /// Construct a new instance of the FriendShipResponseEventArgs class @@ -1051,22 +1129,20 @@ namespace OpenMetaverse /// 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; + this.AgentID = agentID; + this.AgentName = agentName; + this.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; } } + public UUID AgentID { get; } + /// Get the name of the agent that terminated the friendship with us - public string AgentName { get { return m_AgentName; } } + public string AgentName { get; } /// /// Construct a new instance of the FrindshipTerminatedEventArgs class @@ -1075,8 +1151,8 @@ namespace OpenMetaverse /// 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; + this.AgentID = agentID; + this.AgentName = agentName; } } @@ -1085,16 +1161,14 @@ namespace OpenMetaverse /// 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; } } + public UUID AgentID { get; } + /// Get the region handle where our mapped friend is located - public ulong RegionHandle { get { return m_RegionHandle; } } + public ulong RegionHandle { get; } + /// Get the simulator local position where our friend is located - public Vector3 Location { get { return m_Location; } } + public Vector3 Location { get; } /// /// Construct a new instance of the FriendFoundReplyEventArgs class @@ -1104,9 +1178,9 @@ namespace OpenMetaverse /// 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; + this.AgentID = agentID; + this.RegionHandle = regionHandle; + this.Location = location; } } #endregion diff --git a/Assets/Plugins/LibreMetaverse/GridClient.cs b/Assets/Plugins/LibreMetaverse/GridClient.cs index 1c1d21e..a6c845d 100644 --- a/Assets/Plugins/LibreMetaverse/GridClient.cs +++ b/Assets/Plugins/LibreMetaverse/GridClient.cs @@ -24,7 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; using LibreMetaverse; namespace OpenMetaverse diff --git a/Assets/Plugins/LibreMetaverse/GridManager.cs b/Assets/Plugins/LibreMetaverse/GridManager.cs index 78e313a..ab87359 100644 --- a/Assets/Plugins/LibreMetaverse/GridManager.cs +++ b/Assets/Plugins/LibreMetaverse/GridManager.cs @@ -382,13 +382,16 @@ namespace OpenMetaverse #endregion Delegates /// Unknown - public float SunPhase { get { return sunPhase; } } - /// Current direction of the sun - public Vector3 SunDirection { get { return sunDirection; } } + public float SunPhase { get; private set; } + + /// Current direction of the sun + public Vector3 SunDirection { get; private set; } + /// Current angular velocity of the sun - public Vector3 SunAngVelocity { get { return sunAngVelocity; } } + public Vector3 SunAngVelocity { get; private set; } + /// Microseconds since the start of SL 4-hour day - public ulong TimeOfDay { get { return timeOfDay; } } + public ulong TimeOfDay { get; private set; } /// A dictionary of all the regions, indexed by region name internal Dictionary Regions = new Dictionary(); @@ -396,10 +399,6 @@ namespace OpenMetaverse internal Dictionary RegionsByHandle = new Dictionary(); private GridClient Client; - private float sunPhase; - private Vector3 sunDirection; - private Vector3 sunAngVelocity; - private ulong timeOfDay; /// /// Constructor @@ -430,7 +429,7 @@ namespace OpenMetaverse OSDMap body = new OSDMap {["Flags"] = OSD.FromInteger((int) layer)}; request.OnComplete += new CapsClient.CompleteCallback(MapLayerResponseHandler); - request.BeginGetResponse(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } } @@ -624,9 +623,9 @@ namespace OpenMetaverse if (m_GridLayer != null) { - for (int i = 0; i < layerData.Count; i++) + foreach (var data in layerData) { - OSDMap thisLayerData = (OSDMap)layerData[i]; + OSDMap thisLayerData = (OSDMap)data; GridLayer layer; layer.Bottom = thisLayerData["Bottom"].AsInteger(); @@ -635,7 +634,7 @@ namespace OpenMetaverse layer.Right = thisLayerData["Right"].AsInteger(); layer.ImageID = thisLayerData["ImageID"].AsUUID(); - OnGridLayer(new GridLayerEventArgs(layer)); + OnGridLayer(new GridLayerEventArgs(layer)); } } @@ -695,18 +694,18 @@ namespace OpenMetaverse GridItemType type = (GridItemType)reply.RequestData.ItemType; List items = new List(); - for (int i = 0; i < reply.Data.Length; i++) + foreach (var data in reply.Data) { - string name = Utils.BytesToString(reply.Data[i].Name); + string name = Utils.BytesToString(data.Name); switch (type) { case GridItemType.AgentLocations: MapAgentLocation location = new MapAgentLocation(); - location.GlobalX = reply.Data[i].X; - location.GlobalY = reply.Data[i].Y; + location.GlobalX = data.X; + location.GlobalY = data.Y; location.Identifier = name; - location.AvatarCount = reply.Data[i].Extra; + location.AvatarCount = data.Extra; items.Add(location); break; case GridItemType.Classified: @@ -715,28 +714,28 @@ namespace OpenMetaverse 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.GlobalX = data.X; + landsale.GlobalY = data.Y; + landsale.ID = data.ID; landsale.Name = name; - landsale.Size = reply.Data[i].Extra; - landsale.Price = reply.Data[i].Extra2; + landsale.Size = data.Extra; + landsale.Price = data.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.GlobalX = data.X; + matureEvent.GlobalY = data.Y; matureEvent.Description = name; - matureEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2; + matureEvent.Flags = (DirectoryManager.EventFlags)data.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.GlobalX = data.X; + PGEvent.GlobalY = data.Y; PGEvent.Description = name; - PGEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2; + PGEvent.Flags = (DirectoryManager.EventFlags)data.Extra2; items.Add(PGEvent); break; case GridItemType.Popular: @@ -745,26 +744,26 @@ namespace OpenMetaverse break; case GridItemType.Telehub: MapTelehub teleHubItem = new MapTelehub(); - teleHubItem.GlobalX = reply.Data[i].X; - teleHubItem.GlobalY = reply.Data[i].Y; + teleHubItem.GlobalX = data.X; + teleHubItem.GlobalY = data.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.GlobalX = data.X; + adultLandsale.GlobalY = data.Y; + adultLandsale.ID = data.ID; adultLandsale.Name = name; - adultLandsale.Size = reply.Data[i].Extra; - adultLandsale.Price = reply.Data[i].Extra2; + adultLandsale.Size = data.Extra; + adultLandsale.Price = data.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; + adultEvent.GlobalX = data.X; + adultEvent.GlobalY = data.Y; + adultEvent.Description = Utils.BytesToString(data.Name); + adultEvent.Flags = (DirectoryManager.EventFlags)data.Extra2; items.Add(adultEvent); break; default: @@ -784,10 +783,10 @@ namespace OpenMetaverse { SimulatorViewerTimeMessagePacket time = (SimulatorViewerTimeMessagePacket)e.Packet; - sunPhase = time.TimeInfo.SunPhase; - sunDirection = time.TimeInfo.SunDirection; - sunAngVelocity = time.TimeInfo.SunAngVelocity; - timeOfDay = time.TimeInfo.UsecSinceStart; + 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? } @@ -857,72 +856,59 @@ namespace OpenMetaverse 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 Simulator Simulator { get; } + public List NewEntries { get; } + public List RemovedEntries { get; } public CoarseLocationUpdateEventArgs(Simulator simulator, List newEntries, List removedEntries) { - this.m_Simulator = simulator; - this.m_NewEntries = newEntries; - this.m_RemovedEntries = removedEntries; + this.Simulator = simulator; + this.NewEntries = newEntries; + this.RemovedEntries = removedEntries; } } public class GridRegionEventArgs : EventArgs { - private readonly GridRegion m_Region; - public GridRegion Region { get { return m_Region; } } + public GridRegion Region { get; } public GridRegionEventArgs(GridRegion region) { - this.m_Region = region; + this.Region = region; } } public class GridLayerEventArgs : EventArgs { - private readonly GridLayer m_Layer; - - public GridLayer Layer { get { return m_Layer; } } + public GridLayer Layer { get; } public GridLayerEventArgs(GridLayer layer) { - this.m_Layer = layer; + this.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 GridItemType Type { get; } + public List Items { get; } public GridItemsEventArgs(GridItemType type, List items) { - this.m_Type = type; - this.m_Items = items; + this.Type = type; + this.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 UUID RegionID { get; } + public ulong RegionHandle { get; } public RegionHandleReplyEventArgs(UUID regionID, ulong regionHandle) { - this.m_RegionID = regionID; - this.m_RegionHandle = regionHandle; + this.RegionID = regionID; + this.RegionHandle = regionHandle; } } diff --git a/Assets/Plugins/LibreMetaverse/GroupManager.cs b/Assets/Plugins/LibreMetaverse/GroupManager.cs index 6a9ef66..63c479d 100644 --- a/Assets/Plugins/LibreMetaverse/GroupManager.cs +++ b/Assets/Plugins/LibreMetaverse/GroupManager.cs @@ -1058,7 +1058,7 @@ namespace OpenMetaverse }; OSDMap requestData = new OSDMap(1) {["group_id"] = @group}; - req.BeginGetResponse(requestData, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT * 4); + req.PostRequestAsync(requestData, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT * 4); return requestID; } @@ -1696,7 +1696,7 @@ namespace OpenMetaverse }; - req.BeginGetResponse(Client.Settings.CAPS_TIMEOUT); + req.GetRequestAsync(Client.Settings.CAPS_TIMEOUT); } /// @@ -1737,7 +1737,7 @@ namespace OpenMetaverse } OSDRequest["ban_ids"] = banIDs; - req.BeginGetResponse(OSDRequest, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + req.PostRequestAsync(OSDRequest, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } diff --git a/Assets/Plugins/LibreMetaverse/Imaging/BakeLayer.cs b/Assets/Plugins/LibreMetaverse/Imaging/BakeLayer.cs index decd339..8d33ab2 100644 --- a/Assets/Plugins/LibreMetaverse/Imaging/BakeLayer.cs +++ b/Assets/Plugins/LibreMetaverse/Imaging/BakeLayer.cs @@ -25,7 +25,6 @@ */ using System; -using System.Reflection; using System.Collections.Generic; using System.IO; //using System.Drawing; @@ -161,9 +160,16 @@ namespace OpenMetaverse.Imaging 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 (DrawLayer(LoadResourceLayer("head_color.tga"), false) == true) + { + AddAlpha(bakedTexture.Image, LoadResourceLayer("head_alpha.tga")); + MultiplyLayerFromAlpha(bakedTexture.Image, LoadResourceLayer("head_skingrain.tga")); + Logger.Log("[Bake]: created head master bake", Helpers.LogLevel.Debug); + } + else + { + Logger.Log("[Bake]: Unable to draw layer from texture file", Helpers.LogLevel.Debug); + } } if (skinTexture.Texture == null) @@ -424,8 +430,8 @@ namespace OpenMetaverse.Imaging private bool MaskBelongsToBake(string mask) { - return (bakeType != BakeType.LowerBody || !mask.Contains("upper")) - && (bakeType != BakeType.LowerBody || !mask.Contains("shirt")) + return (bakeType != BakeType.LowerBody || !mask.Contains("upper")) + && (bakeType != BakeType.LowerBody || !mask.Contains("shirt")) && (bakeType != BakeType.UpperBody || !mask.Contains("lower")); } @@ -460,16 +466,25 @@ namespace OpenMetaverse.Imaging byte[] sourceAlpha = sourceHasAlpha ? source.Alpha : null; byte[] sourceBump = sourceHasBump ? source.Bump : null; + /* 4c506093003675ce6f24d7273812c4440adc87b7 + Update BakeLayer.cs + add unneeded but nice debug info around head_color loading + correct color loading due to alpha being broken + */ + bool loadedAlpha = false; for (int y = 0; y < bakeHeight; y++) { for (int x = 0; x < bakeWidth; x++) { + loadedAlpha = false; alpha = 0; alphaInv = 0; + if (sourceHasAlpha) { if (sourceAlpha.Length > i) { + loadedAlpha = true; alpha = sourceAlpha[i]; alphaInv = (byte)(Byte.MaxValue - alpha); } @@ -481,9 +496,18 @@ namespace OpenMetaverse.Imaging { if ((sourceRed.Length > i) && (sourceGreen.Length > i) && (sourceBlue.Length > i)) { - 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 (loadedAlpha == true) + { + 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); + } + else + { + bakedRed[i] = sourceRed[i]; + bakedGreen[i] = sourceGreen[i]; + bakedBlue[i] = sourceBlue[i]; + } } } } @@ -519,7 +543,7 @@ namespace OpenMetaverse.Imaging /// /// Destination image /// Source image - /// Sanitization was succefull + /// Sanitization was successful private bool SanitizeLayers(ManagedImage dest, ManagedImage src) { if (dest == null || src == null) return false; diff --git a/Assets/Plugins/LibreMetaverse/Imaging/ManagedImage.cs b/Assets/Plugins/LibreMetaverse/Imaging/ManagedImage.cs index 0c7b7d4..a6c1cac 100644 --- a/Assets/Plugins/LibreMetaverse/Imaging/ManagedImage.cs +++ b/Assets/Plugins/LibreMetaverse/Imaging/ManagedImage.cs @@ -144,24 +144,24 @@ namespace OpenMetaverse.Imaging Alpha = new byte[pixelCount]; //BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, Width, Height), - // ImageLockMode.ReadOnly, 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); + // ImageLockMode.ReadOnly, 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++); + } + } + + */ + for (int i = 0; i < pixelCount; i++) { Color32 bit = tex.GetPixel(i%Width , i / Width); @@ -171,7 +171,10 @@ namespace OpenMetaverse.Imaging Alpha[i] = bit.a; } + //bitmap.UnlockBits(bd); } + // this 16bit grayscale image format is commented-out for Raindrop and we need to investigate what its used for; can we just ignore it? + // unity does not seem to support 16bit grayscale //else if (tex.format == TextureFormat.Alpha8) // PixelFormat.Format16bppGrayScale --- 16 bits per pixel. The color information specifies 65536 shades of gray. //{ // Channels = ImageChannels.Gray; @@ -215,6 +218,7 @@ namespace OpenMetaverse.Imaging } } + // can we remove the following? this Format32bppRgb is a ridiculous format. else if (tex.format == TextureFormat.RGB24) // PixelFormat.Format32bppRgb) --- The remaining 8 bits are not used. { Channels = ImageChannels.Color; diff --git a/Assets/Plugins/LibreMetaverse/Imaging/TGALoader.cs b/Assets/Plugins/LibreMetaverse/Imaging/TGALoader.cs index 98f2c67..31d6e0a 100644 --- a/Assets/Plugins/LibreMetaverse/Imaging/TGALoader.cs +++ b/Assets/Plugins/LibreMetaverse/Imaging/TGALoader.cs @@ -1,28 +1,28 @@ -///* -// * Copyright (c) 2006-2016, openmetaverse.co -// * 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.co 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. -// */ +/* + * Copyright (c) 2006-2016, openmetaverse.co + * 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.co 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; @@ -130,192 +130,182 @@ namespace OpenMetaverse.Imaging } } - public static bool isRLE(string path) + struct tgaCD { - return true; + public uint RMask, GMask, BMask, AMask; + public byte RShift, GShift, BShift, AShift; + public uint FinalOr; + public bool NeedNoConvert; } - public static Texture2D LoadTGAOld(System.IO.Stream source) + static uint UnpackColor( + uint sourceColor, ref tgaCD cd) { - 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)) + if (cd.RMask == 0xFF && cd.GMask == 0xFF && cd.BMask == 0xFF) { - 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.PixelDepth == 8) - // throw new ArgumentException("TGA texture had 8 bit depth."); - //if (header.ImageSpec.PixelDepth == 16) - // throw new ArgumentException("TGA texture had 16 bit depth."); - - if (header.ImageSpec.AlphaBits > 8) - throw new ArgumentException("Not a supported tga file: too many Alpha bits"); - - if (header.ImageSpec.Width > 4096 || - header.ImageSpec.Height > 4096) - throw new ArgumentException("Image too large."); - - - long len = br.BaseStream.Length; - //if (header.ImageSpec.PixelDepth == 24) - //{ - // long expectedBytes = header.ImageSpec.Width * header.ImageSpec.Height * 3; - // if (len < expectedBytes) - // { - // //throw new ArgumentException("TGA texture has 24 bit depth, height and width of " +header.ImageSpec.Width+ " " + header.ImageSpec.Height+ " but the number of bytes in file is " + len); - // throw new ArgumentException("the 24bit TGA file is smaller than expected"); - // } - - //} - //if (header.ImageSpec.PixelDepth == 32) - //{ - // long expectedBytes = header.ImageSpec.Width * header.ImageSpec.Height * 4; - // if (len < expectedBytes) - // { - // //throw new ArgumentException("TGA texture has 32 bit depth, height and width of " +header.ImageSpec.Width+ " " + header.ImageSpec.Height+ " but the number of bytes in file is " + len); - // throw new ArgumentException("the 32bit TGA file is smaller than expected"); - // } - - //} - //if (header.ImageSpec.PixelDepth == 8) - //{ - // long expectedBytes = header.ImageSpec.Width * header.ImageSpec.Height * 1; - // if (len < expectedBytes) - // { - // //throw new ArgumentException("TGA texture has 32 bit depth, height and width of " +header.ImageSpec.Width+ " " + header.ImageSpec.Height+ " but the number of bytes in file is " + len); - // throw new ArgumentException("the 8bit TGA file is smaller than expected"); - // } - - //} - - - Texture2D b; - int width = header.ImageSpec.Width; - int height = header.ImageSpec.Height; - Color32[] pulledColors = new Color32[width * height]; - //BitmapData bd; - - //NOTE NON COMPRESSED textures only!!! - - // 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 Texture2D( - header.ImageSpec.Width, - header.ImageSpec.Height, - TextureFormat.ARGB32, - false - /*PixelFormat.Format32bppArgb*/); - - //bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), - // ImageLockMode.WriteOnly, - // PixelFormat.Format32bppPArgb); - - //Debug.Log("Debug the color: " + pulledColors[5]); //ok we know these are correct. - //Debug.Log("Debug the color: " + pulledColors[500]); - //Debug.Log("Debug the color: " + pulledColors[50000]); - } - else - { // Image does not need an alpha layer, so do not include one. - b = new Texture2D( - header.ImageSpec.Width, - header.ImageSpec.Height, - TextureFormat.RGB24, - false - /*PixelFormat.Format32bppRgb*/); - - //bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), - // ImageLockMode.WriteOnly, - // PixelFormat.Format32bppRgb); - - } - - if (header.ImageSpec.PixelDepth == 8) - { - for (int i = 0; i < width * height; i++) - { - byte red = br.ReadByte(); - - pulledColors[i] = new Color32(0, 0, 0, red); - } - - } else if (header.ImageSpec.PixelDepth == 16) - { - throw new ArgumentException("TGA texture had 16 bit depth."); - - } else if (header.ImageSpec.PixelDepth == 24) //TODO: handle the case of 'alpha channel is present'! - { - for (int i = 0; i < width * height; i++) - { - byte red = br.ReadByte(); - byte green = br.ReadByte(); - byte blue = br.ReadByte(); - - pulledColors[i] = new Color32(blue, green, red, 1); - } - - } else if (header.ImageSpec.PixelDepth == 32) - { - - for (int i = 0; i < width * height; i++) - { - byte red = br.ReadByte(); - byte green = br.ReadByte(); - byte blue = br.ReadByte(); - byte alpha = br.ReadByte(); - - pulledColors[i] = new Color32(blue, green, red, alpha); - } - } - - //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); - b.SetPixels32(pulledColors); - b.Apply(); - - return b; + // 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( + Color32[] b, int texWidth, int texHeight, + int line, + int byp, + byte[] data, + ref tgaCD cd) + { + if (cd.NeedNoConvert) + { + // fast copy + uint offset_colorArray_scanline = (uint)(line * texWidth + 0); //should be large enough? + //uint* linep = (uint*)((byte*)b.Scan0.ToPointer() + line * b.Stride); + fixed (byte* ptr = data) + { + uint* sptr = (uint*)ptr; + for (int i = 0; i < texWidth; ++i) + { + b[i + offset_colorArray_scanline] = makeColor32fromUInt(sptr[i]); + } + } + } + else + { + //byte* linep = (byte*)b.Scan0.ToPointer() + line * b.Stride; + uint offset_colorArray_scanline = (uint)(line * texWidth + 0); + + //uint* up = (uint*)linep; + + int rdi = 0; + + fixed (byte* ptr = data) + { + for (int i = 0; i < texWidth; ++i) + { + uint x = 0; + for (int j = 0; j < byp; ++j) + { + x |= ((uint)ptr[rdi]) << (j << 3); //load all bytes that represent the pixel's color into register x. + ++rdi; + } + uint unpackedColoByte = UnpackColor(x, ref cd); + b[i+line*texWidth] = makeColor32fromUInt(unpackedColoByte); + } + } + } + } + + + static void decodeRle( + Color32[] b, int texWidth, int texHeight, + int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) + { + try + { + int w = texWidth; + // 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 < texHeight; ++j) + { + while (index < maxindex) + { + byte blocktype = br.ReadByte(); //MSB of blocktype: 1 means Raw packet(non-RLE), 0 means RLE packet + + int bytestoread; + int bytestocopy; + + if (blocktype >= 0x80) // run-length packet. - read 1 color and replicate them by bytestocopy + { + int pixel_count_minus_1 = (blocktype - 0x80); + bytestoread = byp; // pixel data + bytestocopy = byp * pixel_count_minus_1; + } + else //raw packet (non run-lenght encoding.) + { + 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; + } + // todo: did i wrongly flip the orientation here? is the original actually correct? + if (!bottomUp) + decodeLine(b, texWidth, texHeight, j, byp, linebuffer, ref cd); + else + decodeLine(b, texWidth, texHeight, texHeight - j - 1, byp, linebuffer, ref cd); + + if (index > maxindex) + { + Array.Copy(linebuffer, maxindex, linebuffer, 0, index - maxindex); + index -= maxindex; + } + else + index = 0; + + } + } + catch (System.IO.EndOfStreamException) + { + } + } + + + + /// + /// decodes the non-RLE version of tga files. + /// + /// output reference to texture/bmp + /// bytes-per-pixel + /// ??? + /// binary reader that is reading the data file + /// if the image sh. + static void decodePlain( + Color32[] b, int texWidth, int texHeight, + int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) + { + int w = texWidth; + byte[] linebuffer = new byte[w * byp]; + + for (int j = 0; j < texHeight; ++j) + { + br.Read(linebuffer, 0, w * byp); + + // todo: did i wrongly flip the orientation here? is the original actually correct? + if (!bottomUp) + decodeLine(b, texWidth, texHeight, j, byp, linebuffer, ref cd); + else + decodeLine(b, texWidth, texHeight, texHeight - j - 1, byp, linebuffer, ref cd); + } + } + + static void decodeStandard8( Color32[] b, int texWidth, int texHeight, tgaHeader hdr, @@ -621,107 +611,6 @@ namespace OpenMetaverse.Imaging - struct tgaCD - { - public uint RMask, GMask, BMask, AMask; - public byte RShift, GShift, BShift, AShift; - public uint FinalOr; - public bool NeedNoConvert; - } - - - /// - /// decodes the non-RLE version of tga files. - /// - /// output reference to texture/bmp - /// bytes-per-pixel - /// ??? - /// binary reader that is reading the data file - /// if the image sh. - static void decodePlain( - Color32[] b, int texWidth, int texHeight, - int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) - { - int w = texWidth; - byte[] linebuffer = new byte[w * byp]; - - for (int j = 0; j < texHeight; ++j) - { - br.Read(linebuffer, 0, w * byp); - - if (!bottomUp) - decodeLine(b, texWidth, texHeight, j, byp, linebuffer, ref cd); - else - decodeLine(b, texWidth, texHeight, texHeight - j - 1, byp, linebuffer, ref cd); - } - } - - static void decodeRle( - Color32[] b, int texWidth, int texHeight, - int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) - { - try - { - int w = texWidth; - // 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 < texHeight; ++j) - { - while (index < maxindex) - { - byte blocktype = br.ReadByte(); //MSB of blocktype: 1 means Raw packet(non-RLE), 0 means RLE packet - - int bytestoread; - int bytestocopy; - - if (blocktype >= 0x80) // run-length packet. - read 1 color and replicate them by bytestocopy - { - int pixel_count_minus_1 = (blocktype - 0x80); - bytestoread = byp; // pixel data - bytestocopy = byp * pixel_count_minus_1; - } - else //raw packet (non run-lenght encoding.) - { - 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, texWidth, texHeight, j, byp, linebuffer, ref cd); - else - decodeLine(b, texWidth, texHeight, texHeight - j - 1, 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 public Color32 makeColor32fromUInt(uint x) { return new Color32( (byte)( (x & 0x00FF0000) >> 16), @@ -730,75 +619,6 @@ namespace OpenMetaverse.Imaging (byte)((x & 0xFF000000) >> 24)); //alpha } - 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( - Color32[] b, int texWidth, int texHeight, - int line, - int byp, - byte[] data, - ref tgaCD cd) - { - if (cd.NeedNoConvert) - { - // fast copy - uint offset_colorArray_scanline = (uint)(line * texWidth + 0); //should be large enough? - //uint* linep = (uint*)((byte*)b.Scan0.ToPointer() + line * b.Stride); - fixed (byte* ptr = data) - { - uint* sptr = (uint*)ptr; - for (int i = 0; i < texWidth; ++i) - { - b[i + offset_colorArray_scanline] = makeColor32fromUInt(sptr[i]); - } - } - } - else - { - //byte* linep = (byte*)b.Scan0.ToPointer() + line * b.Stride; - uint offset_colorArray_scanline = (uint)(line * texWidth + 0); - - //uint* up = (uint*)linep; - - int rdi = 0; - - fixed (byte* ptr = data) - { - for (int i = 0; i < texWidth; ++i) - { - uint x = 0; - for (int j = 0; j < byp; ++j) - { - x |= ((uint)ptr[rdi]) << (j << 3); //load all bytes that represent the pixel's color into register x. - ++rdi; - } - uint unpackedColoByte = UnpackColor(x, ref cd); - b[i+line*texWidth] = makeColor32fromUInt(unpackedColoByte); - } - } - } - } - } #endif diff --git a/Assets/Plugins/LibreMetaverse/ImportExport/ModelUploader.cs b/Assets/Plugins/LibreMetaverse/ImportExport/ModelUploader.cs index 3f357cc..34fbcce 100644 --- a/Assets/Plugins/LibreMetaverse/ImportExport/ModelUploader.cs +++ b/Assets/Plugins/LibreMetaverse/ImportExport/ModelUploader.cs @@ -26,10 +26,6 @@ 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; @@ -149,16 +145,9 @@ namespace OpenMetaverse.ImportExport resources["mesh_list"] = meshList; OSDArray textureList = new OSDArray(); - for (int i = 0; i < Images.Count; i++) + foreach (var img in Images) { - if (upload) - { - textureList.Add(new OSDBinary(Images[i])); - } - else - { - textureList.Add(new OSDBinary(Utils.EmptyBytes)); - } + textureList.Add(upload ? new OSDBinary(img) : new OSDBinary(Utils.EmptyBytes)); } resources["texture_list"] = textureList; @@ -190,9 +179,8 @@ namespace OpenMetaverse.ImportExport return; } - if (result is OSDMap) + if (result is OSDMap res) { - var res = (OSDMap)result; Uri uploader = new Uri(res["uploader"]); PerformUpload(uploader, (contents => { @@ -262,11 +250,11 @@ namespace OpenMetaverse.ImportExport return; } - Logger.Log("Response from mesh upload prepare:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug); + Logger.Log("Response from mesh upload prepare:" + Environment.NewLine + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug); callback?.Invoke(result); }; - request.BeginGetResponse(req, OSDFormat.Xml, 3 * 60 * 1000); + request.PostRequestAsync(req, OSDFormat.Xml, 3 * 60 * 1000); } @@ -287,11 +275,12 @@ namespace OpenMetaverse.ImportExport return; } OSDMap res = (OSDMap)result; - Logger.Log("Response from mesh upload perform:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug); + Logger.Log("Response from mesh upload perform:" + Environment.NewLine + + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug); callback?.Invoke(res); }; - request.BeginGetResponse(AssetResources(true), OSDFormat.Xml, 60 * 1000); + request.PostRequestAsync(AssetResources(true), OSDFormat.Xml, 60 * 1000); } diff --git a/Assets/Plugins/LibreMetaverse/Interfaces/IByteBufferPool.cs b/Assets/Plugins/LibreMetaverse/Interfaces/IByteBufferPool.cs index fbfb6fa..63a7747 100644 --- a/Assets/Plugins/LibreMetaverse/Interfaces/IByteBufferPool.cs +++ b/Assets/Plugins/LibreMetaverse/Interfaces/IByteBufferPool.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenMetaverse.Interfaces +namespace OpenMetaverse.Interfaces { /// /// Interface to a class that can supply cached byte arrays diff --git a/Assets/Plugins/LibreMetaverse/Interfaces/IMessage.cs b/Assets/Plugins/LibreMetaverse/Interfaces/IMessage.cs index 56ffbb3..3a61e15 100644 --- a/Assets/Plugins/LibreMetaverse/Interfaces/IMessage.cs +++ b/Assets/Plugins/LibreMetaverse/Interfaces/IMessage.cs @@ -24,9 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Collections.Generic; -using System.Text; using OpenMetaverse.StructuredData; diff --git a/Assets/Plugins/LibreMetaverse/Inventory.cs b/Assets/Plugins/LibreMetaverse/Inventory.cs index cafc48c..3a0a4a6 100644 --- a/Assets/Plugins/LibreMetaverse/Inventory.cs +++ b/Assets/Plugins/LibreMetaverse/Inventory.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -132,7 +133,7 @@ namespace OpenMetaverse set { UpdateNodeFor(value); - _RootNode = Items[value.UUID]; + RootNode = Items[value.UUID]; } } @@ -145,28 +146,25 @@ namespace OpenMetaverse set { UpdateNodeFor(value); - _LibraryRootNode = Items[value.UUID]; + LibraryRootNode = Items[value.UUID]; } } - private InventoryNode _LibraryRootNode; - private InventoryNode _RootNode; - /// /// The root node of the avatars inventory /// - public InventoryNode RootNode => _RootNode; + public InventoryNode RootNode { get; private set; } /// /// The root node of the default shared library /// - public InventoryNode LibraryRootNode => _LibraryRootNode; + public InventoryNode LibraryRootNode { get; private set; } - public UUID Owner { get; } + public UUID Owner { get; private set; } private GridClient Client; //private InventoryManager Manager; - public Dictionary Items = new Dictionary(); + public Dictionary Items; public Inventory(GridClient client, InventoryManager manager) : this(client, manager, client.Self.AgentID) { } @@ -226,8 +224,10 @@ namespace OpenMetaverse 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. + InventoryFolder fakeParent = new InventoryFolder(item.ParentUUID) + { + DescendentCount = 1 // Dear god, please forgive me. + }; itemParent = new InventoryNode(fakeParent); Items[item.ParentUUID] = itemParent; // Unfortunately, this breaks the nice unified tree @@ -235,13 +235,6 @@ namespace OpenMetaverse // 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) {item.ParentUUID}; - - } } InventoryNode itemNode; @@ -349,7 +342,7 @@ namespace OpenMetaverse BinaryFormatter bformatter = new BinaryFormatter(); lock (Items) { - Logger.Log("Caching " + Items.Count.ToString() + " inventory items to " + filename, Helpers.LogLevel.Info); + Logger.Log($"Caching {Items.Count} inventory items to {filename}", Helpers.LogLevel.Info); foreach (KeyValuePair kvp in Items) { bformatter.Serialize(stream, kvp.Value); @@ -359,7 +352,7 @@ namespace OpenMetaverse } catch (Exception e) { - Logger.Log("Error saving inventory cache to disk :"+e.Message,Helpers.LogLevel.Error); + Logger.Log("Error saving inventory cache to disk", Helpers.LogLevel.Error, e); } } @@ -367,7 +360,7 @@ namespace OpenMetaverse /// 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 + /// The number of inventory items successfully reconstructed into the inventory node tree public int RestoreFromDisk(string filename) { List nodes = new List(); @@ -381,10 +374,9 @@ namespace OpenMetaverse using (Stream stream = File.Open(filename, FileMode.Open)) { BinaryFormatter bformatter = new BinaryFormatter(); - while (stream.Position < stream.Length) { - OpenMetaverse.InventoryNode node = (InventoryNode)bformatter.Deserialize(stream); + var node = (InventoryNode)bformatter.Deserialize(stream); nodes.Add(node); item_count++; } @@ -392,11 +384,11 @@ namespace OpenMetaverse } catch (Exception e) { - Logger.Log("Error accessing inventory cache file :" + e.Message, Helpers.LogLevel.Error); + Logger.Log("Error accessing inventory cache file", Helpers.LogLevel.Error, e); return -1; } - Logger.Log("Read " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); + Logger.Log($"Read {item_count} items from inventory cache file", Helpers.LogLevel.Info); item_count = 0; List del_nodes = new List(); //nodes that we have processed and will delete @@ -478,7 +470,7 @@ namespace OpenMetaverse del_nodes.Clear(); } - Logger.Log("Reassembled " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); + Logger.Log($"Reassembled {item_count} items from inventory cache file", Helpers.LogLevel.Info); return item_count; } @@ -506,9 +498,10 @@ namespace OpenMetaverse { // 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); - + { + Logger.Log($"Inventory[uuid]: uuid {uuid} is not equal to value.UUID {value.UUID}", + Helpers.LogLevel.Warning, Client); + } UpdateNodeFor(value); } else diff --git a/Assets/Plugins/LibreMetaverse/InventoryAISClient.cs b/Assets/Plugins/LibreMetaverse/InventoryAISClient.cs index 96dedc2..4e0e832 100644 --- a/Assets/Plugins/LibreMetaverse/InventoryAISClient.cs +++ b/Assets/Plugins/LibreMetaverse/InventoryAISClient.cs @@ -1,10 +1,33 @@ +/* + * Copyright (c) 2019-2022, Sjofn LLC + * 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.co 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 System.Linq; -using System.Net; using System.Net.Http; -using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using OpenMetaverse; @@ -26,7 +49,7 @@ namespace LibreMetaverse { Client = client; httpClient.DefaultRequestHeaders.Accept.Clear(); - httpClient.DefaultRequestHeaders.Add("User-Agent", "LibreMetaverse AIS Client"); + httpClient.DefaultRequestHeaders.Add("User-Agent", $"{Settings.USER_AGENT} AIS Client"); } public bool IsAvailable => (Client.Network.CurrentSim.Caps != null && diff --git a/Assets/Plugins/LibreMetaverse/InventoryBase.cs b/Assets/Plugins/LibreMetaverse/InventoryBase.cs index a7c8c52..5fd4d94 100644 --- a/Assets/Plugins/LibreMetaverse/InventoryBase.cs +++ b/Assets/Plugins/LibreMetaverse/InventoryBase.cs @@ -1,7 +1,32 @@ -using System; -using System.Collections.Generic; +/* + * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. + * 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.co 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.Serialization; -using System.Text; using OpenMetaverse.StructuredData; namespace OpenMetaverse @@ -9,7 +34,7 @@ namespace OpenMetaverse /// /// Base Class for Inventory Items /// - [Serializable()] + [Serializable] public abstract class InventoryBase : ISerializable { /// of item/folder @@ -69,7 +94,7 @@ namespace OpenMetaverse } /// - /// Determine whether the specified object is equal to the current object + /// Determine whether the specified object is equal to the current object /// /// InventoryBase object to compare against /// true if objects are the same @@ -79,7 +104,7 @@ namespace OpenMetaverse } /// - /// Determine whether the specified object is equal to the current object + /// Determine whether the specified object is equal to the current object /// /// InventoryBase object to compare against /// true if objects are the same @@ -106,10 +131,9 @@ namespace OpenMetaverse { public override string ToString() { - return AssetType + " " + AssetUUID + " (" + InventoryType + " " + UUID + ") '" + Name + "'/'" + - Description + "' " + Permissions; + return $"{AssetType} {AssetUUID} ({InventoryType} {UUID}) '{Name}'/'{Description}' {Permissions}"; } - /// The of this item + /// The of this item public UUID AssetUUID; /// The combined of this item public Permissions Permissions; @@ -117,11 +141,11 @@ namespace OpenMetaverse public AssetType AssetType; /// The type of item from the enum public InventoryType InventoryType; - /// The of the creator of this item + /// 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 + /// The s this item is set to or owned by public UUID GroupID; /// If true, item is owned by a group public bool GroupOwned; @@ -129,20 +153,20 @@ namespace OpenMetaverse public int SalePrice; /// The type of sale from the enum public SaleType SaleType; - /// Combined flags from + /// 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 + /// The of the previous owner of the item public UUID LastOwnerID; /// /// Construct a new InventoryItem object /// - /// The of the item + /// The of the item public InventoryItem(UUID itemID) : base(itemID) { } @@ -245,9 +269,9 @@ namespace OpenMetaverse } /// - /// Determine whether the specified object is equal to the current object + /// Determine whether the specified object is equal to the current object /// - /// The object to compare against + /// The object to compare against /// true if objects are the same public bool Equals(InventoryItem o) { @@ -348,14 +372,14 @@ namespace OpenMetaverse /// InventoryTexture Class representing a graphical image /// /// - [Serializable()] + [Serializable] public class InventoryTexture : InventoryItem { /// /// Construct an InventoryTexture object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryTexture(UUID itemID) : base(itemID) { @@ -376,14 +400,14 @@ namespace OpenMetaverse /// /// InventorySound Class representing a playable sound /// - [Serializable()] + [Serializable] public class InventorySound : InventoryItem { /// /// Construct an InventorySound object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventorySound(UUID itemID) : base(itemID) { @@ -404,14 +428,14 @@ namespace OpenMetaverse /// /// InventoryCallingCard Class, contains information on another avatar /// - [Serializable()] + [Serializable] public class InventoryCallingCard : InventoryItem { /// /// Construct an InventoryCallingCard object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryCallingCard(UUID itemID) : base(itemID) { @@ -432,14 +456,14 @@ namespace OpenMetaverse /// /// InventoryLandmark Class, contains details on a specific location /// - [Serializable()] + [Serializable] public class InventoryLandmark : InventoryItem { /// /// Construct an InventoryLandmark object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryLandmark(UUID itemID) : base(itemID) { @@ -474,14 +498,14 @@ namespace OpenMetaverse /// /// InventoryObject Class contains details on a primitive or coalesced set of primitives /// - [Serializable()] + [Serializable] public class InventoryObject : InventoryItem { /// /// Construct an InventoryObject object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryObject(UUID itemID) : base(itemID) { @@ -520,14 +544,14 @@ namespace OpenMetaverse /// /// InventoryNotecard Class, contains details on an encoded text document /// - [Serializable()] + [Serializable] public class InventoryNotecard : InventoryItem { /// /// Construct an InventoryNotecard object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryNotecard(UUID itemID) : base(itemID) { @@ -549,14 +573,14 @@ namespace OpenMetaverse /// InventoryCategory Class /// /// TODO: Is this even used for anything? - [Serializable()] + [Serializable] public class InventoryCategory : InventoryItem { /// /// Construct an InventoryCategory object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryCategory(UUID itemID) : base(itemID) { @@ -577,14 +601,14 @@ namespace OpenMetaverse /// /// InventoryLSL Class, represents a Linden Scripting Language object /// - [Serializable()] + [Serializable] public class InventoryLSL : InventoryItem { /// /// Construct an InventoryLSL object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryLSL(UUID itemID) : base(itemID) { @@ -605,7 +629,7 @@ namespace OpenMetaverse /// /// InventorySnapshot Class, an image taken with the viewer /// - [Serializable()] + [Serializable] public class InventorySnapshot : InventoryItem { /// @@ -633,14 +657,14 @@ namespace OpenMetaverse /// /// InventoryAttachment Class, contains details on an attachable object /// - [Serializable()] + [Serializable] public class InventoryAttachment : InventoryItem { /// /// Construct an InventoryAttachment object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryAttachment(UUID itemID) : base(itemID) { @@ -670,14 +694,14 @@ namespace OpenMetaverse /// /// InventoryWearable Class, details on a clothing item or body part /// - [Serializable()] + [Serializable] public class InventoryWearable : InventoryItem { /// /// Construct an InventoryWearable object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryWearable(UUID itemID) : base(itemID) { InventoryType = InventoryType.Wearable; } /// @@ -703,14 +727,14 @@ namespace OpenMetaverse /// /// InventoryAnimation Class, A bvh encoded object which animates an avatar /// - [Serializable()] + [Serializable] public class InventoryAnimation : InventoryItem { /// /// Construct an InventoryAnimation object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryAnimation(UUID itemID) : base(itemID) { @@ -731,14 +755,14 @@ namespace OpenMetaverse /// /// InventoryGesture Class, details on a series of animations, sounds, and actions /// - [Serializable()] + [Serializable] public class InventoryGesture : InventoryItem { /// /// Construct an InventoryGesture object /// - /// A which becomes the - /// objects AssetUUID + /// A which becomes the + /// objects AssetUUID public InventoryGesture(UUID itemID) : base(itemID) { @@ -760,7 +784,7 @@ namespace OpenMetaverse /// A folder contains s and has certain attributes specific /// to itself /// - [Serializable()] + [Serializable] public class InventoryFolder : InventoryBase { /// The Preferred for a folder. diff --git a/Assets/Plugins/LibreMetaverse/InventoryManager.cs b/Assets/Plugins/LibreMetaverse/InventoryManager.cs index 416b873..9eeb3bf 100644 --- a/Assets/Plugins/LibreMetaverse/InventoryManager.cs +++ b/Assets/Plugins/LibreMetaverse/InventoryManager.cs @@ -29,8 +29,6 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading; -using System.Runtime.Serialization; -using System.Threading.Tasks; using OpenMetaverse.Http; using OpenMetaverse.Messages.Linden; using OpenMetaverse.StructuredData; @@ -548,8 +546,7 @@ namespace OpenMetaverse 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 && + if (Client.Network.CurrentSim.Caps != null && Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventory2") != null) { RequestFetchInventoryCap(itemIDs, ownerIDs); @@ -590,8 +587,7 @@ namespace OpenMetaverse 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 && + if (Client.Network.CurrentSim.Caps != null && Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventory2") != null) { CapsClient request = Client.Network.CurrentSim.Caps.CreateCapsClient("FetchInventory2"); @@ -633,7 +629,7 @@ namespace OpenMetaverse OSDRequest["items"] = items; - request.BeginGetResponse(OSDRequest, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(OSDRequest, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } } /// @@ -647,7 +643,7 @@ namespace OpenMetaverse /// sort order to return results in /// a integer representing the number of milliseconds to wait for results /// when false uses links and does not attempt to get the real object - /// keypair with a status message, and List + /// keypair with a status message, and List /// if the status message is retry you should check again in a bit is is currently loading /// links using RequestFetchInventoryCap /// @@ -764,8 +760,7 @@ namespace OpenMetaverse { string cap = owner == Client.Self.AgentID ? "FetchInventoryDescendents2" : "FetchLibDescendents2"; - if (Client.Settings.HTTP_INVENTORY && - Client.Network.CurrentSim.Caps != null && + if (Client.Network.CurrentSim.Caps != null && Client.Network.CurrentSim.Caps.CapabilityURI(cap) != null) { RequestFolderContentsCap(folder, owner, folders, items, order); @@ -909,8 +904,8 @@ namespace OpenMetaverse } catch (Exception exc) { - Logger.Log($"Failed to fetch inventory descendants: {exc.Message}\n" + - $"{exc.StackTrace.ToString()}", + Logger.Log($"Failed to fetch inventory descendants: {exc.Message}" + Environment.NewLine + + $"{exc.StackTrace}", Helpers.LogLevel.Warning, Client); foreach (var f in batch) { @@ -937,11 +932,11 @@ namespace OpenMetaverse } OSDMap req = new OSDMap(1) { ["folders"] = requestedFolders }; - request.BeginGetResponse(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } catch (Exception ex) { - Logger.Log($"Failed to fetch inventory descendants: {ex.Message}\n" + + Logger.Log($"Failed to fetch inventory descendants: {ex.Message}" + Environment.NewLine + $"{ex.StackTrace}", Helpers.LogLevel.Warning, Client); foreach (var f in batch) @@ -1778,31 +1773,29 @@ namespace OpenMetaverse CapsClient request = Client.Network.CurrentSim.Caps.CreateCapsClient("NewFileAgentInventory"); - if (request != null) - { - OSDMap query = new OSDMap - { - {"folder_id", OSD.FromUUID(folderID)}, - {"asset_type", OSD.FromString(Utils.AssetTypeToString(assetType))}, - {"inventory_type", OSD.FromString(Utils.InventoryTypeToString(invType))}, - {"name", OSD.FromString(name)}, - {"description", OSD.FromString(description)}, - {"everyone_mask", OSD.FromInteger((int) permissions.EveryoneMask)}, - {"group_mask", OSD.FromInteger((int) permissions.GroupMask)}, - {"next_owner_mask", OSD.FromInteger((int) permissions.NextOwnerMask)}, - {"expected_upload_cost", OSD.FromInteger(Client.Settings.UPLOAD_COST)} - }; - - // Make the request - request.OnComplete += CreateItemFromAssetResponse; - request.UserData = new object[] { callback, data, Client.Settings.CAPS_TIMEOUT, query }; - - request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); - } - else - { + if (request == null) { throw new Exception("NewFileAgentInventory capability is not currently available"); } + + OSDMap query = new OSDMap + { + {"folder_id", OSD.FromUUID(folderID)}, + {"asset_type", OSD.FromString(Utils.AssetTypeToString(assetType))}, + {"inventory_type", OSD.FromString(Utils.InventoryTypeToString(invType))}, + {"name", OSD.FromString(name)}, + {"description", OSD.FromString(description)}, + {"everyone_mask", OSD.FromInteger((int) permissions.EveryoneMask)}, + {"group_mask", OSD.FromInteger((int) permissions.GroupMask)}, + {"next_owner_mask", OSD.FromInteger((int) permissions.NextOwnerMask)}, + {"expected_upload_cost", OSD.FromInteger(Client.Settings.UPLOAD_COST)} + }; + + // Make the request + request.OnComplete += CreateItemFromAssetResponse; + request.UserData = new object[] { callback, data, Client.Settings.CAPS_TIMEOUT, query }; + + request.PostRequestAsync(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + } /// @@ -2009,7 +2002,7 @@ namespace OpenMetaverse ObjectID = objectID }; - request.BeginGetResponse(message.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(message.Serialize(),OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2163,7 +2156,7 @@ namespace OpenMetaverse // Make the request request.OnComplete += UploadInventoryAssetResponse; request.UserData = new object[] { new KeyValuePair(callback, data), notecardID }; - request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2196,7 +2189,7 @@ namespace OpenMetaverse // Make the request request.OnComplete += UploadInventoryAssetResponse; request.UserData = new object[] { new KeyValuePair(callback, data), notecardID }; - request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2224,7 +2217,7 @@ namespace OpenMetaverse // Make the request request.OnComplete += UploadInventoryAssetResponse; request.UserData = new object[] { new KeyValuePair(callback, data), gestureID }; - request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2253,7 +2246,7 @@ namespace OpenMetaverse 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); + request.PostRequestAsync(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2286,7 +2279,7 @@ namespace OpenMetaverse 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); + request.PostRequestAsync(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2563,7 +2556,7 @@ namespace OpenMetaverse /// /// Recurse inventory category and return folders and items. Does NOT contain parent folder being searched /// - /// Inventory category to recursively search + /// Inventory category to recursively search /// Owner of folder /// reference to list of categories /// reference to list of items @@ -3589,6 +3582,7 @@ namespace OpenMetaverse break; } imp.MessageBlock.BinaryBucket = args.FolderID.GetBytes(); + RequestFetchInventory(objectID, e.IM.ToAgentID); } else { @@ -3609,7 +3603,7 @@ namespace OpenMetaverse imp.MessageBlock.BinaryBucket = Utils.EmptyBytes; } - Client.Network.SendPacket(imp, e.Simulator); + Client.Network.SendPacket(imp, e.Simulator ?? Client.Network.CurrentSim); } catch (Exception ex) { @@ -3660,7 +3654,7 @@ namespace OpenMetaverse CapsClient upload = new CapsClient(new Uri(uploadURL), "CreateItemFromAsset"); upload.OnComplete += CreateItemFromAssetResponse; upload.UserData = new object[] { callback, itemData, millisecondsTimeout, request }; - upload.BeginGetResponse(itemData, "application/octet-stream", millisecondsTimeout); + upload.PostRequestAsync(itemData, "application/octet-stream", millisecondsTimeout); } else if (status == "complete") { @@ -3739,7 +3733,7 @@ namespace OpenMetaverse CapsClient upload = new CapsClient(uploadURL, "UploadItemResponse"); upload.OnComplete += UploadInventoryAssetResponse; upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; - upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); + upload.PostRequestAsync(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); } else { @@ -3810,7 +3804,7 @@ namespace OpenMetaverse CapsClient upload = new CapsClient(new Uri(uploadURL), "ScriptAgentInventoryResponse"); upload.OnComplete += UpdateScriptAgentInventoryResponse; upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; - upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); + upload.PostRequestAsync(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); } else if (status == "complete" && callback != null) { diff --git a/Assets/Plugins/LibreMetaverse/InventoryNode.cs b/Assets/Plugins/LibreMetaverse/InventoryNode.cs index d4dfb5d..7eb27f0 100644 --- a/Assets/Plugins/LibreMetaverse/InventoryNode.cs +++ b/Assets/Plugins/LibreMetaverse/InventoryNode.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -34,13 +35,12 @@ namespace OpenMetaverse { private InventoryBase data; private InventoryNode parent; - private UUID parentID; //used for de-seralization + private UUID parentID; //used for deseralization private InventoryNodeDictionary nodes; private bool needsUpdate = true; [NonSerialized] private object tag; - /// public InventoryBase Data { get => data; @@ -54,24 +54,35 @@ namespace OpenMetaverse set => tag = value; } - /// public InventoryNode Parent { get => parent; set => parent = value; } - /// - public UUID ParentID => parentID; + public UUID ParentID + { + get => parentID; + private set => parentID = value; + } - /// public InventoryNodeDictionary Nodes { - get { return nodes ?? (nodes = new InventoryNodeDictionary(this)); } + get => nodes ?? (nodes = new InventoryNodeDictionary(this)); set => nodes = value; } - public System.DateTime ModifyTime + /// + /// For inventory folder nodes specifies weather the folder needs to be + /// refreshed from the server + /// + public bool NeedsUpdate + { + get => needsUpdate; + set => needsUpdate = value; + } + + public DateTime ModifyTime { get { @@ -97,16 +108,6 @@ namespace OpenMetaverse 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() { } @@ -151,8 +152,8 @@ namespace OpenMetaverse 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 }); + System.Reflection.ConstructorInfo ctr = type.GetConstructor(new[] {typeof(SerializationInfo),typeof(StreamingContext)}); + if (ctr != null) data = (InventoryBase)ctr.Invoke(new object[] { info, ctxt }); } public override string ToString() diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs index 81974a4..43150b8 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs @@ -1,4 +1,6 @@ /* Copyright (c) 2008 Robert Adams + * Copyright (c) 2021-2022, Sjofn LLC. 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 @@ -37,8 +39,6 @@ using System.Collections.Generic; using System.IO; using OpenMetaverse.StructuredData; using LibreMetaverse.PrimMesher; -using OMV = OpenMetaverse; -using OMVR = OpenMetaverse.Rendering; //using Catnip.Drawing; using UnityEngine; @@ -48,7 +48,7 @@ namespace OpenMetaverse.Rendering /// Meshing code based on the Idealist Viewer (20081213). /// [RendererName("MeshmerizerR")] - public class MeshmerizerR : OMVR.IRendering + public class MeshmerizerR : IRendering { /// /// Generates a basic mesh structure from a primitive @@ -57,9 +57,9 @@ namespace OpenMetaverse.Rendering /// Primitive to generate the mesh from /// Level of detail to generate the mesh at /// The generated mesh or null on failure - public OMVR.SimpleMesh GenerateSimpleMesh(OMV.Primitive prim, OMVR.DetailLevel lod) + public SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod) { - LibreMetaverse.PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, false); + PrimMesh newPrim = GeneratePrimMesh(prim, lod, false); if (newPrim == null) return null; @@ -86,6 +86,44 @@ namespace OpenMetaverse.Rendering return mesh; } + + /// + /// Generates a basic mesh structure from a primitive, adding normals data. + /// A 'SimpleMesh' is just the prim's overall shape with no material information. + /// + /// Primitive to generate the mesh from + /// Level of detail to generate the mesh at + /// The generated mesh or null on failure + public SimpleMesh GenerateSimpleMeshWithNormals(Primitive prim, DetailLevel lod) { + PrimMesh newPrim = GeneratePrimMesh(prim, lod, true); + if(newPrim == null) + return null; + + SimpleMesh mesh = new SimpleMesh { + Path = new Path(), + Prim = prim, + Profile = new Profile(), + Vertices = new List(newPrim.coords.Count) + }; + + for(int i = 0; i < newPrim.coords.Count; i++) { + Coord c = newPrim.coords[i]; + // Also saving the normal within the vertice + Coord n = newPrim.normals[i]; + mesh.Vertices.Add(new Vertex {Position = new Vector3(c.X, c.Y, c.Z), Normal = new Vector3(n.X, n.Y, n.Z)}); + } + + mesh.Indices = new List(newPrim.faces.Count * 3); + foreach(var face in newPrim.faces) { + mesh.Indices.Add((ushort) face.v1); + mesh.Indices.Add((ushort) face.v2); + mesh.Indices.Add((ushort) face.v3); + } + + return mesh; + } + + /// /// Generates a basic mesh structure from a sculpted primitive. /// 'SimpleMesh's have a single mesh and no faces or material information. @@ -94,7 +132,9 @@ namespace OpenMetaverse.Rendering /// Sculpt texture /// Level of detail to generate the mesh at /// The generated mesh or null on failure - public SimpleMesh GenerateSimpleSculptMesh(Primitive prim, Texture2D sculptTexture, DetailLevel lod) + public SimpleMesh GenerateSimpleSculptMesh( Primitive prim, + Texture2D sculptTexture, + DetailLevel lod) { var faceted = GenerateFacetedSculptMesh(prim, sculptTexture, lod); @@ -130,41 +170,41 @@ namespace OpenMetaverse.Rendering /// The generated mesh public FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod) { - bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle); - LibreMetaverse.PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true); + bool isSphere = ((ProfileCurve)(prim.PrimData.profileCurve & 0x07) == ProfileCurve.HalfCircle); + PrimMesh newPrim = GeneratePrimMesh(prim, lod, true); if (newPrim == null) return null; - // copy the vertex information into OMVR.IRendering structures - var omvrmesh = new OMVR.FacetedMesh + // copy the vertex information into IRendering structures + var omvrmesh = new FacetedMesh { - Faces = new List(), + Faces = new List(), Prim = prim, - Profile = new OMVR.Profile + Profile = new Profile { - Faces = new List(), - Positions = new List() + Faces = new List(), + Positions = new List() }, - Path = new OMVR.Path {Points = new List()} + Path = new Path {Points = new List()} }; var indexer = newPrim.GetVertexIndexer(); for (int i = 0; i < indexer.numPrimFaces; i++) { - OMVR.Face oface = new OMVR.Face + Face oface = new Face { - Vertices = new List(), + Vertices = new List(), Indices = new List(), TextureFace = prim.Textures.GetFace((uint) i) }; for (int j = 0; j < indexer.viewerVertices[i].Count; j++) { - var vert = new OMVR.Vertex(); + var vert = new Vertex(); var m = indexer.viewerVertices[i][j]; vert.Position = new Vector3(m.v.X, m.v.Y, m.v.Z); vert.Normal = new Vector3(m.n.X, m.n.Y, m.n.Z); - vert.TexCoord = new OMV.Vector2(m.uv.U, 1.0f - m.uv.V); + vert.TexCoord = new Vector2(m.uv.U, 1.0f - m.uv.V); oface.Vertices.Add(vert); } @@ -189,25 +229,27 @@ namespace OpenMetaverse.Rendering /// routine since all the context for finding teh texture is elsewhere. /// /// The faceted mesh or null if can't do it - public OMVR.FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Texture2D scupltTexture, DetailLevel lod) + public FacetedMesh GenerateFacetedSculptMesh( Primitive prim, + Texture2D scupltTexture, + DetailLevel lod) { LibreMetaverse.PrimMesher.SculptMesh.SculptType smSculptType; switch (prim.Sculpt.Type) { case SculptType.Cylinder: - smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.cylinder; + smSculptType = SculptMesh.SculptType.cylinder; break; case SculptType.Plane: - smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.plane; + smSculptType = SculptMesh.SculptType.plane; break; case SculptType.Sphere: - smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.sphere; + smSculptType = SculptMesh.SculptType.sphere; break; case SculptType.Torus: - smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.torus; + smSculptType = SculptMesh.SculptType.torus; break; default: - smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.plane; + smSculptType = SculptMesh.SculptType.plane; break; } // The lod for sculpties is the resolution of the texture passed. @@ -216,40 +258,40 @@ namespace OpenMetaverse.Rendering int mesherLod = 32; // number used in Idealist viewer switch (lod) { - case OMVR.DetailLevel.Highest: + case DetailLevel.Highest: break; - case OMVR.DetailLevel.High: + case DetailLevel.High: break; - case OMVR.DetailLevel.Medium: + case DetailLevel.Medium: mesherLod /= 2; break; - case OMVR.DetailLevel.Low: + case DetailLevel.Low: mesherLod /= 4; break; } - LibreMetaverse.PrimMesher.SculptMesh newMesh = - new LibreMetaverse.PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert); + SculptMesh newMesh = + new SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert); int numPrimFaces = 1; // a scuplty has only one face - // copy the vertex information into OMVR.IRendering structures - FacetedMesh omvrmesh = new OMVR.FacetedMesh + // copy the vertex information into IRendering structures + FacetedMesh omvrmesh = new FacetedMesh { - Faces = new List(), + Faces = new List(), Prim = prim, - Profile = new OMVR.Profile + Profile = new Profile { - Faces = new List(), - Positions = new List() + Faces = new List(), + Positions = new List() }, - Path = new OMVR.Path {Points = new List()} + Path = new Path {Points = new List()} }; for (int ii = 0; ii < numPrimFaces; ii++) { - Face oface = new OMVR.Face + Face oface = new Face { - Vertices = new List(), + Vertices = new List(), Indices = new List(), TextureFace = prim.Textures.GetFace((uint) ii) }; @@ -257,7 +299,7 @@ namespace OpenMetaverse.Rendering for (int j = 0; j < faceVertices; j++) { - var vert = new OMVR.Vertex + var vert = new Vertex { Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z), Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z), @@ -286,12 +328,16 @@ namespace OpenMetaverse.Rendering /// /// Apply texture coordinate modifications from a - /// to a list of vertices + /// to a list of vertices /// /// Vertex list to modify texture coordinates for /// Center-point of the face /// Face texture parameters - public void TransformTexCoords(List vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace, Vector3 primScale) + /// Prim scale vector + public void TransformTexCoords( List vertices, + Vector3 center, + Primitive.TextureEntryFace teFace, + Vector3 primScale) { // compute trig stuff up front float cosineAngle = (float)Math.Cos(teFace.Rotation); @@ -346,7 +392,7 @@ namespace OpenMetaverse.Rendering // var facetedMesh = MeshSubMeshAsFacetedMesh(prim, meshParts["medium_lod"]): // 3. Get a simple mesh from one of the submeshes (good if just getting a physics version): // OSDMap meshParts = UnpackMesh(meshData); - // OMV.Mesh flatMesh = MeshSubMeshAsSimpleMesh(prim, meshParts["physics_mesh"]); + // Mesh flatMesh = MeshSubMeshAsSimpleMesh(prim, meshParts["physics_mesh"]); // // "physics_convex" is specially formatted so there is another routine to unpack // that section: @@ -364,9 +410,9 @@ namespace OpenMetaverse.Rendering /// routine since all the context for finding the data is elsewhere. /// /// The faceted mesh or null if can't do it - public OMVR.FacetedMesh GenerateFacetedMeshMesh(OMV.Primitive prim, byte[] meshData) + public FacetedMesh GenerateFacetedMeshMesh(Primitive prim, byte[] meshData) { - OMVR.FacetedMesh ret = null; + FacetedMesh ret = null; OSDMap meshParts = UnpackMesh(meshData); if (meshParts != null) { @@ -391,18 +437,18 @@ namespace OpenMetaverse.Rendering // A version of GenerateFacetedMeshMesh that takes LOD spec so it's similar in calling convention of // the other Generate* methods. - public OMVR.FacetedMesh GenerateFacetedMeshMesh(OMV.Primitive prim, byte[] meshData, OMVR.DetailLevel lod) { - OMVR.FacetedMesh ret = null; + public FacetedMesh GenerateFacetedMeshMesh(Primitive prim, byte[] meshData, DetailLevel lod) { + FacetedMesh ret = null; string partName = null; switch (lod) { - case OMVR.DetailLevel.Highest: + case DetailLevel.Highest: partName = "high_lod"; break; - case OMVR.DetailLevel.High: + case DetailLevel.High: partName = "medium_lod"; break; - case OMVR.DetailLevel.Medium: + case DetailLevel.Medium: partName = "low_lod"; break; - case OMVR.DetailLevel.Low: + case DetailLevel.Low: partName = "lowest_lod"; break; } if (partName != null) @@ -424,7 +470,7 @@ namespace OpenMetaverse.Rendering } // Convert a compressed submesh buffer into a FacetedMesh. - public FacetedMesh MeshSubMeshAsFacetedMesh(OMV.Primitive prim, byte[] compressedMeshData) + public FacetedMesh MeshSubMeshAsFacetedMesh(Primitive prim, byte[] compressedMeshData) { FacetedMesh ret = null; OSD meshOSD = Helpers.DecompressOSD(compressedMeshData); @@ -443,24 +489,27 @@ namespace OpenMetaverse.Rendering // Convert a compressed submesh buffer into a SimpleMesh. - public OMVR.SimpleMesh MeshSubMeshAsSimpleMesh(OMV.Primitive prim, byte[] compressedMeshData) + public SimpleMesh MeshSubMeshAsSimpleMesh(Primitive prim, byte[] compressedMeshData) { - OMVR.SimpleMesh ret = null; + SimpleMesh ret = null; OSD meshOSD = Helpers.DecompressOSD(compressedMeshData); OSDArray meshFaces = meshOSD as OSDArray; if (meshOSD != null) { ret = new SimpleMesh(); - foreach (OSD subMesh in meshFaces) + if (meshFaces != null) { - AddSubMesh(subMesh, ref ret); + foreach (OSD subMesh in meshFaces) + { + AddSubMesh(subMesh, ref ret); + } } } return ret; } - public List> MeshSubMeshAsConvexHulls(OMV.Primitive prim, byte[] compressedMeshData) + public List> MeshSubMeshAsConvexHulls(Primitive prim, byte[] compressedMeshData) { List> hulls = new List>(); try { @@ -529,7 +578,7 @@ namespace OpenMetaverse.Rendering } // Add the submesh to the passed SimpleMesh - private void AddSubMesh(OSD subMeshOsd, ref OMVR.SimpleMesh holdingMesh) { + private void AddSubMesh(OSD subMeshOsd, ref SimpleMesh holdingMesh) { if (subMeshOsd is OSDMap subMeshMap) { // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level @@ -544,7 +593,7 @@ namespace OpenMetaverse.Rendering } // Add the submesh to the passed FacetedMesh as a new face. - private void AddSubMesh(OMV.Primitive prim, int faceIndex, OSD subMeshOsd, ref OMVR.FacetedMesh holdingMesh) { + private void AddSubMesh(Primitive prim, int faceIndex, OSD subMeshOsd, ref FacetedMesh holdingMesh) { if (subMeshOsd is OSDMap subMesh) { // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level @@ -673,13 +722,11 @@ namespace OpenMetaverse.Rendering return indices; } - /// - /// Decodes mesh asset. + /// Decodes mesh asset. /// OSDMap of all of the submeshes in the mesh. The value of the submesh name /// is the uncompressed data for that mesh. /// The OSDMap is made up of the asset_header section (which includes a lot of stuff) - /// plus each of the submeshes unpacked into compressed byte arrays. - /// + /// plus each of the submeshes unpacked into compressed byte arrays. public OSDMap UnpackMesh(byte[] assetData) { OSDMap meshData = new OSDMap(); @@ -723,7 +770,7 @@ namespace OpenMetaverse.Rendering // Local routine to create a mesh from prim parameters. // Collects parameters and calls PrimMesher to create all the faces of the prim. - private LibreMetaverse.PrimMesher.PrimMesh GeneratePrimMesh(Primitive prim, DetailLevel lod, bool viewerMode) + private PrimMesh GeneratePrimMesh(Primitive prim, DetailLevel lod, bool viewerMode) { Primitive.ConstructionData primData = prim.PrimData; int sides = 4; @@ -734,14 +781,14 @@ namespace OpenMetaverse.Rendering bool isSphere = false; - if ((ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.Circle) + if ((ProfileCurve)(primData.profileCurve & 0x07) == ProfileCurve.Circle) { switch (lod) { - case OMVR.DetailLevel.Low: + case DetailLevel.Low: sides = 6; break; - case OMVR.DetailLevel.Medium: + case DetailLevel.Medium: sides = 12; break; default: @@ -749,18 +796,18 @@ namespace OpenMetaverse.Rendering break; } } - else if ((ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.EqualTriangle) + else if ((ProfileCurve)(primData.profileCurve & 0x07) == ProfileCurve.EqualTriangle) sides = 3; - else if ((ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle) + else if ((ProfileCurve)(primData.profileCurve & 0x07) == ProfileCurve.HalfCircle) { // half circle, prim is a sphere isSphere = true; switch (lod) { - case OMVR.DetailLevel.Low: + case DetailLevel.Low: sides = 6; break; - case OMVR.DetailLevel.Medium: + case DetailLevel.Medium: sides = 12; break; default: @@ -858,7 +905,7 @@ namespace OpenMetaverse.Rendering for (int j = 0; j < faceVertices; j++) { - var vert = new OMVR.Vertex + var vert = new Vertex { Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z), Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z), diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonData.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonData.cs index 64bfe96..51ce37d 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonData.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonData.cs @@ -122,18 +122,16 @@ namespace LitJson #region IDictionary Indexer object IDictionary.this[object key] { - get { - return EnsureDictionary ()[key]; - } + get => EnsureDictionary ()[key]; set { - if (! (key is String)) + if (! (key is string str)) throw new ArgumentException ( "The key has to be a string"); JsonData data = ToJsonData (value); - this[(string) key] = data; + this[str] = data; } } #endregion diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonMapper.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonMapper.cs index 4be58aa..6473767 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonMapper.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonMapper.cs @@ -30,8 +30,6 @@ namespace LitJson internal struct ArrayMetadata { private Type element_type; - private bool is_array; - private bool is_list; public Type ElementType { @@ -45,24 +43,15 @@ namespace LitJson set { element_type = value; } } - public bool IsArray { - get { return is_array; } - set { is_array = value; } - } + public bool IsArray { get; set; } - public bool IsList { - get { return is_list; } - set { is_list = value; } - } + public bool IsList { get; set; } } internal struct ObjectMetadata { private Type element_type; - private bool is_dictionary; - - private IDictionary properties; public Type ElementType { @@ -76,15 +65,9 @@ namespace LitJson set { element_type = value; } } - public bool IsDictionary { - get { return is_dictionary; } - set { is_dictionary = value; } - } + public bool IsDictionary { get; set; } - public IDictionary Properties { - get { return properties; } - set { properties = value; } - } + public IDictionary Properties { get; set; } } diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonReader.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonReader.cs index a327300..75052bb 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonReader.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/JSON/JsonReader.cs @@ -46,16 +46,13 @@ namespace LitJson 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 @@ -70,13 +67,13 @@ namespace LitJson set { lexer.AllowSingleQuotedStrings = value; } } - public bool EndOfInput => end_of_input; + public bool EndOfInput { get; private set; } - public bool EndOfJson => end_of_json; + public bool EndOfJson { get; private set; } - public JsonToken Token => token; + public JsonToken Token { get; private set; } - public object Value => token_value; + public object Value { get; private set; } #endregion @@ -112,8 +109,8 @@ namespace LitJson lexer = new Lexer (reader); - end_of_input = false; - end_of_json = false; + EndOfInput = false; + EndOfJson = false; this.reader = reader; reader_is_owned = owned; @@ -250,8 +247,8 @@ namespace LitJson double n_double; if (Double.TryParse (number, out n_double)) { - token = JsonToken.Double; - token_value = n_double; + Token = JsonToken.Double; + Value = n_double; return; } @@ -259,41 +256,41 @@ namespace LitJson int n_int32; if (Int32.TryParse (number, out n_int32)) { - token = JsonToken.Int; - token_value = n_int32; + Token = JsonToken.Int; + Value = n_int32; return; } long n_int64; if (Int64.TryParse (number, out n_int64)) { - token = JsonToken.Long; - token_value = n_int64; + Token = JsonToken.Long; + Value = n_int64; return; } // Shouldn't happen, but just in case, return something - token = JsonToken.Int; - token_value = 0; + Token = JsonToken.Int; + Value = 0; } private void ProcessSymbol () { if (current_symbol == '[') { - token = JsonToken.ArrayStart; + Token = JsonToken.ArrayStart; parser_return = true; } else if (current_symbol == ']') { - token = JsonToken.ArrayEnd; + Token = JsonToken.ArrayEnd; parser_return = true; } else if (current_symbol == '{') { - token = JsonToken.ObjectStart; + Token = JsonToken.ObjectStart; parser_return = true; } else if (current_symbol == '}') { - token = JsonToken.ObjectEnd; + Token = JsonToken.ObjectEnd; parser_return = true; } else if (current_symbol == '"') { @@ -303,22 +300,22 @@ namespace LitJson parser_return = true; } else { - if (token == JsonToken.None) - token = JsonToken.String; + if (Token == JsonToken.None) + Token = JsonToken.String; parser_in_string = true; } } else if (current_symbol == (int) ParserToken.CharSeq) { - token_value = lexer.StringValue; + Value = lexer.StringValue; } else if (current_symbol == (int) ParserToken.False) { - token = JsonToken.Boolean; - token_value = false; + Token = JsonToken.Boolean; + Value = false; parser_return = true; } else if (current_symbol == (int) ParserToken.Null) { - token = JsonToken.Null; + Token = JsonToken.Null; parser_return = true; } else if (current_symbol == (int) ParserToken.Number) { @@ -327,11 +324,11 @@ namespace LitJson parser_return = true; } else if (current_symbol == (int) ParserToken.Pair) { - token = JsonToken.PropertyName; + Token = JsonToken.PropertyName; } else if (current_symbol == (int) ParserToken.True) { - token = JsonToken.Boolean; - token_value = true; + Token = JsonToken.Boolean; + Value = true; parser_return = true; } @@ -339,7 +336,7 @@ namespace LitJson private bool ReadToken () { - if (end_of_input) + if (EndOfInput) return false; lexer.NextToken (); @@ -359,11 +356,11 @@ namespace LitJson public void Close () { - if (end_of_input) + if (EndOfInput) return; - end_of_input = true; - end_of_json = true; + EndOfInput = true; + EndOfJson = true; if (reader_is_owned) reader.Close (); @@ -373,11 +370,11 @@ namespace LitJson public bool Read () { - if (end_of_input) + if (EndOfInput) return false; - if (end_of_json) { - end_of_json = false; + if (EndOfJson) { + EndOfJson = false; automaton_stack.Clear (); automaton_stack.Push ((int) ParserToken.End); automaton_stack.Push ((int) ParserToken.Text); @@ -386,8 +383,8 @@ namespace LitJson parser_in_string = false; parser_return = false; - token = JsonToken.None; - token_value = null; + Token = JsonToken.None; + Value = null; if (! read_started) { read_started = true; @@ -400,7 +397,7 @@ namespace LitJson while (true) { if (parser_return) { if (automaton_stack.Peek () == (int) ParserToken.End) - end_of_json = true; + EndOfJson = true; return true; } diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/BinaryLLSD.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/BinaryLLSD.cs index 64c9412..78d1dd3 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/BinaryLLSD.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/BinaryLLSD.cs @@ -38,7 +38,6 @@ using System; using System.IO; -using System.Collections; using System.Collections.Generic; using System.Text; diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs index 00a80fd..9fe9d81 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -28,7 +29,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Xml; -using System.Xml.Schema; using System.Text; namespace OpenMetaverse.StructuredData @@ -38,46 +38,75 @@ 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(); + private static string linden_lab_loves_bad_pi = " - /// + /// Deserialize LLSD/XML stream /// - /// + /// a containing the serialized data + /// + public static OSD DeserializeLLSDXml(Stream xmlStream) + { + // XmlReader don't take no shit from nobody. Parse out Linden Lab's bad PI. + bool match = true; + for (int i = 0; i < linden_lab_loves_bad_pi.Length; ++i) + { + if (xmlStream.ReadByte() != linden_lab_loves_bad_pi[i]) + { + match = false; + break; + } + } + if (match) + { + // read until the linebreak > + while (xmlStream.ReadByte() != '\n') + { } + } else { + xmlStream.Seek(0, SeekOrigin.Begin); + } + + XmlReaderSettings settings = new XmlReaderSettings + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreComments = true, + IgnoreProcessingInstructions = false, + DtdProcessing = DtdProcessing.Ignore + }; + using (XmlReader xrd = XmlReader.Create(xmlStream)) + { + return DeserializeLLSDXml(xrd); + } + } + + /// + /// Deserialize LLSD/XML stream + /// + /// Data as a byte array /// public static OSD DeserializeLLSDXml(byte[] xmlData) { - using(XmlTextReader xrd = new XmlTextReader(new MemoryStream(xmlData, false))) - return DeserializeLLSDXml(xrd); - } - - public static OSD DeserializeLLSDXml(Stream xmlStream) - { - using(XmlTextReader xrd = new XmlTextReader(xmlStream)) - return DeserializeLLSDXml(xrd); + return DeserializeLLSDXml(new MemoryStream(xmlData, false)); } /// - /// + /// Deserialize LLSD/XML stream /// - /// + /// Serialized data as a /// public static OSD DeserializeLLSDXml(string xmlData) { byte[] bytes = Utils.StringToBytes(xmlData); - using(XmlTextReader xrd = new XmlTextReader(new MemoryStream(bytes, false))) - return DeserializeLLSDXml(xrd); + return DeserializeLLSDXml(bytes); } /// - /// + /// Deserialize LLSD/XML stream /// - /// + /// Serialized data as a /// - public static OSD DeserializeLLSDXml(XmlTextReader xmlData) + public static OSD DeserializeLLSDXml(XmlReader xmlData) { try { @@ -89,17 +118,18 @@ namespace OpenMetaverse.StructuredData return ret; } - catch + catch (XmlException ex) { + string exs = ex.ToString(); return new OSD(); } } /// - /// + /// Serialize an OSD object in LLSD/XML /// - /// - /// + /// OSD object to serialize + /// Serialized data as a byte aray public static byte[] SerializeLLSDXmlBytes(OSD data) { return Encoding.UTF8.GetBytes(SerializeLLSDXmlString(data)); @@ -113,7 +143,7 @@ namespace OpenMetaverse.StructuredData public static string SerializeLLSDXmlString(OSD data) { StringWriter sw = new StringWriter(); - using(XmlTextWriter writer = new XmlTextWriter(sw)) + using (XmlTextWriter writer = new XmlTextWriter(sw)) { writer.Formatting = Formatting.None; @@ -143,7 +173,7 @@ namespace OpenMetaverse.StructuredData /// /// /// - public static void SerializeLLSDXmlElement(XmlTextWriter writer, OSD data) + public static void SerializeLLSDXmlElement(XmlWriter writer, OSD data) { switch (data.Type) { @@ -224,59 +254,12 @@ namespace OpenMetaverse.StructuredData } } - /// - /// - /// - /// - /// - /// - 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); - - using(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) + private static OSD ParseLLSDXmlElement(XmlReader reader) { SkipWhitespace(reader); @@ -464,7 +447,7 @@ namespace OpenMetaverse.StructuredData return ret; } - private static OSDMap ParseLLSDXmlMap(XmlTextReader reader) + private static OSDMap ParseLLSDXmlMap(XmlReader reader) { if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "map") throw new NotImplementedException("Expected "); @@ -507,7 +490,7 @@ namespace OpenMetaverse.StructuredData return map; } - private static OSDArray ParseLLSDXmlArray(XmlTextReader reader) + private static OSDArray ParseLLSDXmlArray(XmlReader reader) { if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "array") throw new OSDException("Expected "); @@ -539,7 +522,7 @@ namespace OpenMetaverse.StructuredData return array; } - private static void SkipWhitespace(XmlTextReader reader) + private static void SkipWhitespace(XmlReader reader) { while ( reader.NodeType == XmlNodeType.Comment || @@ -550,121 +533,5 @@ namespace OpenMetaverse.StructuredData reader.Read(); } } - - private static void CreateLLSDXmlSchema() - { - if (XmlSchema == null) - { - #region XSD - const 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 = - $"Line: {XmlTextReader.LineNumber} - Position: {XmlTextReader.LinePosition} - {args.Message}"; - - if (LastXmlErrors == string.Empty) - LastXmlErrors = error; - else - LastXmlErrors += Environment.NewLine + error; - } } } diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/StructuredData.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/StructuredData.cs index 4ba93bf..61a5a3c 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/StructuredData.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.StructuredData/StructuredData.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -892,6 +893,11 @@ namespace OpenMetaverse.StructuredData return new OSDMap(new Dictionary(_mMap)); } + public Hashtable ToHashtable() + { + return new Hashtable(_mMap); + } + #region IDictionary Implementation public int Count => _mMap.Count; @@ -1124,6 +1130,11 @@ namespace OpenMetaverse.StructuredData return OSDParser.SerializeJsonString(this, true); } + public ArrayList ToArrayList() + { + return new ArrayList(_mArray); + } + #region IList Implementation public int Count => _mArray.Count; @@ -1246,7 +1257,7 @@ namespace OpenMetaverse.StructuredData public static OSD Deserialize(Stream stream) { - if (!stream.CanSeek) throw new OSDException("Cannot deserialize structured data from unseekable streams"); + if (!stream.CanSeek) { throw new OSDException("Cannot deserialize structured data from unseekable streams"); } byte[] headerData = new byte[14]; stream.Read(headerData, 0, 14); diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/CRC32.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/CRC32.cs index eb32dee..8811889 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/CRC32.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/CRC32.cs @@ -24,8 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; - namespace OpenMetaverse { public class CRC32 diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Quaternion.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Quaternion.cs index f4ffdf0..1dae88a 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Quaternion.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Quaternion.cs @@ -321,6 +321,15 @@ namespace OpenMetaverse //} } + /// + /// Convert quaternion to euler angles vector + /// + /// + public Vector3 ToEulerVector() { + GetEulerAngles(out float r, out float p, out float y); + return new Vector3(r, p, y); + } + /// /// Convert this quaternion to an angle around an axis /// diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Ray.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Ray.cs new file mode 100644 index 0000000..18fd694 --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Ray.cs @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2016, openmetaverse.co + * 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.co 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. + */ + +namespace OpenMetaverse +{ + public struct Ray + { + public Vector3 Origin; + public Vector3 Direction; + + public Ray(Vector3 origin, Vector3 direction) + { + Origin = origin; + Direction = direction; + } + } +} diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Ray.cs.meta b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Ray.cs.meta new file mode 100644 index 0000000..5832707 --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/Ray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dfd7f6aa761fa8344ae0221058b55cf3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/TokenBucket.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/TokenBucket.cs index 2b1b381..3dab44a 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/TokenBucket.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/TokenBucket.cs @@ -55,10 +55,7 @@ namespace OpenMetaverse /// parent. The parent bucket will limit the aggregate bandwidth of all /// of its children buckets /// - public TokenBucket Parent - { - get { return parent; } - } + public TokenBucket Parent => parent; /// /// Maximum burst rate in bytes per second. This is the maximum number @@ -66,8 +63,8 @@ namespace OpenMetaverse /// public int MaxBurst { - get { return maxBurst; } - set { maxBurst = (value >= 0 ? value : 0); } + get => maxBurst; + set => maxBurst = (value >= 0 ? value : 0); } /// @@ -75,11 +72,11 @@ namespace OpenMetaverse /// 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 + /// is called, at the granularity of /// the system tick interval (typically around 15-22ms) public int DripRate { - get { return tokensPerMS * 1000; } + get => tokensPerMS * 1000; set { if (value == 0) @@ -95,13 +92,10 @@ namespace OpenMetaverse /// 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 + /// enough tokens for a request, will /// return false regardless of the content of this bucket /// - public int Content - { - get { return content; } - } + public int Content => content; #endregion Properties diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UUID.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UUID.cs index d6bf43b..91ac438 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UUID.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UUID.cs @@ -297,9 +297,8 @@ namespace OpenMetaverse /// True if the object is a UUID and both UUIDs are equal public override bool Equals(object o) { - if (!(o is UUID)) return false; + if (!(o is UUID uuid)) return false; - UUID uuid = (UUID)o; return Guid == uuid.Guid; } diff --git a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UtilsConversions.cs b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UtilsConversions.cs index 0211354..22bdeb3 100644 --- a/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UtilsConversions.cs +++ b/Assets/Plugins/LibreMetaverse/LibreMetaverse.Types/UtilsConversions.cs @@ -25,6 +25,7 @@ */ using System; +using System.Collections; using System.Linq; using System.Net; using System.Text; @@ -654,7 +655,7 @@ namespace OpenMetaverse /// 0x7fffffff public static string UIntToHexString(uint i) { - return string.Format("{0:x8}", i); + return $"{i:x8}"; } /// @@ -680,7 +681,7 @@ namespace OpenMetaverse private static string GetString(byte[] bytes, int index, int count) { - string cnv = UTF8Encoding.UTF8.GetString(bytes, index, count); + string cnv = Encoding.UTF8.GetString(bytes, index, count); return InternStrings ? string.Intern(cnv) : cnv; } @@ -729,7 +730,8 @@ namespace OpenMetaverse if (j != 0) output.Append(' '); - output.Append(String.Format("{0:X2}", bytes[i + j])); + //output.Append(String.Format("{0:X2}", bytes[i + j])); + output.Append($"{bytes[i + j]:X2}"); } } } @@ -744,9 +746,11 @@ namespace OpenMetaverse /// A null-terminated UTF8 byte array public static byte[] StringToBytes(string str) { - if (String.IsNullOrEmpty(str)) { return EmptyBytes; } - if (!str.EndsWith("\0")) { str += "\0"; } - return UTF8Encoding.UTF8.GetBytes(str); + if (string.IsNullOrEmpty(str)) { return EmptyBytes; } + // HACK: Say it ain't so .NET5 + return str.EndsWith("\0", StringComparison.Ordinal) + ? Encoding.UTF8.GetBytes(str) + : Encoding.UTF8.GetBytes(str + '\0'); } /// @@ -767,9 +771,9 @@ namespace OpenMetaverse char c; // remove all non A-F, 0-9, characters - for (int i = 0; i < hexString.Length; i++) + foreach (var str in hexString) { - c = hexString[i]; + c = str; if (IsHexDigit(c)) stripped.Append(c); } @@ -801,14 +805,14 @@ namespace OpenMetaverse /// /// Character to test /// true if hex digit, false if not - private static bool IsHexDigit(Char c) + private static bool IsHexDigit(char c) { const int numA = 65; const int num0 = 48; int numChar; - c = Char.ToUpper(c); + c = char.ToUpper(c); numChar = Convert.ToInt32(c); if (numChar >= numA && numChar < (numA + 6)) @@ -1217,9 +1221,7 @@ namespace OpenMetaverse /// Second value public static void Swap(ref T lhs, ref T rhs) { - T temp = lhs; - lhs = rhs; - rhs = temp; + (lhs, rhs) = (rhs, lhs); } /// diff --git a/Assets/Plugins/LibreMetaverse/LocationParser.cs b/Assets/Plugins/LibreMetaverse/LocationParser.cs new file mode 100644 index 0000000..8592489 --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/LocationParser.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022, Sjofn, LLC + * 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.co 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 LocationParser + { + public string Sim { get; } + public int X { get; } + public int Y { get; } + public int Z { get; } + + public LocationParser(string location) + { + if (location == null ) { throw new ArgumentNullException("Location cannot be null."); } + if (location.Length == 0) { throw new ArgumentException("Location cannot be empty."); } + + string toParse; + if (location.StartsWith("secondlife://")) { toParse = location.Substring(13); } + else if (location.StartsWith("uri:")) { toParse = location.Substring(4); } + else { toParse = location; } + + string[] elements = toParse.Split('/'); + Sim = elements[0]; + int parsed; + X = (elements.Length > 1 && int.TryParse(elements[1], out parsed)) ? parsed : 128; + Y = (elements.Length > 2 && int.TryParse(elements[2], out parsed)) ? parsed : 128; + Z = (elements.Length > 3 && int.TryParse(elements[3], out parsed)) ? parsed : 0; + } + + public string GetRawLocation() + { + return $"{Sim}/{X}/{Y}/{Z}"; + } + + public string GetSlurl() + { + return $"secondlife://{Sim}/{X}/{Y}/{Z}/"; + } + + public string GetStartLocationUri() + { + return $"uri:{Sim}&{X}&{Y}&{Z}"; + } + } +} diff --git a/Assets/Plugins/LibreMetaverse/LocationParser.cs.meta b/Assets/Plugins/LibreMetaverse/LocationParser.cs.meta new file mode 100644 index 0000000..3abf2e9 --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/LocationParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c55f03914703744682d029a8cfbceda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LibreMetaverse/Login.cs b/Assets/Plugins/LibreMetaverse/Login.cs index 3e8cecc..782b269 100644 --- a/Assets/Plugins/LibreMetaverse/Login.cs +++ b/Assets/Plugins/LibreMetaverse/Login.cs @@ -1,6 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co - * Copyright (c) 2019-2020, Sjofn, LLC + * Copyright (c) 2019-2022, Sjofn, LLC * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -35,7 +35,6 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; -using System.Net.NetworkInformation; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -151,6 +150,10 @@ namespace OpenMetaverse /// internally in the library and is never sent over the wire internal UUID LoginID; + /// LoginLocation used to set the starting region and location (overrides Start) example: "Tentacles/128/64/109" + /// Leave empty to use the starting location + public string LoginLocation; + /// /// Default constructor, initializes sane default values /// @@ -220,7 +223,8 @@ namespace OpenMetaverse /// Password /// Login channel (application name) /// Client version, should be application name + version number - public LoginParams(GridClient client, string firstName, string lastName, string password, string channel, string version) + public LoginParams(GridClient client, string firstName, string lastName, string password, + string channel, string version) : this() { URI = client.Settings.LOGIN_SERVER; @@ -239,10 +243,11 @@ namespace OpenMetaverse /// Login first name /// Login last name /// Password - /// Login channnel (application name) + /// Login channel (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) + public LoginParams(GridClient client, string firstName, string lastName, string password, + string channel, string version, string loginURI) : this(client, firstName, lastName, password, channel, version) { URI = loginURI; @@ -256,6 +261,13 @@ namespace OpenMetaverse public int BuddyRightsHas; } + public struct HomeInfo + { + public ulong RegionHandle; + public Vector3 Position; + public Vector3 LookAt; + } + /// /// The decoded data returned from the login server after a successful login /// @@ -268,18 +280,21 @@ namespace OpenMetaverse public string Reason; /// Login message of the day public string Message; + public bool FirstLogin; public UUID AgentID; public UUID SessionID; public UUID SecureSessionID; public string FirstName; public string LastName; public string StartLocation; + public string AccountType; /// M or PG, also agent_region_access and agent_access_max public string AgentAccess; + public string AgentAccessMax; + public string AgentRegionAccess; + public string InitialOutfit; public Vector3 LookAt; - public ulong HomeRegion; - public Vector3 HomePosition; - public Vector3 HomeLookAt; + public HomeInfo Home; public int CircuitCode; public uint RegionX; public uint RegionY; @@ -289,6 +304,18 @@ namespace OpenMetaverse public BuddyListEntry[] BuddyList; public int SecondsSinceEpoch; public string UDPBlacklist; + public int MaxAgentGroups; + public string OpenIDUrl; + public string AgentAppearanceServiceURL; + public string MapServerUrl; + public string SnapshotConfigUrl; + public uint COFVersion; + public Hashtable AccountLevelBenefits; + public Hashtable PremiumPackages; + public ArrayList ClassifiedCategories; + public ArrayList EventCategories; + public ArrayList GlobalTextures; + public ArrayList UiConfig; #region Inventory @@ -297,6 +324,7 @@ namespace OpenMetaverse public InventoryFolder[] InventorySkeleton; public InventoryFolder[] LibrarySkeleton; public UUID LibraryOwner; + public Dictionary Gestures; #endregion @@ -309,19 +337,6 @@ namespace OpenMetaverse #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; - public Dictionary Gestures; - /// /// Parse LLSD Login Reply Data /// @@ -336,10 +351,12 @@ namespace OpenMetaverse 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('"'); + FirstName = ParseString("first_name", reply).Trim('"').Trim(); // lol but necessary, unfortunately. + LastName = ParseString("last_name", reply).Trim('"').Trim(); StartLocation = ParseString("start_location", reply); AgentAccess = ParseString("agent_access", reply); + AgentAccessMax = ParseString("agent_access_max", reply); + AgentRegionAccess = ParseString("agent_region_access", reply); LookAt = ParseVector3("look_at", reply); Reason = ParseString("reason", reply); Message = ParseString("message", reply); @@ -349,40 +366,59 @@ namespace OpenMetaverse } catch (OSDException e) { - Logger.Log("Login server returned (some) invalid data: " + e.Message, Helpers.LogLevel.Warning); + Logger.Log("Login server returned (some) invalid data", Helpers.LogLevel.Warning, e); } // Home - OSD osdHome = OSDParser.DeserializeLLSDNotation(reply["home"].AsString()); - - if (osdHome.Type == OSDType.Map) + if (reply.ContainsKey("home_info")) { - var home = (OSDMap)osdHome; - - OSD homeRegion; - if (home.TryGetValue("region_handle", out homeRegion) && homeRegion.Type == OSDType.Array) + if (reply["home_info"].Type == OSDType.Map) { - OSDArray homeArray = (OSDArray)homeRegion; - HomeRegion = homeArray.Count == 2 - ? Utils.UIntsToLong((uint)homeArray[0].AsInteger(), (uint)homeArray[1].AsInteger()) - : 0; - } + var map = (OSDMap)reply["home_info"]; + Home.Position = ParseVector3("position", map); + Home.LookAt = ParseVector3("look_at", map); - HomePosition = ParseVector3("position", home); - HomeLookAt = ParseVector3("look_at", home); + var coords = (OSDArray)OSDParser.DeserializeLLSDNotation(map["region_handle"].ToString()); + if (coords.Type == OSDType.Array) + { + Home.RegionHandle = (coords.Count == 2) + ? Utils.UIntsToLong((uint)coords[0].AsInteger(), (uint)coords[1].AsInteger()) : 0; + } + } + } + else if (reply.ContainsKey("home")) + { + var osdHome = OSDParser.DeserializeLLSDNotation(reply["home"].AsString()); + + if (osdHome.Type == OSDType.Map) + { + var home = (OSDMap)osdHome; + + OSD homeRegion; + if (home.TryGetValue("region_handle", out homeRegion) && homeRegion.Type == OSDType.Array) + { + var homeArray = (OSDArray)homeRegion; + Home.RegionHandle = homeArray.Count == 2 + ? Utils.UIntsToLong((uint)homeArray[0].AsInteger(), (uint)homeArray[1].AsInteger()) + : 0; + } + + Home.Position = ParseVector3("position", home); + Home.LookAt = ParseVector3("look_at", home); + } } else { - HomeRegion = 0; - HomePosition = Vector3.Zero; - HomeLookAt = Vector3.Zero; + Home.RegionHandle = 0; + Home.Position = Vector3.Zero; + Home.LookAt = Vector3.Zero; } CircuitCode = (int)ParseUInt("circuit_code", reply); RegionX = ParseUInt("region_x", reply); RegionY = ParseUInt("region_y", reply); SimPort = (ushort)ParseUInt("sim_port", reply); - string simIP = ParseString("sim_ip", reply); + var simIP = ParseString("sim_ip", reply); IPAddress.TryParse(simIP, out SimIP); SeedCapability = ParseString("seed_capability", reply); @@ -390,14 +426,14 @@ namespace OpenMetaverse OSD buddyLLSD; if (reply.TryGetValue("buddy-list", out buddyLLSD) && buddyLLSD.Type == OSDType.Array) { - List buddys = new List(); - OSDArray buddyArray = (OSDArray)buddyLLSD; - foreach (OSD t in buddyArray) + var buddys = new List(); + var buddyArray = (OSDArray)buddyLLSD; + foreach (var t in buddyArray) { if (t.Type == OSDType.Map) { - BuddyListEntry bud = new BuddyListEntry(); - OSDMap buddy = (OSDMap)t; + var bud = new BuddyListEntry(); + var buddy = (OSDMap)t; bud.BuddyId = buddy["buddy_id"].AsString(); bud.BuddyRightsGiven = (int)ParseUInt("buddy_rights_given", buddy); @@ -417,6 +453,63 @@ namespace OpenMetaverse LibraryOwner = ParseMappedUUID("inventory-lib-owner", "agent_id", reply); LibraryRoot = ParseMappedUUID("inventory-lib-root", "folder_id", reply); LibrarySkeleton = ParseInventorySkeleton("inventory-skel-lib", reply); + + if (reply.ContainsKey("account_level_benefits")) + { + if (reply["account_level_benefits"].Type == OSDType.Map) + { + AccountLevelBenefits = ((OSDMap)reply["account_level_benefits"]).ToHashtable(); + } + } + + if (reply.ContainsKey("classified_categories")) + { + if (reply["classified_categories"].Type == OSDType.Array) + { + ClassifiedCategories = ((OSDArray)reply["classified_categories"]).ToArrayList(); + } + } + + if (reply.ContainsKey("event_categories")) + { + if (reply["event_categories"].Type == OSDType.Array) + { + EventCategories = ((OSDArray)reply["event_categories"]).ToArrayList(); + } + } + + if (reply.ContainsKey("global-textures")) + { + if (reply["global-textures"].Type == OSDType.Array) + { + GlobalTextures = ((OSDArray)reply["global-textures"]).ToArrayList(); + } + } + + if (reply.ContainsKey("premium_packages")) + { + if (reply["premium_packages"].Type == OSDType.Map) + { + PremiumPackages = ((OSDMap)reply["premium_packages"]).ToHashtable(); + } + } + + if (reply.ContainsKey("ui-config")) + { + if (reply["ui-config"].Type == OSDType.Array) + { + UiConfig = ((OSDArray)reply["ui-config"]).ToArrayList(); + } + } + + if (reply.ContainsKey("max-agent-groups")) + { + MaxAgentGroups = (int)ParseUInt("max-agent-groups", reply); + } + else + { + MaxAgentGroups = -1; + } } public void Parse(Hashtable reply) @@ -454,45 +547,78 @@ namespace OpenMetaverse { Logger.Log("Login server returned (some) invalid data: " + e.Message, Helpers.LogLevel.Warning); } - if (!Success) - return; + if (!Success) { return; } - // Home - if (reply.ContainsKey("home")) + // HomeInfo + try { - OSD osdHome = OSDParser.DeserializeLLSDNotation(reply["home"].ToString()); - - if (osdHome.Type == OSDType.Map) + if (reply.ContainsKey("home_info")) { - var home = (OSDMap)osdHome; - - OSD homeRegion; - if (home.TryGetValue("region_handle", out homeRegion) && homeRegion.Type == OSDType.Array) + if (reply?["home_info"] is Hashtable map) { - OSDArray homeArray = (OSDArray)homeRegion; - if (homeArray.Count == 2) - HomeRegion = Utils.UIntsToLong((uint)homeArray[0].AsInteger(), - (uint)homeArray[1].AsInteger()); - else - HomeRegion = 0; - } + Home.Position = ParseVector3("position", map); + Home.LookAt = ParseVector3("look_at", map); - HomePosition = ParseVector3("position", home); - HomeLookAt = ParseVector3("look_at", home); + var coords = (OSDArray)OSDParser.DeserializeLLSDNotation(map["region_handle"].ToString()); + if (coords.Type == OSDType.Array) + { + Home.RegionHandle = (coords.Count == 2) + ? Utils.UIntsToLong((uint)coords[0].AsInteger(), (uint)coords[1].AsInteger()) : 0; + } + } } - } - else + + // Home + if (Home.RegionHandle == 0 && reply.ContainsKey("home")) + { + if (reply?["home"] is Hashtable map) + { + Home.Position = ParseVector3("position", map); + Home.LookAt = ParseVector3("look_at", map); + + var coords = (OSDArray)OSDParser.DeserializeLLSDNotation(map["region_handle"].ToString()); + if (coords.Type == OSDType.Array) + { + Home.RegionHandle = (coords.Count == 2) + ? Utils.UIntsToLong((uint)coords[0].AsInteger(), (uint)coords[1].AsInteger()) : 0; + } + } + else if (reply?["home"] is string osdString) + { + var osdHome = OSDParser.DeserializeLLSDNotation(reply["home"].ToString()); + + if (osdHome.Type == OSDType.Map) + { + var home = (OSDMap)osdHome; + + OSD homeRegion; + if (home.TryGetValue("region_handle", out homeRegion) && homeRegion.Type == OSDType.Array) + { + var coords = (OSDArray)homeRegion; + Home.RegionHandle = (coords.Count == 2) + ? Utils.UIntsToLong((uint)coords[0].AsInteger(), (uint)coords[1].AsInteger()) : 0; + + } + Home.Position = ParseVector3("position", home); + Home.LookAt = ParseVector3("look_at", home); + } + } + else + { + throw new Exception("Could not parse 'home' in Login Response"); + } + } + } catch (Exception ex) { - HomeRegion = 0; - HomePosition = Vector3.Zero; - HomeLookAt = Vector3.Zero; + Logger.Log("Could not parse home info from login response. Setting nil", Helpers.LogLevel.Warning, ex); + Home = new HomeInfo(); } CircuitCode = (int)ParseUInt("circuit_code", reply); RegionX = ParseUInt("region_x", reply); RegionY = ParseUInt("region_y", reply); SimPort = (ushort)ParseUInt("sim_port", reply); - string simIP = ParseString("sim_ip", reply); + var simIP = ParseString("sim_ip", reply); IPAddress.TryParse(simIP, out SimIP); SeedCapability = ParseString("seed_capability", reply); @@ -504,14 +630,14 @@ namespace OpenMetaverse var buddyArray = (ArrayList)reply["buddy-list"]; foreach (var t in buddyArray) { - if (!(t is Hashtable)) continue; + if (!(t is Hashtable buddy)) continue; - var bud = new BuddyListEntry(); - var buddy = (Hashtable)t; - - bud.BuddyId = ParseString("buddy_id", buddy); - bud.BuddyRightsGiven = (int)ParseUInt("buddy_rights_given", buddy); - bud.BuddyRightsHas = (int)ParseUInt("buddy_rights_has", buddy); + var bud = new BuddyListEntry + { + BuddyId = ParseString("buddy_id", buddy), + BuddyRightsGiven = (int)ParseUInt("buddy_rights_given", buddy), + BuddyRightsHas = (int)ParseUInt("buddy_rights_has", buddy) + }; buddys.Add(bud); } @@ -527,11 +653,61 @@ namespace OpenMetaverse LibraryOwner = ParseMappedUUID("inventory-lib-owner", "agent_id", reply); LibraryRoot = ParseMappedUUID("inventory-lib-root", "folder_id", reply); LibrarySkeleton = ParseInventorySkeleton("inventory-skel-lib", reply); + + AccountType = ParseString("account_type", reply); + AgentAppearanceServiceURL = ParseString("agent_appearance_service", reply); + COFVersion = ParseUInt("cof_version", reply); + MapServerUrl = ParseString("map-server-url", reply); + OpenIDUrl = ParseString("openid_url", reply); + SnapshotConfigUrl = ParseString("snapshot_config_url", reply); + UDPBlacklist = ParseString("udp_blacklist", reply); - // UDP Blacklist - if (reply.ContainsKey("udp_blacklist")) + if (reply.ContainsKey("account_level_benefits")) { - UDPBlacklist = ParseString("udp_blacklist", reply); + if (reply?["account_level_benefits"] is Hashtable) + { + AccountLevelBenefits = (Hashtable)reply["account_level_benefits"]; + } + } + + if (reply.ContainsKey("classified_categories")) + { + if (reply?["classified_categories"] is ArrayList) + { + ClassifiedCategories = (ArrayList)reply["classified_categories"]; + } + } + + if (reply.ContainsKey("event_categories")) + { + if (reply?["event_categories"] is ArrayList) + { + EventCategories = (ArrayList)reply["event_categories"]; + } + } + + if (reply.ContainsKey("global-textures")) + { + if (reply?["global-textures"] is ArrayList) + { + GlobalTextures = (ArrayList)reply["global-textures"]; + } + } + + if (reply.ContainsKey("premium_packages")) + { + if (reply?["premium_packages"] is Hashtable) + { + PremiumPackages = (Hashtable)reply["premium_packages"]; + } + } + + if (reply.ContainsKey("ui-config")) + { + if (reply?["ui-config"] is ArrayList) + { + UiConfig = (ArrayList)reply["ui-config"]; + } } if (reply.ContainsKey("max-agent-groups")) @@ -543,21 +719,6 @@ namespace OpenMetaverse 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) @@ -565,9 +726,8 @@ namespace OpenMetaverse var array = (ArrayList)reply["initial-outfit"]; foreach (var t in array) { - if (!(t is Hashtable)) continue; + if (!(t is Hashtable map)) continue; - var map = (Hashtable)t; InitialOutfit = ParseString("folder_name", map); } } @@ -605,9 +765,8 @@ namespace OpenMetaverse var array = (ArrayList)reply["login-flags"]; foreach (var t in array) { - if (!(t is Hashtable)) continue; + if (!(t is Hashtable map)) continue; - var map = (Hashtable)t; FirstLogin = ParseString("ever_logged_in", map) == "N"; } } @@ -651,12 +810,12 @@ namespace OpenMetaverse public static string ParseString(string key, OSDMap reply) { OSD osd; - return reply.TryGetValue(key, out osd) ? osd.AsString() : String.Empty; + return reply.TryGetValue(key, out osd) ? osd.AsString() : string.Empty; } public static string ParseString(string key, Hashtable reply) { - return reply.ContainsKey(key) ? $"{reply[key]}" : String.Empty; + return reply.ContainsKey(key) ? $"{reply[key]}" : string.Empty; } public static Vector3 ParseVector3(string key, OSDMap reply) @@ -669,7 +828,7 @@ namespace OpenMetaverse case OSDType.Array: return ((OSDArray)osd).AsVector3(); case OSDType.String: - OSDArray array = (OSDArray)OSDParser.DeserializeLLSDNotation(osd.AsString()); + var array = (OSDArray)OSDParser.DeserializeLLSDNotation(osd.AsString()); return array.AsVector3(); } @@ -687,16 +846,16 @@ namespace OpenMetaverse 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); + float.TryParse((string)list[0], out x); + float.TryParse((string)list[1], out y); + float.TryParse((string)list[2], out z); return new Vector3(x, y, z); } } else if (value is string str) { - OSDArray array = (OSDArray)OSDParser.DeserializeLLSDNotation(str); + var array = (OSDArray)OSDParser.DeserializeLLSDNotation(str); return array.AsVector3(); } @@ -706,12 +865,12 @@ namespace OpenMetaverse public static UUID ParseMappedUUID(string key, string key2, OSDMap reply) { OSD folderOSD; - if (!reply.TryGetValue(key, out folderOSD) || folderOSD.Type != OSDType.Array) { return UUID.Zero; } + if (!reply.TryGetValue(key, out folderOSD) || folderOSD.Type != OSDType.Array) {return UUID.Zero;} - OSDArray array = (OSDArray)folderOSD; + var array = (OSDArray)folderOSD; if (array.Count == 1 && array[0].Type == OSDType.Map) { - OSDMap map = (OSDMap)array[0]; + var map = (OSDMap)array[0]; OSD folder; if (map.TryGetValue(key2, out folder)) return folder.AsUUID(); @@ -722,7 +881,7 @@ namespace OpenMetaverse public static UUID ParseMappedUUID(string key, string key2, Hashtable reply) { - if (!reply.ContainsKey(key) || !(reply[key] is ArrayList)) { return UUID.Zero; } + if (!reply.ContainsKey(key) || !(reply[key] is ArrayList)) {return UUID.Zero;} var array = (ArrayList)reply[key]; if (array.Count == 1 && array[0] is Hashtable) @@ -736,25 +895,25 @@ namespace OpenMetaverse public static InventoryFolder[] ParseInventoryFolders(string key, UUID owner, OSDMap reply) { - List folders = new List(); + var folders = new List(); OSD skeleton; - if (!reply.TryGetValue(key, out skeleton) || skeleton.Type != OSDType.Array) { return folders.ToArray(); } + if (!reply.TryGetValue(key, out skeleton) || skeleton.Type != OSDType.Array) {return folders.ToArray();} - OSDArray array = (OSDArray)skeleton; + var array = (OSDArray)skeleton; folders.AddRange(from t in array - where t.Type == OSDType.Map - select (OSDMap)t + where t.Type == OSDType.Map + select (OSDMap)t into map - select new InventoryFolder(map["folder_id"].AsUUID()) - { - PreferredType = (FolderType)map["type_default"].AsInteger(), - Version = map["version"].AsInteger(), - OwnerID = owner, - ParentUUID = map["parent_id"].AsUUID(), - Name = map["name"].AsString() - }); + select new InventoryFolder(map["folder_id"].AsUUID()) + { + PreferredType = (FolderType)map["type_default"].AsInteger(), + Version = map["version"].AsInteger(), + OwnerID = owner, + ParentUUID = map["parent_id"].AsUUID(), + Name = map["name"].AsString() + }); return folders.ToArray(); } @@ -764,19 +923,19 @@ namespace OpenMetaverse var folders = new List(); OSD skeleton; - if (!reply.TryGetValue(key, out skeleton) || skeleton.Type != OSDType.Array) { return folders.ToArray(); } - OSDArray array = (OSDArray)skeleton; + if (!reply.TryGetValue(key, out skeleton) || skeleton.Type != OSDType.Array) {return folders.ToArray();} + var array = (OSDArray)skeleton; folders.AddRange(from t in array - where t.Type == OSDType.Map - select (OSDMap)t + where t.Type == OSDType.Map + select (OSDMap)t into map - select new InventoryFolder(map["folder_id"].AsUUID()) - { - Name = map["name"].AsString(), - ParentUUID = map["parent_id"].AsUUID(), - PreferredType = (FolderType)map["type_default"].AsInteger(), - Version = map["version"].AsInteger() - }); + select new InventoryFolder(map["folder_id"].AsUUID()) + { + Name = map["name"].AsString(), + ParentUUID = map["parent_id"].AsUUID(), + PreferredType = (FolderType)map["type_default"].AsInteger(), + Version = map["version"].AsInteger() + }); return folders.ToArray(); } @@ -787,14 +946,13 @@ namespace OpenMetaverse var folders = new List(); - if (!reply.ContainsKey(key) || !(reply[key] is ArrayList)) { return folders.ToArray(); } + if (!reply.ContainsKey(key) || !(reply[key] is ArrayList)) {return folders.ToArray();} - ArrayList array = (ArrayList)reply[key]; - foreach (object t in array) + var array = (ArrayList)reply[key]; + foreach (var t in array) { - if (!(t is Hashtable)) continue; - Hashtable map = (Hashtable)t; - InventoryFolder folder = new InventoryFolder(ParseUUID("folder_id", map)) + if (!(t is Hashtable map)) continue; + var folder = new InventoryFolder(ParseUUID("folder_id", map)) { Name = ParseString("name", map), ParentUUID = ParseUUID("parent_id", map), @@ -893,9 +1051,9 @@ namespace OpenMetaverse #region Public Members /// Seed CAPS URL returned from the login server - public string LoginSeedCapability = String.Empty; + public string LoginSeedCapability = string.Empty; /// Current state of logging in - public LoginStatus LoginStatusCode => InternalStatusCode; + public LoginStatus LoginStatusCode { get; private set; } = LoginStatus.None; /// Upon login failure, contains a short string key for the /// type of login error that occurred @@ -923,13 +1081,13 @@ namespace OpenMetaverse public static readonly HttpClient HTTP_CLIENT = new HttpClient(new HttpClientHandler() { + //todo add the crt //ServerCertificateCustomValidationCallback = delegate { return true; }, AllowAutoRedirect = true }); - + private LoginParams CurrentContext = null; private readonly AutoResetEvent LoginEvent = new AutoResetEvent(false); - private LoginStatus InternalStatusCode = LoginStatus.None; private readonly Dictionary CallbackOptions = new Dictionary(); /// A list of packets obtained during the login process which @@ -990,7 +1148,7 @@ namespace OpenMetaverse public bool Login(string firstName, string lastName, string password, string channel, string start, string version) { - LoginParams loginParams = DefaultLoginParams(firstName, lastName, password, channel, version); + var loginParams = DefaultLoginParams(firstName, lastName, password, channel, version); loginParams.Start = start; return Login(loginParams); @@ -1014,18 +1172,18 @@ namespace OpenMetaverse if (CurrentContext != null) { CurrentContext = null; // Will force any pending callbacks to bail out early - InternalStatusCode = LoginStatus.Failed; + LoginStatusCode = LoginStatus.Failed; LoginMessage = "Timed out"; return false; } - return (InternalStatusCode == LoginStatus.Success); + return (LoginStatusCode == 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"); } + if (CurrentContext != null) {throw new Exception("Login already in progress");} LoginEvent.Reset(); CurrentContext = loginParams; @@ -1058,15 +1216,14 @@ namespace OpenMetaverse /// 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 + /// 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 $"uri:{sim}&{x}&{y}&{z}"; } public void AbortLogin() { - LoginParams loginParams = CurrentContext; + var 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) @@ -1075,7 +1232,7 @@ namespace OpenMetaverse } else { - InternalStatusCode = LoginStatus.Failed; + LoginStatusCode = LoginStatus.Failed; LoginMessage = "Aborted"; } UpdateLoginStatus(LoginStatus.Failed, "Abort Requested"); @@ -1084,10 +1241,10 @@ namespace OpenMetaverse #endregion #region Private Methods - // actually perform the login. + private void BeginLogin() { - LoginParams loginParams = CurrentContext; + var loginParams = CurrentContext; // Generate a random ID to identify this login attempt loginParams.LoginID = UUID.Random(); CurrentContext = loginParams; @@ -1100,7 +1257,7 @@ namespace OpenMetaverse if (loginParams.Password == null) loginParams.Password = string.Empty; - // Convert the password to MD5 if it isn't already + // *HACK: 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); @@ -1111,7 +1268,7 @@ namespace OpenMetaverse loginParams.Version = string.Empty; if (loginParams.UserAgent == null) - loginParams.UserAgent = string.Empty; + loginParams.UserAgent = Settings.USER_AGENT; if (loginParams.Platform == null) loginParams.Platform = string.Empty; @@ -1124,18 +1281,38 @@ namespace OpenMetaverse if (string.IsNullOrEmpty(loginParams.Channel)) { - Logger.Log("Viewer channel not set. This is a TOS violation on some grids.", + Logger.Log("Viewer channel not set.", Helpers.LogLevel.Warning); - loginParams.Channel = "LibreMetaverse client"; + loginParams.Channel = $"{Settings.USER_AGENT}"; + } + + if (!string.IsNullOrEmpty(loginParams.LoginLocation)) + { + var startLoc = new LocationParser(loginParams.LoginLocation.Trim()); + loginParams.Start = startLoc.GetStartLocationUri(); + } + else + { + switch (loginParams.Start) + { + case "home": + case "last": + break; + default: + var startLoc = new LocationParser(loginParams.Start.Trim()); + loginParams.Start = startLoc.GetStartLocationUri(); + break; + } } if (loginParams.Author == null) + { loginParams.Author = string.Empty; - + } #endregion // TODO: Allow a user callback to be defined for handling the cert - ServicePointManager.ServerCertificateValidationCallback = + ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; if (Client.Settings.USE_LLSD_LOGIN) @@ -1143,7 +1320,7 @@ namespace OpenMetaverse #region LLSD Based Login // Create the CAPS login structure - OSDMap loginLLSD = new OSDMap + var loginLLSD = new OSDMap { ["first"] = OSD.FromString(loginParams.FirstName), ["last"] = OSD.FromString(loginParams.LastName), @@ -1162,11 +1339,18 @@ namespace OpenMetaverse }; // Create the options LLSD array - OSDArray optionsOSD = new OSDArray(); + var optionsOSD = new OSDArray(); foreach (var t in loginParams.Options) optionsOSD.Add(OSD.FromString(t)); - foreach (var callbackOpts in CallbackOptions.Values) + foreach (var t in from callbackOpts in CallbackOptions.Values where callbackOpts != null + from t in callbackOpts where !optionsOSD.Contains(t) select t) + { + optionsOSD.Add(t); + } + + /* old version; i can't read the new one. + foreach (var callbackOpts in CallbackOptions.Values) { if (callbackOpts == null) continue; foreach (var t in callbackOpts) @@ -1175,6 +1359,8 @@ namespace OpenMetaverse optionsOSD.Add(t); } } + */ + loginLLSD["options"] = optionsOSD; // Make the CAPS POST for login @@ -1195,7 +1381,7 @@ namespace OpenMetaverse loginRequest.UserData = CurrentContext; UpdateLoginStatus(LoginStatus.ConnectingToLogin, $"Logging in as {loginParams.FirstName} {loginParams.LastName}..."); - loginRequest.BeginGetResponse(loginLLSD, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + loginRequest.PostRequestAsync(loginLLSD, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); #endregion } @@ -1204,7 +1390,7 @@ namespace OpenMetaverse #region XML-RPC Based Login Code // Create the Hashtable for XmlRpcCs - Hashtable loginXmlRpc = new Hashtable + var loginXmlRpc = new Hashtable { ["first"] = loginParams.FirstName, ["last"] = loginParams.LastName, @@ -1253,7 +1439,7 @@ namespace OpenMetaverse cts.CancelAfter(cc.Timeout); var loginResponse = await HTTP_CLIENT.PostAsXmlRpcAsync(cc.URI, request, cts.Token); cts.Dispose(); - + LoginReplyXmlRpcHandler(loginResponse, loginParams); } catch (Exception e) @@ -1274,7 +1460,7 @@ namespace OpenMetaverse private void UpdateLoginStatus(LoginStatus status, string message) { - InternalStatusCode = status; + LoginStatusCode = status; LoginMessage = message; Logger.DebugLog($"Login status: {status.ToString()}: {message}", Client); @@ -1310,9 +1496,9 @@ namespace OpenMetaverse /// private void LoginReplyXmlRpcHandler(XmlRpcResponse response, LoginParams context) { - LoginResponseData reply = new LoginResponseData(); + var reply = new LoginResponseData(); // Fetch the login response - if (!(response?.Value is Hashtable)) + if (!(response?.Value is Hashtable value)) { UpdateLoginStatus(LoginStatus.Failed, "Invalid or missing login response from the server"); Logger.Log("Invalid or missing login response from the server", Helpers.LogLevel.Warning); @@ -1321,10 +1507,11 @@ namespace OpenMetaverse try { - reply.Parse((Hashtable)response.Value); + reply.Parse(value); if (context.LoginID != CurrentContext.LoginID) { - Logger.Log("Login response does not match login request. Only one login can be attempted at a time", + Logger.Log("Login response does not match login request. " + + "Only one login can be attempted at a time", Helpers.LogLevel.Error); return; } @@ -1348,8 +1535,8 @@ namespace OpenMetaverse ushort simPort = 0; uint regionX = 0; uint regionY = 0; - string reason = reply.Reason; - string message = reply.Message; + var reason = reply.Reason; + var message = reply.Message; if (reply.Login == "true") { @@ -1407,7 +1594,7 @@ namespace OpenMetaverse // reply.initial_outfit } - bool redirect = (reply.Login == "indeterminate"); + var redirect = (reply.Login == "indeterminate"); try { @@ -1429,7 +1616,7 @@ namespace OpenMetaverse loginParams.Options = reply.NextOptions; // Sleep for some amount of time while the servers work - int seconds = reply.NextDuration; + var seconds = reply.NextDuration; Logger.Log($"Sleeping for {seconds} seconds during a login redirect", Helpers.LogLevel.Info); Thread.Sleep(seconds * 1000); @@ -1479,16 +1666,16 @@ namespace OpenMetaverse { if (result != null && result.Type == OSDType.Map) { - OSDMap map = (OSDMap)result; + var map = (OSDMap)result; OSD osd; - LoginResponseData data = new LoginResponseData(); + var data = new LoginResponseData(); data.Parse(map); if (map.TryGetValue("login", out osd)) { - bool loginSuccess = osd.AsBoolean(); - bool redirect = (osd.AsString() == "indeterminate"); + var loginSuccess = osd.AsBoolean(); + var redirect = (osd.AsString() == "indeterminate"); if (redirect) { @@ -1497,12 +1684,12 @@ namespace OpenMetaverse // Make the next login URL jump UpdateLoginStatus(LoginStatus.Redirecting, data.Message); - LoginParams loginParams = CurrentContext; + var 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); + var seconds = (int)LoginResponseData.ParseUInt("next_duration", map); Logger.Log("Sleeping for " + seconds + " seconds during a login redirect", Helpers.LogLevel.Info); Thread.Sleep(seconds * 1000); @@ -1560,7 +1747,7 @@ namespace OpenMetaverse // Login failed // Make sure a usable error key is set - LoginErrorKey = data.Reason != String.Empty ? data.Reason : "unknown"; + LoginErrorKey = data.Reason != string.Empty ? data.Reason : "unknown"; UpdateLoginStatus(LoginStatus.Failed, data.Message); } @@ -1568,14 +1755,14 @@ namespace OpenMetaverse else { // Got an LLSD map but no login value - UpdateLoginStatus(LoginStatus.Failed, "login parameter missing in the response"); + UpdateLoginStatus(LoginStatus.Failed, "Login parameter missing in the response"); } } else { // No LLSD response LoginErrorKey = "bad response"; - UpdateLoginStatus(LoginStatus.Failed, "Empty or unparseable login response"); + UpdateLoginStatus(LoginStatus.Failed, "Empty or corrupt login response"); } } else @@ -1622,14 +1809,14 @@ namespace OpenMetaverse try { - System.Net.NetworkInformation.NetworkInterface[] nics = + var nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); if (nics.Length > 0) { - foreach (NetworkInterface t in nics) + foreach (var t in nics) { - string adapterMac = t.GetPhysicalAddress().ToString().ToUpper(); + var adapterMac = t.GetPhysicalAddress().ToString().ToUpper(); if (adapterMac.Length == 12 && adapterMac != "000000000000") { mac = adapterMac; @@ -1643,7 +1830,7 @@ namespace OpenMetaverse if (mac.Length < 12) mac = UUID.Random().ToString().Substring(24, 12); - return String.Format("{0}:{1}:{2}:{3}:{4}:{5}", + return string.Format("{0}:{1}:{2}:{3}:{4}:{5}", mac.Substring(0, 2), mac.Substring(2, 2), mac.Substring(4, 2), @@ -1660,8 +1847,8 @@ namespace OpenMetaverse private static string HashString(string str) { MD5 sec = new MD5CryptoServiceProvider(); - ASCIIEncoding enc = new ASCIIEncoding(); - byte[] buf = enc.GetBytes(str); + var enc = new ASCIIEncoding(); + var buf = enc.GetBytes(str); return GetHexString(sec.ComputeHash(buf)); } diff --git a/Assets/Plugins/LibreMetaverse/Messages/LindenMessages.cs b/Assets/Plugins/LibreMetaverse/Messages/LindenMessages.cs index 9b7549c..3137e4b 100644 --- a/Assets/Plugins/LibreMetaverse/Messages/LindenMessages.cs +++ b/Assets/Plugins/LibreMetaverse/Messages/LindenMessages.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -1401,9 +1402,7 @@ namespace OpenMetaverse.Messages.Linden { FolderDataInfo ret = new FolderDataInfo(); - if (!(data is OSDMap)) return ret; - - OSDMap map = (OSDMap)data; + if (!(data is OSDMap map)) return ret; ret.FolderID = map["FolderID"]; ret.ParentID = map["ParentID"]; @@ -1442,9 +1441,7 @@ namespace OpenMetaverse.Messages.Linden { ItemDataInfo ret = new ItemDataInfo(); - if (!(data is OSDMap)) return ret; - - OSDMap map = (OSDMap)data; + if (!(data is OSDMap map)) return ret; ret.ItemID = map["ItemID"]; ret.CallbackID = map["CallbackID"]; diff --git a/Assets/Plugins/LibreMetaverse/NetworkManager.cs b/Assets/Plugins/LibreMetaverse/NetworkManager.cs index 5e74c86..38b5a17 100644 --- a/Assets/Plugins/LibreMetaverse/NetworkManager.cs +++ b/Assets/Plugins/LibreMetaverse/NetworkManager.cs @@ -25,12 +25,10 @@ */ using System; -using System.Collections.Concurrent; using System.Threading; using System.Collections.Generic; using System.Linq; using System.Net; -using System.Net.Http; using System.Threading.Channels; using System.Threading.Tasks; using OpenMetaverse.Packets; @@ -38,7 +36,7 @@ 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 @@ -316,7 +314,7 @@ namespace OpenMetaverse /// Shows whether the network layer is logged in to the /// grid or not - public bool Connected => connected; + public bool Connected { get; private set; } /// Number of packets in the incoming queue public int InboxCount => _packetInboxCount; @@ -346,7 +344,6 @@ namespace OpenMetaverse private GridClient Client; private Timer DisconnectTimer; - private bool connected; private long lastpacketwarning = 0; @@ -587,7 +584,7 @@ namespace OpenMetaverse { // Mark that we are connecting/connected to the grid // - connected = true; + Connected = true; // raise the SimConnecting event and allow any event // subscribers to cancel the connection @@ -746,7 +743,7 @@ namespace OpenMetaverse } // This will catch a Logout when the client is not logged in - if (CurrentSim == null || !connected) + if (CurrentSim == null || !Connected) { Logger.Log("Ignoring RequestLogout(), client is already logged out", Helpers.LogLevel.Warning, Client); return; @@ -865,7 +862,7 @@ namespace OpenMetaverse Interlocked.Exchange(ref _packetInboxCount, 0); Interlocked.Exchange(ref _packetOutboxCount, 0); - connected = false; + Connected = false; // Fire the disconnected callback if (m_Disconnected != null) @@ -923,7 +920,7 @@ namespace OpenMetaverse // FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP! var stopwatch = new System.Diagnostics.Stopwatch(); - while (await reader.WaitToReadAsync() && connected) + while (await reader.WaitToReadAsync() && Connected) { while (reader.TryRead(out var outgoingPacket)) { @@ -956,7 +953,7 @@ namespace OpenMetaverse { var reader = _packetInbox.Reader; - while (await reader.WaitToReadAsync() && connected) + while (await reader.WaitToReadAsync() && Connected) { while (reader.TryRead(out var incomingPacket)) { @@ -1006,14 +1003,14 @@ namespace OpenMetaverse private void DisconnectTimer_Elapsed(object obj) { - if (!connected || CurrentSim == null) + if (!Connected || CurrentSim == null) { if (DisconnectTimer != null) { DisconnectTimer.Dispose(); DisconnectTimer = null; } - connected = false; + Connected = false; } else if (CurrentSim.DisconnectCandidate) { @@ -1027,7 +1024,7 @@ namespace OpenMetaverse DisconnectTimer = null; } - connected = false; + Connected = false; // Shutdown the network layer Shutdown(DisconnectType.NetworkTimeout); diff --git a/Assets/Plugins/LibreMetaverse/ObjectManager.cs b/Assets/Plugins/LibreMetaverse/ObjectManager.cs index f6829f4..d1285ee 100644 --- a/Assets/Plugins/LibreMetaverse/ObjectManager.cs +++ b/Assets/Plugins/LibreMetaverse/ObjectManager.cs @@ -1696,7 +1696,7 @@ namespace OpenMetaverse } }; - request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -1725,7 +1725,7 @@ namespace OpenMetaverse Logger.Log("ObjectMediaUpdate: " + error.Message, Helpers.LogLevel.Error, Client); } }; - request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -1781,7 +1781,7 @@ namespace OpenMetaverse } }; - request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -3359,22 +3359,20 @@ namespace OpenMetaverse /// 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; } } + public Simulator Simulator { get; } + /// Get the details - public Primitive Prim { get { return m_Prim; } } + public Primitive Prim { get; } + /// 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; } } + public bool IsNew { get; } + /// true if the is attached to an - public bool IsAttachment { get { return m_IsAttachment; } } + public bool IsAttachment { get; } + /// Get the simulator Time Dilation - public ushort TimeDilation { get { return m_TimeDilation; } } + public ushort TimeDilation { get; } /// /// Construct a new instance of the PrimEventArgs class @@ -3386,11 +3384,11 @@ namespace OpenMetaverse /// 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; + this.Simulator = simulator; + this.IsNew = isNew; + this.IsAttachment = isAttachment; + this.Prim = prim; + this.TimeDilation = timeDilation; } } @@ -3440,19 +3438,17 @@ namespace OpenMetaverse /// 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; } } + public Simulator Simulator { get; } + /// Get the data - public Avatar Avatar { get { return m_Avatar; } } + public Avatar Avatar { get; } + /// Get the simulator time dilation - public ushort TimeDilation { get { return m_TimeDilation; } } + public ushort TimeDilation { get; } + /// 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; } } + public bool IsNew { get; } /// /// Construct a new instance of the AvatarUpdateEventArgs class @@ -3463,24 +3459,22 @@ namespace OpenMetaverse /// 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; + this.Simulator = simulator; + this.Avatar = avatar; + this.TimeDilation = timeDilation; + this.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; } } + public Simulator Simulator { get; } + /// Get the data - public Primitive.ParticleSystem ParticleSystem { get { return m_ParticleSystem; } } + public Primitive.ParticleSystem ParticleSystem { get; } + /// Get source - public Primitive Source { get { return m_Source; } } + public Primitive Source { get; } /// /// Construct a new instance of the ParticleUpdateEventArgs class @@ -3489,9 +3483,9 @@ namespace OpenMetaverse /// 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; + this.Simulator = simulator; + this.ParticleSystem = particlesystem; + this.Source = source; } } @@ -3548,11 +3542,8 @@ namespace OpenMetaverse /// public class ObjectPropertiesUpdatedEventArgs : ObjectPropertiesEventArgs { - - private readonly Primitive m_Prim; - /// Get the primitive details - public Primitive Prim { get { return m_Prim; } } + public Primitive Prim { get; } /// /// Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class @@ -3562,7 +3553,7 @@ namespace OpenMetaverse /// The primitive Properties public ObjectPropertiesUpdatedEventArgs(Simulator simulator, Primitive prim, Primitive.ObjectProperties props) : base(simulator, props) { - this.m_Prim = prim; + this.Prim = prim; } } @@ -3575,22 +3566,20 @@ namespace OpenMetaverse /// 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 Simulator Simulator { get; } + /// - public Primitive.ObjectProperties Properties { get { return m_Properties; } } + public Primitive.ObjectProperties Properties { get; } + /// - public ReportType Type { get { return m_Type; } } + public ReportType Type { get; } public ObjectPropertiesFamilyEventArgs(Simulator simulator, Primitive.ObjectProperties props, ReportType type) { - this.m_Simulator = simulator; - this.m_Properties = props; - this.m_Type = type; + this.Simulator = simulator; + this.Properties = props; + this.Type = type; } } @@ -3599,26 +3588,24 @@ namespace OpenMetaverse /// 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; } } + public Simulator Simulator { get; } + /// Get the primitive details - public Primitive Prim { get { return m_Prim; } } + public Primitive Prim { get; } + /// - public ObjectMovementUpdate Update { get { return m_Update; } } + public ObjectMovementUpdate Update { get; } + /// - public ushort TimeDilation { get { return m_TimeDilation; } } + public ushort TimeDilation { get; } 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; + this.Simulator = simulator; + this.Prim = prim; + this.Update = update; + this.TimeDilation = timeDilation; } } @@ -3627,35 +3614,33 @@ namespace OpenMetaverse /// 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; } } + public Simulator Simulator { get; } + /// Get the primitive details - public Primitive Prim { get { return m_Prim; } } + public Primitive Prim { get; } + /// - public Primitive.ConstructionData ConstructionData { get { return m_ConstructionData; } } + public Primitive.ConstructionData ConstructionData { get; } + /// - public ObjectUpdatePacket.ObjectDataBlock Block { get { return m_Block; } } + public ObjectUpdatePacket.ObjectDataBlock Block { get; } + /// - public ObjectMovementUpdate Update { get { return m_Update; } } + public ObjectMovementUpdate Update { get; } + /// - public NameValue[] NameValues { get { return m_NameValues; } } + public NameValue[] NameValues { get; } 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; + this.Simulator = simulator; + this.Prim = prim; + this.ConstructionData = constructionData; + this.Block = block; + this.Update = objectupdate; + this.NameValues = nameValues; } } @@ -3663,18 +3648,16 @@ namespace OpenMetaverse /// 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; } } + public Simulator Simulator { get; } + /// The LocalID of the object - public uint ObjectLocalID { get { return m_ObjectLocalID; } } + public uint ObjectLocalID { get; } public KillObjectEventArgs(Simulator simulator, uint objectID) { - this.m_Simulator = simulator; - this.m_ObjectLocalID = objectID; + this.Simulator = simulator; + this.ObjectLocalID = objectID; } } @@ -3682,18 +3665,16 @@ namespace OpenMetaverse /// 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; } } + public Simulator Simulator { get; } + /// The LocalID of the object - public uint[] ObjectLocalIDs { get { return m_ObjectLocalIDs; } } + public uint[] ObjectLocalIDs { get; } public KillObjectsEventArgs(Simulator simulator, uint[] objectIDs) { - this.m_Simulator = simulator; - this.m_ObjectLocalIDs = objectIDs; + this.Simulator = simulator; + this.ObjectLocalIDs = objectIDs; } } @@ -3702,26 +3683,24 @@ namespace OpenMetaverse /// 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 Simulator Simulator { get; } + /// - public Avatar Avatar { get { return m_Avatar; } } + public Avatar Avatar { get; } + /// - public uint SittingOn { get { return m_SittingOn; } } + public uint SittingOn { get; } + /// - public uint OldSeat { get { return m_OldSeat; } } + public uint OldSeat { get; } 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; + this.Simulator = simulator; + this.Avatar = avatar; + this.SittingOn = sittingOn; + this.OldSeat = oldSeat; } } @@ -3730,26 +3709,24 @@ namespace OpenMetaverse /// 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 Simulator Simulator { get; } + /// - public UUID ObjectID { get { return m_ObjectID; } } + public UUID ObjectID { get; } + /// - public int DefaultPrice { get { return m_DefaultPrice; } } + public int DefaultPrice { get; } + /// - public int[] ButtonPrices { get { return m_ButtonPrices; } } + public int[] ButtonPrices { get; } 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; + this.Simulator = simulator; + this.ObjectID = objectID; + this.DefaultPrice = defaultPrice; + this.ButtonPrices = buttonPrices; } } diff --git a/Assets/Plugins/LibreMetaverse/PacketDecoder.cs b/Assets/Plugins/LibreMetaverse/PacketDecoder.cs index 4e93f7b..f384cd9 100644 --- a/Assets/Plugins/LibreMetaverse/PacketDecoder.cs +++ b/Assets/Plugins/LibreMetaverse/PacketDecoder.cs @@ -26,7 +26,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Reflection; using System.Text; diff --git a/Assets/Plugins/LibreMetaverse/ParcelManager.cs b/Assets/Plugins/LibreMetaverse/ParcelManager.cs index 02fa521..2bfc1e7 100644 --- a/Assets/Plugins/LibreMetaverse/ParcelManager.cs +++ b/Assets/Plugins/LibreMetaverse/ParcelManager.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -570,6 +571,12 @@ namespace OpenMetaverse public bool ObscureMusic; /// A struct containing media details public ParcelMedia Media; + /// Parcel privacy see avatars outside/inside parcel + public bool SeeAVs; + /// Parcel privacy play sounds attached to avatars outside/inside parcel + public bool AnyAVSounds; + /// Parcel privacy play sounds for group members + public bool GroupAVSounds; /// /// Displays a parcel object in string format @@ -635,12 +642,15 @@ namespace OpenMetaverse SalePrice = (uint) SalePrice, SnapshotID = SnapshotID, UserLocation = UserLocation, - UserLookAt = UserLookAt + UserLookAt = UserLookAt, + SeeAVs = SeeAVs, + AnyAVSounds = AnyAVSounds, + GroupAVSounds = GroupAVSounds }; OSDMap body = req.Serialize(); - request.BeginGetResponse(body, OSDFormat.Xml, simulator.Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(body, OSDFormat.Xml, simulator.Client.Settings.CAPS_TIMEOUT); } else { @@ -1661,9 +1671,9 @@ namespace OpenMetaverse try { - OSD result = request.GetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + OSDMap result = request.PostRequest(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT) as OSDMap; RemoteParcelRequestReply response = new RemoteParcelRequestReply(); - response.Deserialize((OSDMap)result); + response.Deserialize(result); return response.ParcelID; } catch (Exception) @@ -1700,7 +1710,7 @@ namespace OpenMetaverse response.Deserialize((OSDMap)result); CapsClient summaryRequest = new CapsClient(response.ScriptResourceSummary, "ScriptResourceSummary"); - OSD summaryResponse = summaryRequest.GetResponse(Client.Settings.CAPS_TIMEOUT); + OSD summaryResponse = summaryRequest.GetRequest(Client.Settings.CAPS_TIMEOUT); LandResourcesInfo res = new LandResourcesInfo(); res.Deserialize((OSDMap)summaryResponse); @@ -1708,7 +1718,7 @@ namespace OpenMetaverse if (response.ScriptResourceDetails != null && getDetails) { CapsClient detailRequest = new CapsClient(response.ScriptResourceDetails, "ScriptResourceDetails"); - OSD detailResponse = detailRequest.GetResponse(Client.Settings.CAPS_TIMEOUT); + OSD detailResponse = detailRequest.GetRequest(Client.Settings.CAPS_TIMEOUT); res.Deserialize((OSDMap)detailResponse); } callback(true, res); @@ -1721,7 +1731,7 @@ namespace OpenMetaverse }; LandResourcesRequest param = new LandResourcesRequest {ParcelID = parcelID}; - request.BeginGetResponse(param.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + request.PostRequestAsync(param.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } catch (Exception ex) @@ -1842,7 +1852,11 @@ namespace OpenMetaverse RegionDenyAgeUnverified = msg.RegionDenyAgeUnverified, RegionDenyAnonymous = msg.RegionDenyAnonymous, RegionPushOverride = msg.RegionPushOverride, - RentPrice = msg.RentPrice + RentPrice = msg.RentPrice, + SeeAVs = msg.SeeAVs, + AnyAVSounds = msg.AnyAVSounds, + GroupAVSounds = msg.GroupAVSounds + }; ParcelResult result = msg.RequestResult; @@ -2100,18 +2114,14 @@ namespace OpenMetaverse /// 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 => m_ParcelID; + public UUID ParcelID { get; } /// Get the simulator specific ID of the parcel - public int LocalID => m_LocalID; + public int LocalID { get; } /// Get the calculated dwell - public float Dwell => m_Dwell; + public float Dwell { get; } /// /// Construct a new instance of the ParcelDwellReplyEventArgs class @@ -2121,20 +2131,18 @@ namespace OpenMetaverse /// The calculated dwell for the parcel public ParcelDwellReplyEventArgs(UUID parcelID, int localID, float dwell) { - m_ParcelID = parcelID; - m_LocalID = localID; - m_Dwell = dwell; + ParcelID = parcelID; + LocalID = localID; + 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 => m_Parcel; + public ParcelInfo Parcel { get; } /// /// Construct a new instance of the ParcelInfoReplyEventArgs class @@ -2142,40 +2150,33 @@ namespace OpenMetaverse /// The object containing basic parcel info public ParcelInfoReplyEventArgs(ParcelInfo parcel) { - m_Parcel = parcel; + 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 => m_Simulator; + public Simulator Simulator { get; } /// Get the object containing the details /// If Result is NoData, this object will not contain valid data - public Parcel Parcel => m_Parcel; + public Parcel Parcel { get; } /// Get the result of the request - public ParcelResult Result => m_Result; + public ParcelResult Result { get; } /// Get the number of primitieves your agent is /// currently selecting and or sitting on in this parcel - public int SelectedPrims => m_SelectedPrims; + public int SelectedPrims { get; } /// Get the user assigned ID used to correlate a request with /// these results - public int SequenceID => m_SequenceID; + public int SequenceID { get; } /// TODO: - public bool SnapSelection => m_SnapSelection; + public bool SnapSelection { get; } /// /// Construct a new instance of the ParcelPropertiesEventArgs class @@ -2191,39 +2192,33 @@ namespace OpenMetaverse public ParcelPropertiesEventArgs(Simulator simulator, Parcel parcel, ParcelResult result, int selectedPrims, int sequenceID, bool snapSelection) { - m_Simulator = simulator; - m_Parcel = parcel; - m_Result = result; - m_SelectedPrims = selectedPrims; - m_SequenceID = sequenceID; - m_SnapSelection = snapSelection; + Simulator = simulator; + Parcel = parcel; + Result = result; + SelectedPrims = selectedPrims; + SequenceID = sequenceID; + 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 => m_Simulator; + public Simulator Simulator { get; } /// Get the user assigned ID used to correlate a request with /// these results - public int SequenceID => m_SequenceID; + public int SequenceID { get; } /// Get the simulator specific ID of the parcel - public int LocalID => m_LocalID; + public int LocalID { get; } /// TODO - public uint Flags => m_Flags; + public uint Flags { get; } /// Get the list containing the white/blacklisted agents for the parcel - public List AccessList => m_AccessList; + public List AccessList { get; } /// /// Construct a new instance of the ParcelAccessListReplyEventArgs class @@ -2236,11 +2231,11 @@ namespace OpenMetaverse /// The list containing the white/blacklisted agents for the parcel public ParcelAccessListReplyEventArgs(Simulator simulator, int sequenceID, int localID, uint flags, List accessEntries) { - m_Simulator = simulator; - m_SequenceID = sequenceID; - m_LocalID = localID; - m_Flags = flags; - m_AccessList = accessEntries; + Simulator = simulator; + SequenceID = sequenceID; + LocalID = localID; + Flags = flags; + AccessList = accessEntries; } } @@ -2248,14 +2243,11 @@ namespace OpenMetaverse /// 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 => m_Simulator; + public Simulator Simulator { get; } /// Get the list containing prim ownership counts - public List PrimOwners => m_Owners; + public List PrimOwners { get; } /// /// Construct a new instance of the ParcelObjectOwnersReplyEventArgs class @@ -2264,27 +2256,23 @@ namespace OpenMetaverse /// The list containing prim ownership counts public ParcelObjectOwnersReplyEventArgs(Simulator simulator, List primOwners) { - m_Simulator = simulator; - m_Owners = primOwners; + Simulator = simulator; + PrimOwners = 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 => m_Simulator; + public Simulator Simulator { get; } /// A dictionary containing the parcel data where the key correlates to the ParcelMap entry - public InternalDictionary Parcels => m_Parcels; + public InternalDictionary Parcels { get; } /// Get the multidimensional array containing a x,y grid mapped /// to each 64x64 parcel's LocalID. - public int[,] ParcelMap => m_ParcelMap; + public int[,] ParcelMap { get; } /// /// Construct a new instance of the SimParcelsDownloadedEventArgs class @@ -2295,28 +2283,24 @@ namespace OpenMetaverse /// to each 64x64 parcel's LocalID. public SimParcelsDownloadedEventArgs(Simulator simulator, InternalDictionary simParcels, int[,] parcelMap) { - m_Simulator = simulator; - m_Parcels = simParcels; - m_ParcelMap = parcelMap; + Simulator = simulator; + Parcels = simParcels; + 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 => m_Simulator; + public Simulator Simulator { get; } /// Get the list of primitive IDs - public List ObjectIDs => m_ObjectIDs; + public List ObjectIDs { get; } /// true if the list is clean and contains the information /// only for a given request - public bool ResetList => m_ResetList; + public bool ResetList { get; } /// /// Construct a new instance of the ForceSelectObjectsReplyEventArgs class @@ -2327,23 +2311,20 @@ namespace OpenMetaverse /// 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; + this.Simulator = simulator; + this.ObjectIDs = objectIDs; + this.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 => m_Simulator; + public Simulator Simulator { get; } /// Get the updated media information - public ParcelMedia Media => m_ParcelMedia; + public ParcelMedia Media { get; } /// /// Construct a new instance of the ParcelMediaUpdateReplyEventArgs class @@ -2352,34 +2333,28 @@ namespace OpenMetaverse /// The updated media information public ParcelMediaUpdateReplyEventArgs(Simulator simulator, ParcelMedia media) { - this.m_Simulator = simulator; - this.m_ParcelMedia = media; + this.Simulator = simulator; + this.Media = 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 => m_Simulator; + public Simulator Simulator { get; } /// - public uint Sequence => m_Sequence; + public uint Sequence { get; } /// - public ParcelFlags ParcelFlags => m_ParcelFlags; + public ParcelFlags ParcelFlags { get; } /// Get the media command that was sent - public ParcelMediaCommand MediaCommand => m_MediaCommand; + public ParcelMediaCommand MediaCommand { get; } /// - public float Time => m_Time; + public float Time { get; } /// /// Construct a new instance of the ParcelMediaCommandEventArgs class @@ -2391,11 +2366,11 @@ namespace OpenMetaverse /// public ParcelMediaCommandEventArgs(Simulator simulator, uint sequence, ParcelFlags flags, ParcelMediaCommand command, float time) { - m_Simulator = simulator; - m_Sequence = sequence; - m_ParcelFlags = flags; - m_MediaCommand = command; - m_Time = time; + Simulator = simulator; + Sequence = sequence; + ParcelFlags = flags; + MediaCommand = command; + Time = time; } } #endregion diff --git a/Assets/Plugins/LibreMetaverse/Permissions.cs b/Assets/Plugins/LibreMetaverse/Permissions.cs index bd21da1..7e506fc 100644 --- a/Assets/Plugins/LibreMetaverse/Permissions.cs +++ b/Assets/Plugins/LibreMetaverse/Permissions.cs @@ -29,9 +29,6 @@ using OpenMetaverse.StructuredData; namespace OpenMetaverse { - /// - /// - /// [Flags] public enum PermissionMask : uint { @@ -47,9 +44,6 @@ namespace OpenMetaverse All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) } - /// - /// - /// [Flags] public enum PermissionWho : byte { @@ -67,10 +61,7 @@ namespace OpenMetaverse All = 0x1F } - /// - /// - /// - [Serializable()] + [Serializable] public struct Permissions { public PermissionMask BaseMask; diff --git a/Assets/Plugins/LibreMetaverse/PrimMesher/ObjMesh.cs b/Assets/Plugins/LibreMetaverse/PrimMesher/ObjMesh.cs index 01edcf5..f38d220 100644 --- a/Assets/Plugins/LibreMetaverse/PrimMesher/ObjMesh.cs +++ b/Assets/Plugins/LibreMetaverse/PrimMesher/ObjMesh.cs @@ -66,7 +66,7 @@ namespace LibreMetaverse.PrimMesher while (!s.EndOfStream) { - var line = s.ReadLine().Trim(); + var line = s.ReadLine()?.Trim(); var tokens = Regex.Split(line, @"\s+"); // Skip blank lines and comments diff --git a/Assets/Plugins/LibreMetaverse/PrimMesher/PrimMesher.cs b/Assets/Plugins/LibreMetaverse/PrimMesher/PrimMesher.cs index af11e8c..4ab6e10 100644 --- a/Assets/Plugins/LibreMetaverse/PrimMesher/PrimMesher.cs +++ b/Assets/Plugins/LibreMetaverse/PrimMesher/PrimMesher.cs @@ -24,8 +24,8 @@ * (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 VERTEX_INDEXER +#define VERTEX_INDEXER using System; using System.Collections.Generic; using System.IO; diff --git a/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMap.cs b/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMap.cs index b427c01..029afea 100644 --- a/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMap.cs +++ b/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMap.cs @@ -73,9 +73,8 @@ namespace LibreMetaverse.PrimMesher try { if (needsScaling) - bm.Resize(width,height); - //bm = ScaleImage(bm, width, height, - // InterpolationMode.NearestNeighbor); + //bm.Resize(width,height); + ScaleImage(bm, width, height); } catch (Exception e) @@ -167,6 +166,12 @@ namespace LibreMetaverse.PrimMesher return rows; } + private void ScaleImage(Texture2D srcImage, int destWidth, int destHeight) + { + srcImage.Resize(destWidth, destHeight); + srcImage.Apply(); + } + //private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight, // InterpolationMode interpMode) //{ diff --git a/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMesh.cs b/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMesh.cs index 04c1386..0783bfb 100644 --- a/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMesh.cs +++ b/Assets/Plugins/LibreMetaverse/PrimMesher/SculptMesh.cs @@ -58,18 +58,9 @@ namespace LibreMetaverse.PrimMesher // //public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) //{ - // //var bitmap = (Bitmap) Image.FromFile(fileName); - // var myreader = new BMPLoader(); - // BMPImage myimg = myreader.LoadBMP(fileName); - // Texture2D tex = myimg.ToTexture2D(); - // Texture2D fakebmp = new Texture2D(tex); - - // _SculptMesh(fakebmp, (SculptType) sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); - // //bitmap.Dispose(); - - // fakebmp.delete(); - - + // var bitmap = (Bitmap) Image.FromFile(fileName); + // _SculptMesh(bitmap, (SculptType) sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); + // bitmap.Dispose(); //} /// diff --git a/Assets/Plugins/LibreMetaverse/Primitives/ParticleSystem.cs b/Assets/Plugins/LibreMetaverse/Primitives/ParticleSystem.cs index 2c01235..ab1a0c8 100644 --- a/Assets/Plugins/LibreMetaverse/Primitives/ParticleSystem.cs +++ b/Assets/Plugins/LibreMetaverse/Primitives/ParticleSystem.cs @@ -25,8 +25,6 @@ */ using System; -using System.Collections.Generic; -using System.ComponentModel; using OpenMetaverse.StructuredData; namespace OpenMetaverse @@ -46,6 +44,7 @@ namespace OpenMetaverse /// /// Particle source pattern /// + [Flags] public enum SourcePattern : byte { /// None diff --git a/Assets/Plugins/LibreMetaverse/Primitives/Primitive.cs b/Assets/Plugins/LibreMetaverse/Primitives/Primitive.cs index 49fc768..20c25c0 100644 --- a/Assets/Plugins/LibreMetaverse/Primitives/Primitive.cs +++ b/Assets/Plugins/LibreMetaverse/Primitives/Primitive.cs @@ -25,7 +25,6 @@ */ using System; -using System.Collections.Generic; using OpenMetaverse.StructuredData; namespace OpenMetaverse @@ -744,9 +743,8 @@ namespace OpenMetaverse { PhysicsProperties ret = new PhysicsProperties(); - if (osd is OSDMap) + if (osd is OSDMap map) { - OSDMap map = (OSDMap)osd; ret.LocalID = map["LocalID"]; ret.Density = map["Density"]; ret.Friction = map["Friction"]; @@ -1317,7 +1315,7 @@ namespace OpenMetaverse public override bool Equals(object obj) { - return (obj is Primitive) ? this == (Primitive)obj : false; + return (obj is Primitive primitive) && this == primitive; } public bool Equals(Primitive other) diff --git a/Assets/Plugins/LibreMetaverse/Rendering/Rendering.cs b/Assets/Plugins/LibreMetaverse/Rendering/Rendering.cs index a76bb4a..70003d0 100644 --- a/Assets/Plugins/LibreMetaverse/Rendering/Rendering.cs +++ b/Assets/Plugins/LibreMetaverse/Rendering/Rendering.cs @@ -116,7 +116,7 @@ namespace OpenMetaverse.Rendering public override bool Equals(object obj) { - return (obj is Vertex) && this == (Vertex)obj; + return (obj is Vertex vertex) && this == vertex; } public bool Equals(Vertex other) @@ -301,11 +301,9 @@ namespace OpenMetaverse.Rendering OSD subMeshOsd = decodedMeshOsdArray[faceNr]; // Decode each individual face - if (subMeshOsd is OSDMap) + if (subMeshOsd is OSDMap subMeshMap) { - OSDMap subMeshMap = (OSDMap)subMeshOsd; - - // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level + // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no // geometry for this submesh. if (subMeshMap.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshMap["NoGeometry"])) diff --git a/Assets/Plugins/LibreMetaverse/Settings.cs b/Assets/Plugins/LibreMetaverse/Settings.cs index 0f662c8..336aeda 100644 --- a/Assets/Plugins/LibreMetaverse/Settings.cs +++ b/Assets/Plugins/LibreMetaverse/Settings.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -37,6 +38,8 @@ namespace OpenMetaverse /// happen at login or dynamically public class Settings { + public static string USER_AGENT = "LibreMetaverse"; + #region Login/Networking Settings /// Main grid login server @@ -55,7 +58,7 @@ namespace OpenMetaverse 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 = true; + public bool USE_LLSD_LOGIN = true; //why is the false by default? /// /// Maximum number of HTTP connections to open to a particular endpoint. @@ -80,10 +83,6 @@ namespace OpenMetaverse /// 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 @@ -227,10 +226,6 @@ namespace OpenMetaverse /// 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 @@ -302,7 +297,7 @@ namespace OpenMetaverse /// Cost of uploading an asset /// Read-only since this value is dynamically fetched at login - public int UPLOAD_COST => priceUpload; + public int UPLOAD_COST { get; private set; } = 0; /// Maximum number of times to resend a failed packet public int MAX_RESEND_COUNT = 3; @@ -310,9 +305,6 @@ namespace OpenMetaverse /// 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 @@ -362,7 +354,6 @@ namespace OpenMetaverse #region Private Fields private GridClient Client; - private int priceUpload = 0; public static bool SORT_INVENTORY = false; /// Constructor @@ -383,7 +374,7 @@ namespace OpenMetaverse { EconomyDataPacket econ = (EconomyDataPacket)e.Packet; - priceUpload = econ.Info.PriceUpload; //TODO: is this thread safe? no lock + UPLOAD_COST = econ.Info.PriceUpload; //TODO: is this thread safe? no lock } #endregion diff --git a/Assets/Plugins/LibreMetaverse/SoundManager.cs b/Assets/Plugins/LibreMetaverse/SoundManager.cs index 9b3d105..e152070 100644 --- a/Assets/Plugins/LibreMetaverse/SoundManager.cs +++ b/Assets/Plugins/LibreMetaverse/SoundManager.cs @@ -343,18 +343,14 @@ namespace OpenMetaverse /// 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 => m_Simulator; + public Simulator Simulator { get; } /// Get the ID of the Object - public UUID ObjectID => m_ObjectID; + public UUID ObjectID { get; } /// Get the volume level - public float Gain => m_Gain; + public float Gain { get; } /// /// Construct a new instance of the AttachedSoundGainChangedEventArgs class @@ -364,9 +360,9 @@ namespace OpenMetaverse /// The new volume level public AttachedSoundGainChangeEventArgs(Simulator sim, UUID objectID, float gain) { - m_Simulator = sim; - m_ObjectID = objectID; - m_Gain = gain; + Simulator = sim; + ObjectID = objectID; + Gain = gain; } } @@ -398,38 +394,29 @@ namespace OpenMetaverse /// 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 => m_Simulator; + public Simulator Simulator { get; } /// Get the sound asset id - public UUID SoundID => m_SoundID; + public UUID SoundID { get; } /// Get the ID of the owner - public UUID OwnerID => m_OwnerID; + public UUID OwnerID { get; } /// Get the ID of the Object - public UUID ObjectID => m_ObjectID; + public UUID ObjectID { get; } /// Get the ID of the objects parent - public UUID ParentID => m_ParentID; + public UUID ParentID { get; } /// Get the volume level - public float Gain => m_Gain; + public float Gain { get; } /// Get the regionhandle - public ulong RegionHandle => m_RegionHandle; + public ulong RegionHandle { get; } /// Get the source position - public Vector3 Position => m_Position; + public Vector3 Position { get; } /// /// Construct a new instance of the SoundTriggerEventArgs class @@ -444,14 +431,14 @@ namespace OpenMetaverse /// The source position public SoundTriggerEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID, UUID parentID, float gain, ulong regionHandle, Vector3 position) { - m_Simulator = sim; - m_SoundID = soundID; - m_OwnerID = ownerID; - m_ObjectID = objectID; - m_ParentID = parentID; - m_Gain = gain; - m_RegionHandle = regionHandle; - m_Position = position; + Simulator = sim; + SoundID = soundID; + OwnerID = ownerID; + ObjectID = objectID; + ParentID = parentID; + Gain = gain; + RegionHandle = regionHandle; + Position = position; } } @@ -474,22 +461,17 @@ namespace OpenMetaverse /// 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 => m_Simulator; + public Simulator Simulator { get; } /// Get the sound asset id - public UUID SoundID => m_SoundID; + public UUID SoundID { get; } /// Get the ID of the owner - public UUID OwnerID => m_OwnerID; + public UUID OwnerID { get; } /// Get the ID of the Object - public UUID ObjectID => m_ObjectID; + public UUID ObjectID { get; } /// /// Construct a new instance of the PreloadSoundEventArgs class @@ -500,10 +482,10 @@ namespace OpenMetaverse /// The ID of the object public PreloadSoundEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID) { - m_Simulator = sim; - m_SoundID = soundID; - m_OwnerID = ownerID; - m_ObjectID = objectID; + Simulator = sim; + SoundID = soundID; + OwnerID = ownerID; + ObjectID = objectID; } } #endregion diff --git a/Assets/Plugins/LibreMetaverse/Sounds.cs b/Assets/Plugins/LibreMetaverse/Sounds.cs index 32aacf0..6c0f13b 100644 --- a/Assets/Plugins/LibreMetaverse/Sounds.cs +++ b/Assets/Plugins/LibreMetaverse/Sounds.cs @@ -24,7 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; using System.Reflection; using System.Collections.Generic; diff --git a/Assets/Plugins/LibreMetaverse/TerrainManager.cs b/Assets/Plugins/LibreMetaverse/TerrainManager.cs index b8452f1..8b1c6cf 100644 --- a/Assets/Plugins/LibreMetaverse/TerrainManager.cs +++ b/Assets/Plugins/LibreMetaverse/TerrainManager.cs @@ -193,34 +193,28 @@ namespace OpenMetaverse // 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 => m_Simulator; + public Simulator Simulator { get; } /// Sim coordinate of the patch - public int X => m_X; + public int X { get; } /// Sim coordinate of the patch - public int Y => m_Y; + public int Y { get; } /// Size of tha patch - public int PatchSize => m_PatchSize; + public int PatchSize { get; } /// Heightmap for the patch - public float[] HeightMap => m_HeightMap; + public float[] HeightMap { get; } public LandPatchReceivedEventArgs(Simulator simulator, int x, int y, int patchSize, float[] heightMap) { - m_Simulator = simulator; - m_X = x; - m_Y = y; - m_PatchSize = patchSize; - m_HeightMap = heightMap; + Simulator = simulator; + X = x; + Y = y; + PatchSize = patchSize; + HeightMap = heightMap; } } #endregion diff --git a/Assets/Plugins/LibreMetaverse/UDPPacketBuffer.cs b/Assets/Plugins/LibreMetaverse/UDPPacketBuffer.cs index 7574bf0..50659b6 100644 --- a/Assets/Plugins/LibreMetaverse/UDPPacketBuffer.cs +++ b/Assets/Plugins/LibreMetaverse/UDPPacketBuffer.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System; using System.Net; namespace OpenMetaverse diff --git a/Assets/Plugins/LibreMetaverse/Voice/TCPPipe.cs b/Assets/Plugins/LibreMetaverse/Voice/TCPPipe.cs index 59553a9..5a93678 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/TCPPipe.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/TCPPipe.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -28,13 +29,13 @@ using System; using System.Net; using System.Net.Sockets; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.Voice { public class TCPPipe { protected class SocketPacket { - public System.Net.Sockets.Socket TCPSocket; + public Socket TCPSocket; public byte[] DataBuffer = new byte[1]; } @@ -47,12 +48,9 @@ namespace OpenMetaverse.Voice protected Socket _TCPSocket; protected IAsyncResult _Result; protected AsyncCallback _Callback; - protected string _Buffer = String.Empty; + protected string _Buffer = string.Empty; - public bool Connected - { - get { return _TCPSocket != null && _TCPSocket.Connected; } - } + public bool Connected => _TCPSocket != null && _TCPSocket.Connected; public SocketException Connect(string address, int port) { @@ -117,8 +115,10 @@ namespace OpenMetaverse.Voice try { if (_Callback == null) _Callback = new AsyncCallback(OnDataReceived); - SocketPacket packet = new SocketPacket(); - packet.TCPSocket = _TCPSocket; + SocketPacket packet = new SocketPacket + { + TCPSocket = _TCPSocket + }; _Result = _TCPSocket.BeginReceive(packet.DataBuffer, 0, packet.DataBuffer.Length, SocketFlags.None, _Callback, packet); } catch (SocketException se) @@ -127,8 +127,8 @@ namespace OpenMetaverse.Voice } } - static char[] splitNull = { '\0' }; - static string[] splitLines = { "\r", "\n", "\r\n" }; + static readonly char[] splitNull = { '\0' }; + static readonly string[] splitLines = { "\r", "\n", "\r\n" }; void ReceiveData(string data) { @@ -159,7 +159,7 @@ namespace OpenMetaverse.Voice 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); + string data = new string(chars); ReceiveData(data); WaitForData(); } @@ -171,8 +171,9 @@ namespace OpenMetaverse.Voice { if (!_TCPSocket.Connected) { - if (OnDisconnected != null) - OnDisconnected(se); + // if (OnDisconnected != null) + // OnDisconnected(se); + OnDisconnected?.Invoke(se); } } } diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceAccount.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceAccount.cs index 603fed3..4eaff06 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceAccount.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceAccount.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -24,11 +25,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Collections.Generic; using System.Text; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.Voice { public partial class VoiceGateway { diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceAux.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceAux.cs index afbcc3b..02c781e 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceAux.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceAux.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -24,11 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenMetaverse.Voice +namespace LibreMetaverse.Voice { public partial class VoiceGateway { diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceConnector.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceConnector.cs index 55528d4..7724166 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceConnector.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceConnector.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -24,11 +25,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Collections.Generic; using System.Text; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.Voice { public partial class VoiceGateway { diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceControl.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceControl.cs index 328a2f3..a8af6e3 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceControl.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceControl.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -27,15 +28,14 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; +using System.Runtime.InteropServices; using System.Threading; - using OpenMetaverse; using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.Voice { public partial class VoiceGateway : IDisposable { @@ -71,7 +71,7 @@ namespace OpenMetaverse.Voice private string spatialCredentials; // Session management - private Dictionary sessions; + private readonly Dictionary sessions; private VoiceSession spatialSession; private Uri currentParcelCap; private Uri nextParcelCap; @@ -82,21 +82,21 @@ namespace OpenMetaverse.Voice private CancellationTokenSource posTokenSource; private ManualResetEvent posRestart; public GridClient Client; - private VoicePosition position; + private readonly 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; + public List CaptureDevices { get; private set; } + /// /// List of audio output devices /// - public List PlaybackDevices { get { return outputDevices; } } + public List PlaybackDevices { get; private set; } + private string currentCaptureDevice; private string currentPlaybackDevice; private bool testing = false; @@ -110,15 +110,17 @@ namespace OpenMetaverse.Voice public VoiceGateway(GridClient c) { - Random rand = new Random(); + var 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); + position = new VoicePosition + { + UpOrientation = new Vector3d(0.0, 1.0, 0.0), + Velocity = new Vector3d(0.0, 0.0, 0.0) + }; oldPosition = new Vector3d(0, 0, 0); oldAt = new Vector3d(1, 0, 0); @@ -140,60 +142,48 @@ namespace OpenMetaverse.Voice } posTokenSource = new CancellationTokenSource(); - posThread = new Thread(new ThreadStart(PositionThreadBody)); - posThread.Name = "VoicePositionUpdate"; - posThread.IsBackground = true; + posThread = new Thread(PositionThreadBody) + { + Name = "VoicePositionUpdate", + IsBackground = true + }; posRestart = new ManualResetEvent(false); posThread.Start(); - Client.Network.EventQueueRunning += new EventHandler(Network_EventQueueRunning); + Client.Network.EventQueueRunning += 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); + OnDaemonRunning += connector_OnDaemonRunning; + OnDaemonCouldntRun += connector_OnDaemonCouldntRun; + OnConnectorCreateResponse += connector_OnConnectorCreateResponse; + OnDaemonConnected += connector_OnDaemonConnected; + OnDaemonCouldntConnect += connector_OnDaemonCouldntConnect; + OnAuxAudioPropertiesEvent += connector_OnAuxAudioPropertiesEvent; // Session events - OnSessionStateChangeEvent += - new EventHandler(connector_OnSessionStateChangeEvent); - OnSessionAddedEvent += - new EventHandler(connector_OnSessionAddedEvent); + OnSessionStateChangeEvent += connector_OnSessionStateChangeEvent; + OnSessionAddedEvent += connector_OnSessionAddedEvent; // Session Participants events - OnSessionParticipantUpdatedEvent += - new EventHandler(connector_OnSessionParticipantUpdatedEvent); - OnSessionParticipantAddedEvent += - new EventHandler(connector_OnSessionParticipantAddedEvent); + OnSessionParticipantUpdatedEvent += connector_OnSessionParticipantUpdatedEvent; + OnSessionParticipantAddedEvent += connector_OnSessionParticipantAddedEvent; // Device events - OnAuxGetCaptureDevicesResponse += - new EventHandler(connector_OnAuxGetCaptureDevicesResponse); - OnAuxGetRenderDevicesResponse += - new EventHandler(connector_OnAuxGetRenderDevicesResponse); + OnAuxGetCaptureDevicesResponse += connector_OnAuxGetCaptureDevicesResponse; + OnAuxGetRenderDevicesResponse += connector_OnAuxGetRenderDevicesResponse; // Generic status response - OnVoiceResponse += new EventHandler(connector_OnVoiceResponse); + OnVoiceResponse += connector_OnVoiceResponse; // Account events - OnAccountLoginResponse += - new EventHandler(connector_OnAccountLoginResponse); + OnAccountLoginResponse += 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"); + var vCap = Client.Network.CurrentSim.Caps.CapabilityURI("ProvisionVoiceAccountRequest"); if (vCap != null) RequestVoiceProvision(vCap); @@ -205,55 +195,39 @@ namespace OpenMetaverse.Voice /// /// /// ///If something goes wrong, we log it. - void connector_OnVoiceResponse(object sender, VoiceGateway.VoiceResponseEventArgs e) + void connector_OnVoiceResponse(object sender, VoiceResponseEventArgs e) { - if (e.StatusCode == 0) - return; - - Logger.Log(e.Message + " on " + sender as string, Helpers.LogLevel.Error); + if (e.StatusCode == 0) { return; } + Logger.Log($"{e.Message} on {sender}", Helpers.LogLevel.Error); } public void Stop() { - Client.Network.EventQueueRunning -= new EventHandler(Network_EventQueueRunning); + Client.Network.EventQueueRunning -= 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); + OnDaemonRunning -= connector_OnDaemonRunning; + OnDaemonCouldntRun -= connector_OnDaemonCouldntRun; + OnConnectorCreateResponse -= connector_OnConnectorCreateResponse; + OnDaemonConnected -= connector_OnDaemonConnected; + OnDaemonCouldntConnect -= connector_OnDaemonCouldntConnect; + OnAuxAudioPropertiesEvent -= connector_OnAuxAudioPropertiesEvent; // Session events - OnSessionStateChangeEvent -= - new EventHandler(connector_OnSessionStateChangeEvent); - OnSessionAddedEvent -= - new EventHandler(connector_OnSessionAddedEvent); + OnSessionStateChangeEvent -= connector_OnSessionStateChangeEvent; + OnSessionAddedEvent -= connector_OnSessionAddedEvent; // Session Participants events - OnSessionParticipantUpdatedEvent -= - new EventHandler(connector_OnSessionParticipantUpdatedEvent); - OnSessionParticipantAddedEvent -= - new EventHandler(connector_OnSessionParticipantAddedEvent); - OnSessionParticipantRemovedEvent -= - new EventHandler(connector_OnSessionParticipantRemovedEvent); + OnSessionParticipantUpdatedEvent -= connector_OnSessionParticipantUpdatedEvent; + OnSessionParticipantAddedEvent -= connector_OnSessionParticipantAddedEvent; + OnSessionParticipantRemovedEvent -= connector_OnSessionParticipantRemovedEvent; // Tuning events - OnAuxGetCaptureDevicesResponse -= - new EventHandler(connector_OnAuxGetCaptureDevicesResponse); - OnAuxGetRenderDevicesResponse -= - new EventHandler(connector_OnAuxGetRenderDevicesResponse); + OnAuxGetCaptureDevicesResponse -= connector_OnAuxGetCaptureDevicesResponse; + OnAuxGetRenderDevicesResponse -= connector_OnAuxGetRenderDevicesResponse; // Account events - OnAccountLoginResponse -= - new EventHandler(connector_OnAccountLoginResponse); + OnAccountLoginResponse -= connector_OnAccountLoginResponse; // Stop the background thread if (posThread != null) @@ -267,10 +241,9 @@ namespace OpenMetaverse.Voice } // Close all sessions - foreach (VoiceSession s in sessions.Values) + foreach (var s in sessions.Values) { - if (OnSessionRemove != null) - OnSessionRemove(s, EventArgs.Empty); + OnSessionRemove?.Invoke(s, EventArgs.Empty); s.Close(); } @@ -309,56 +282,46 @@ namespace OpenMetaverse.Voice internal string GetVoiceDaemonPath() { - string myDir = + var myDir = Path.GetDirectoryName( (System.Reflection.Assembly.GetEntryAssembly() ?? typeof (VoiceGateway).Assembly).Location); - if (Environment.OSVersion.Platform != PlatformID.MacOSX && - Environment.OSVersion.Platform != PlatformID.Unix) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - string localDaemon = Path.Combine(myDir, Path.Combine("voice", "SLVoice.exe")); + if (myDir != null) + { + var 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 (File.Exists(localDaemon)) + return localDaemon; } - 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"); + var progFiles = Environment.GetEnvironmentVariable( + !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ProgramFiles(x86)")) + ? "ProgramFiles(x86)" : "ProgramFiles"); + return progFiles != null && File.Exists(Path.Combine(progFiles, @"SecondLife" + Path.DirectorySeparatorChar + @"SLVoice.exe")) + ? Path.Combine(progFiles, @"SecondLife" + Path.DirectorySeparatorChar + @"SLVoice.exe") + : Path.Combine(myDir, @"SLVoice.exe"); } - else + + if (myDir != null) { - string localDaemon = Path.Combine(myDir, Path.Combine("voice", "SLVoice")); - - if (File.Exists(localDaemon)) - return localDaemon; - - return Path.Combine(myDir,"SLVoice"); + var localDaemon = Path.Combine(myDir, Path.Combine("voice", "SLVoice")); + return File.Exists(localDaemon) ? localDaemon : Path.Combine(myDir,"SLVoice"); } + + return string.Empty; } - void RequestVoiceProvision(System.Uri cap) + void RequestVoiceProvision(Uri cap) { - Http.CapsClient capClient = new Http.CapsClient(cap, "ReqVoiceProvision"); + var capClient = new CapsClient(cap, "ReqVoiceProvision"); capClient.OnComplete += cClient_OnComplete; - OSD postData = new OSD(); // STEP 0 Logger.Log("Requesting voice capability", Helpers.LogLevel.Info); - capClient.BeginGetResponse(postData, OSDFormat.Xml, 10000); + capClient.PostRequestAsync(new OSD(), OSDFormat.Xml, 10000); } /// @@ -382,8 +345,7 @@ namespace OpenMetaverse.Voice // 5. Create session // Get the voice provisioning data - System.Uri vCap = - Client.Network.CurrentSim.Caps.CapabilityURI("ProvisionVoiceAccountRequest"); + var vCap = Client.Network.CurrentSim.Caps.CapabilityURI("ProvisionVoiceAccountRequest"); // Do we have voice capability? if (vCap == null) @@ -409,9 +371,8 @@ namespace OpenMetaverse.Voice 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); + var s = FindSession(e.SessionHandle, false); + s?.ParticipantUpdate(e.URI, e.IsMuted, e.IsSpeaking, e.Volume, e.Energy); } public string SIPFromUUID(UUID id) @@ -435,7 +396,7 @@ namespace OpenMetaverse.Voice // 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(); + var encbuff = id.GetBytes(); result += Convert.ToBase64String(encbuff); result = result.Replace('+', '-'); result = result.Replace('/', '_'); @@ -445,7 +406,7 @@ namespace OpenMetaverse.Voice void connector_OnSessionParticipantAddedEvent(object sender, ParticipantAddedEventArgs e) { - VoiceSession s = FindSession(e.SessionHandle, false); + var s = FindSession(e.SessionHandle, false); if (s == null) { Logger.Log("Orphan participant", Helpers.LogLevel.Error); @@ -456,9 +417,8 @@ namespace OpenMetaverse.Voice void connector_OnSessionParticipantRemovedEvent(object sender, ParticipantRemovedEventArgs e) { - VoiceSession s = FindSession(e.SessionHandle, false); - if (s == null) return; - s.RemoveParticipant(e.URI); + var s = FindSession(e.SessionHandle, false); + s?.RemoveParticipant(e.URI); } #endregion @@ -468,14 +428,13 @@ namespace OpenMetaverse.Voice sessionHandle = e.SessionHandle; // Create our session context. - VoiceSession s = FindSession(sessionHandle, true); + var s = FindSession(sessionHandle, true); s.RegionName = regionName; spatialSession = s; // Tell any user-facing code. - if (OnSessionCreate != null) - OnSessionCreate(s, null); + OnSessionCreate?.Invoke(s, null); Logger.Log("Added voice session in " + regionName, Helpers.LogLevel.Info); } @@ -489,7 +448,7 @@ namespace OpenMetaverse.Voice switch (e.State) { - case VoiceGateway.SessionState.Connected: + case SessionState.Connected: s = FindSession(e.SessionHandle, true); sessionHandle = e.SessionHandle; s.RegionName = regionName; @@ -497,11 +456,10 @@ namespace OpenMetaverse.Voice Logger.Log("Voice connected in " + regionName, Helpers.LogLevel.Info); // Tell any user-facing code. - if (OnSessionCreate != null) - OnSessionCreate(s, null); + OnSessionCreate?.Invoke(s, null); break; - case VoiceGateway.SessionState.Disconnected: + case SessionState.Disconnected: s = FindSession(sessionHandle, false); sessions.Remove(sessionHandle); @@ -510,8 +468,7 @@ namespace OpenMetaverse.Voice Logger.Log("Voice disconnected in " + s.RegionName, Helpers.LogLevel.Info); // Inform interested parties - if (OnSessionRemove != null) - OnSessionRemove(s, null); + OnSessionRemove?.Invoke(s, null); if (s == spatialSession) spatialSession = null; @@ -526,6 +483,20 @@ namespace OpenMetaverse.Voice RequestParcelInfo(currentParcelCap); } break; + case SessionState.Idle: + break; + case SessionState.Answering: + break; + case SessionState.InProgress: + break; + case SessionState.Hold: + break; + case SessionState.Refer: + break; + case SessionState.Ringing: + break; + default: + throw new ArgumentOutOfRangeException(); } @@ -544,7 +515,7 @@ namespace OpenMetaverse.Voice ReportConnectionState(ConnectionState.AccountLogin); // Clean up spatial pointers. - VoiceSession s = sessions[sessionHandle]; + var s = sessions[sessionHandle]; if (s.IsSpatial) { spatialSession = null; @@ -555,8 +526,7 @@ namespace OpenMetaverse.Voice sessions.Remove(sessionHandle); // Let any user-facing code clean up. - if (OnSessionRemove != null) - OnSessionRemove(s, null); + OnSessionRemove?.Invoke(s, null); // Tell SLVoice to clean it up as well. SessionTerminate(sessionHandle); @@ -574,7 +544,7 @@ namespace OpenMetaverse.Voice if (!make) return null; // Create a new session and add it to the sessions list. - VoiceSession s = new VoiceSession(this, sessionHandle); + var s = new VoiceSession(this, sessionHandle); // Turn on position updating for spatial sessions // (For now, only spatial sessions are supported) @@ -592,17 +562,14 @@ namespace OpenMetaverse.Voice void connector_OnAuxAudioPropertiesEvent(object sender, AudioPropertiesEventArgs e) { - if (OnVoiceMicTest != null) - OnVoiceMicTest(e.MicEnergy); + OnVoiceMicTest?.Invoke(e.MicEnergy); } #endregion private void ReportConnectionState(ConnectionState s) { - if (OnVoiceConnectionChange == null) return; - - OnVoiceConnectionChange(s); + OnVoiceConnectionChange?.Invoke(s); } /// @@ -611,8 +578,8 @@ namespace OpenMetaverse.Voice /// /// /// - void cClient_OnComplete(OpenMetaverse.Http.CapsClient client, - OpenMetaverse.StructuredData.OSD result, + void cClient_OnComplete(CapsClient client, + OSD result, Exception error) { if (error != null) @@ -624,25 +591,26 @@ namespace OpenMetaverse.Voice 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(); + if (result is OSDMap pMap) + { + 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)) + if (!File.Exists(slvoicePath)) { Logger.Log("SLVoice is missing", Helpers.LogLevel.Error); return; @@ -669,7 +637,7 @@ namespace OpenMetaverse.Voice void connector_OnDaemonRunning() { OnDaemonRunning -= - new VoiceGateway.DaemonRunningCallback(connector_OnDaemonRunning); + connector_OnDaemonRunning; Logger.Log("Daemon started", Helpers.LogLevel.Info); ReportConnectionState(ConnectionState.DaemonStarted); @@ -688,8 +656,8 @@ namespace OpenMetaverse.Voice ReportConnectionState(ConnectionState.DaemonConnected); // The connector is what does the logging. - VoiceGateway.VoiceLoggingSettings vLog = - new VoiceGateway.VoiceLoggingSettings(); + var vLog = + new VoiceLoggingSettings(); #if DEBUG_VOICE vLog.Enabled = true; @@ -698,7 +666,7 @@ namespace OpenMetaverse.Voice vLog.LogLevel = 4; #endif // STEP 3 - int reqId = ConnectorCreate( + var reqId = ConnectorCreate( "V2 SDK", // Magic value keeps SLVoice happy acctServer, // Account manager server 30000, 30099, // port range @@ -714,7 +682,7 @@ namespace OpenMetaverse.Voice /// void connector_OnConnectorCreateResponse( object sender, - VoiceGateway.VoiceConnectorEventArgs e) + VoiceConnectorEventArgs e) { Logger.Log("Voice daemon protocol started " + e.Message, Helpers.LogLevel.Info); @@ -737,9 +705,9 @@ namespace OpenMetaverse.Voice void connector_OnAccountLoginResponse( object sender, - VoiceGateway.VoiceAccountEventArgs e) + VoiceAccountEventArgs e) { - Logger.Log("Account Login " + e.Message, Helpers.LogLevel.Info); + Logger.Log($"Account Login {e.Message}", Helpers.LogLevel.Info); accountHandle = e.AccountHandle; ReportConnectionState(ConnectionState.AccountLogin); ParcelChanged(); @@ -751,9 +719,9 @@ namespace OpenMetaverse.Voice /// void connector_OnAuxGetRenderDevicesResponse( object sender, - VoiceGateway.VoiceDevicesEventArgs e) + VoiceDevicesEventArgs e) { - outputDevices = e.Devices; + PlaybackDevices = e.Devices; currentPlaybackDevice = e.CurrentDevice; } @@ -762,15 +730,15 @@ namespace OpenMetaverse.Voice /// void connector_OnAuxGetCaptureDevicesResponse( object sender, - VoiceGateway.VoiceDevicesEventArgs e) + VoiceDevicesEventArgs e) { - inputDevices = e.Devices; + CaptureDevices = e.Devices; currentCaptureDevice = e.CurrentDevice; } public string CurrentCaptureDevice { - get { return currentCaptureDevice; } + get => currentCaptureDevice; set { currentCaptureDevice = value; @@ -779,7 +747,7 @@ namespace OpenMetaverse.Voice } public string PlaybackDevice { - get { return currentPlaybackDevice; } + get => currentPlaybackDevice; set { currentPlaybackDevice = value; @@ -789,33 +757,21 @@ namespace OpenMetaverse.Voice public int MicLevel { - set - { - ConnectorSetLocalMicVolume(connectionHandle, value); - } + set => ConnectorSetLocalMicVolume(connectionHandle, value); } public int SpkrLevel { - set - { - ConnectorSetLocalSpeakerVolume(connectionHandle, value); - } + set => ConnectorSetLocalSpeakerVolume(connectionHandle, value); } public bool MicMute { - set - { - ConnectorMuteLocalMic(connectionHandle, value); - } + set => ConnectorMuteLocalMic(connectionHandle, value); } public bool SpkrMute { - set - { - ConnectorMuteLocalSpeaker(connectionHandle, value); - } + set => ConnectorMuteLocalSpeaker(connectionHandle, value); } /// @@ -823,7 +779,7 @@ namespace OpenMetaverse.Voice /// public bool TestMode { - get { return testing; } + get => testing; set { testing = value; @@ -855,8 +811,8 @@ namespace OpenMetaverse.Voice internal void ParcelChanged() { // Get the capability for this parcel. - Caps c = Client.Network.CurrentSim.Caps; - System.Uri pCap = c.CapabilityURI("ParcelVoiceInfoRequest"); + var c = Client.Network.CurrentSim.Caps; + var pCap = c.CapabilityURI("ParcelVoiceInfoRequest"); if (pCap == null) { @@ -875,7 +831,7 @@ namespace OpenMetaverse.Voice RequestParcelInfo(pCap); } - private OpenMetaverse.Http.CapsClient parcelCap; + private CapsClient parcelCap; /// /// Request info from a parcel capability Uri. @@ -886,13 +842,12 @@ namespace OpenMetaverse.Voice { Logger.Log("Requesting region voice info", Helpers.LogLevel.Info); - parcelCap = new OpenMetaverse.Http.CapsClient(cap, "RequestParcelInfo"); + parcelCap = new CapsClient(cap, "RequestParcelInfo"); parcelCap.OnComplete += pCap_OnComplete; - OSD postData = new OSD(); currentParcelCap = cap; - parcelCap.BeginGetResponse(postData, OSDFormat.Xml, 10000); + parcelCap.PostRequestAsync(new OSD(), OSDFormat.Xml, 10000); } /// @@ -901,12 +856,11 @@ namespace OpenMetaverse.Voice /// /// /// - void pCap_OnComplete(OpenMetaverse.Http.CapsClient client, - OpenMetaverse.StructuredData.OSD result, + void pCap_OnComplete(CapsClient client, + OSD result, Exception error) { - parcelCap.OnComplete -= - new OpenMetaverse.Http.CapsClient.CompleteCallback(pCap_OnComplete); + parcelCap.OnComplete -= pCap_OnComplete; parcelCap = null; if (error != null) @@ -915,20 +869,21 @@ namespace OpenMetaverse.Voice return; } - OpenMetaverse.StructuredData.OSDMap pMap = result as OpenMetaverse.StructuredData.OSDMap; - - regionName = pMap["region_name"].AsString(); - ReportConnectionState(ConnectionState.RegionCapAvailable); - - if (pMap.ContainsKey("voice_credentials")) + if (result is OSDMap pMap) { - OpenMetaverse.StructuredData.OSDMap cred = - pMap["voice_credentials"] as OpenMetaverse.StructuredData.OSDMap; + regionName = pMap["region_name"].AsString(); + ReportConnectionState(ConnectionState.RegionCapAvailable); - if (cred.ContainsKey("channel_uri")) - spatialUri = cred["channel_uri"].AsString(); - if (cred.ContainsKey("channel_credentials")) - spatialCredentials = cred["channel_credentials"].AsString(); + if (pMap.ContainsKey("voice_credentials")) + { + var cred = + pMap["voice_credentials"] as OSDMap; + + if (cred.ContainsKey("channel_uri")) + spatialUri = cred["channel_uri"].AsString(); + if (cred.ContainsKey("channel_credentials")) + spatialCredentials = cred["channel_credentials"].AsString(); + } } if (string.IsNullOrEmpty(spatialUri)) @@ -940,7 +895,7 @@ namespace OpenMetaverse.Voice Logger.Log("Voice connecting for region " + regionName, Helpers.LogLevel.Info); // STEP 5 - int reqId = SessionCreate( + var reqId = SessionCreate( accountHandle, spatialUri, // uri "", // Channel name seems to be always null @@ -962,7 +917,7 @@ namespace OpenMetaverse.Voice internal void UpdatePosition(AgentManager self) { // Get position in Global coordinates - Vector3d OMVpos = new Vector3d(self.GlobalPosition); + var OMVpos = new Vector3d(self.GlobalPosition); // Do not send trivial updates. if (OMVpos.ApproxEquals(oldPosition, 1.0)) @@ -979,7 +934,7 @@ namespace OpenMetaverse.Voice // Get azimuth from the facing Quaternion. // By definition, facing.W = Cos( angle/2 ) - double angle = 2.0 * Math.Acos(self.Movement.BodyRotation.W); + var 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)); @@ -1005,7 +960,7 @@ namespace OpenMetaverse.Voice private void PositionThreadBody() { var token = posTokenSource.Token; - while (true) + while (!token.IsCancellationRequested) { posRestart.WaitOne(); token.ThrowIfCancellationRequested(); diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceDefinitions.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceDefinitions.cs index 1bcce53..7d7f8c8 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceDefinitions.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceDefinitions.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -26,10 +27,10 @@ using System; using System.Collections.Generic; -using System.Xml; using System.Xml.Serialization; +using OpenMetaverse; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.Voice { public partial class VoiceGateway { @@ -424,16 +425,14 @@ namespace OpenMetaverse.Voice #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 string Version { get; } + public string Handle { get; } public VoiceConnectorEventArgs(int rcode, int scode, string text, string version, string handle) : base(ResponseType.ConnectorCreate, rcode, scode, text) { - m_Version = version; - m_ConnectorHandle = handle; + Version = version; + Handle = handle; } } @@ -443,16 +442,14 @@ namespace OpenMetaverse.Voice #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 string CurrentDevice { get; } + public List Devices { get; } 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; + CurrentDevice = current; + Devices = avail; } } @@ -478,13 +475,12 @@ namespace OpenMetaverse.Voice #region Account Event Args public class VoiceAccountEventArgs : VoiceResponseEventArgs { - private readonly string m_AccountHandle; - public string AccountHandle { get { return m_AccountHandle; } } + public string AccountHandle { get; } public VoiceAccountEventArgs(int rcode, int scode, string text, string ahandle) : base(ResponseType.AccountLogin, rcode, scode, text) { - this.m_AccountHandle = ahandle; + this.AccountHandle = ahandle; } } @@ -612,7 +608,7 @@ namespace OpenMetaverse.Voice public string RequestId; [XmlAttribute("action")] public string Action; - public string ReturnCode; + public int ReturnCode; public VoiceResponseResults Results; public VoiceInputXml InputXml; } @@ -630,7 +626,7 @@ namespace OpenMetaverse.Voice public class VoiceResponseResults { public string VersionID; - public string StatusCode; + public int StatusCode; public string StatusString; public string ConnectorHandle; public string AccountHandle; diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceGateway.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceGateway.cs index 202792b..90e8b9b 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceGateway.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceGateway.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -31,8 +32,9 @@ using System.Net.Sockets; using System.Diagnostics; using System.Threading; using System.Text; +using OpenMetaverse; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.Voice { public partial class VoiceGateway { @@ -50,9 +52,9 @@ namespace OpenMetaverse.Voice 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; } } + public bool DaemonIsRunning => daemonIsRunning; + public bool DaemonIsConnected => daemonIsConnected; + public int RequestId => requestId; protected Process daemonProcess; protected ManualResetEvent daemonLoopSignal = new ManualResetEvent(false); @@ -232,7 +234,7 @@ namespace OpenMetaverse.Voice if (daemonIsConnected) { StringBuilder sb = new StringBuilder(); - sb.Append(String.Format(""); @@ -267,10 +269,9 @@ namespace OpenMetaverse.Voice 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); + return string.IsNullOrEmpty(text) + ? string.Format("<{0} />", name) + : string.Format("<{0}>{1}", name, text); } private void daemonPipe_OnReceiveLine(string line) @@ -299,26 +300,23 @@ namespace OpenMetaverse.Voice // These first responses carry useful information beyond simple status, // so they each have a specific Event. case "Connector.Create.1": - if (OnConnectorCreateResponse != null) - { - OnConnectorCreateResponse( - rsp.InputXml.Request, - new VoiceConnectorEventArgs( - int.Parse(rsp.ReturnCode), - int.Parse(rsp.Results.StatusCode), - rsp.Results.StatusString, - rsp.Results.VersionID, - rsp.Results.ConnectorHandle)); - } + OnConnectorCreateResponse?.Invoke( + rsp.InputXml.Request, + new VoiceConnectorEventArgs( + rsp.ReturnCode, + rsp.Results.StatusCode, + rsp.Results.StatusString, + rsp.Results.VersionID, + rsp.Results.ConnectorHandle)); break; case "Aux.GetCaptureDevices.1": - inputDevices = new List(); + CaptureDevices = new List(); if (rsp.Results.CaptureDevices.Count == 0 || rsp.Results.CurrentCaptureDevice == null) break; foreach (CaptureDevice device in rsp.Results.CaptureDevices) - inputDevices.Add(device.Device); + CaptureDevices.Add(device.Device); currentCaptureDevice = rsp.Results.CurrentCaptureDevice.Device; if (OnAuxGetCaptureDevicesResponse != null && rsp.Results.CaptureDevices.Count > 0) @@ -327,21 +325,21 @@ namespace OpenMetaverse.Voice rsp.InputXml.Request, new VoiceDevicesEventArgs( ResponseType.GetCaptureDevices, - int.Parse(rsp.ReturnCode), - int.Parse(rsp.Results.StatusCode), + rsp.ReturnCode, + rsp.Results.StatusCode, rsp.Results.StatusString, rsp.Results.CurrentCaptureDevice.Device, - inputDevices)); + CaptureDevices)); } break; case "Aux.GetRenderDevices.1": - outputDevices = new List(); + PlaybackDevices = new List(); if (rsp.Results.RenderDevices.Count == 0 || rsp.Results.CurrentRenderDevice == null) break; foreach (RenderDevice device in rsp.Results.RenderDevices) - outputDevices.Add(device.Device); + PlaybackDevices.Add(device.Device); currentPlaybackDevice = rsp.Results.CurrentRenderDevice.Device; @@ -352,11 +350,11 @@ namespace OpenMetaverse.Voice rsp.InputXml.Request, new VoiceDevicesEventArgs( ResponseType.GetCaptureDevices, - int.Parse(rsp.ReturnCode), - int.Parse(rsp.Results.StatusCode), + rsp.ReturnCode, + rsp.Results.StatusCode, rsp.Results.StatusString, rsp.Results.CurrentRenderDevice.Device, - outputDevices)); + PlaybackDevices)); } break; @@ -365,8 +363,8 @@ namespace OpenMetaverse.Voice { OnAccountLoginResponse(rsp.InputXml.Request, new VoiceAccountEventArgs( - int.Parse(rsp.ReturnCode), - int.Parse(rsp.Results.StatusCode), + rsp.ReturnCode, + rsp.Results.StatusCode, rsp.Results.StatusString, rsp.Results.AccountHandle)); } @@ -378,8 +376,8 @@ namespace OpenMetaverse.Voice OnSessionCreateResponse( rsp.InputXml.Request, new VoiceSessionEventArgs( - int.Parse(rsp.ReturnCode), - int.Parse(rsp.Results.StatusCode), + rsp.ReturnCode, + rsp.Results.StatusCode, rsp.Results.StatusString, rsp.Results.SessionHandle)); } @@ -456,8 +454,8 @@ namespace OpenMetaverse.Voice OnVoiceResponse(rsp.InputXml.Request, new VoiceResponseEventArgs( genericResponse, - int.Parse(rsp.ReturnCode), - int.Parse(rsp.Results.StatusCode), + rsp.ReturnCode, + rsp.Results.StatusCode, rsp.Results.StatusString)); } } @@ -478,15 +476,12 @@ namespace OpenMetaverse.Voice { case "LoginStateChangeEvent": case "AccountLoginStateChangeEvent": - if (OnAccountLoginStateChangeEvent != null) - { - OnAccountLoginStateChangeEvent(this, - new AccountLoginStateChangeEventArgs( - evt.AccountHandle, - int.Parse(evt.StatusCode), - evt.StatusString, - (LoginState)int.Parse(evt.State))); - } + OnAccountLoginStateChangeEvent?.Invoke(this, + new AccountLoginStateChangeEventArgs( + evt.AccountHandle, + int.Parse(evt.StatusCode), + evt.StatusString, + (LoginState)int.Parse(evt.State))); break; case "SessionNewEvent": diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceManager.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceManager.cs new file mode 100644 index 0000000..0e11b2d --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceManager.cs @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. + * 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.co 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 OpenMetaverse.StructuredData; +using OpenMetaverse; +using OpenMetaverse.Http; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Messages.Linden; + +namespace LibreMetaverse.Voice +{ + 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; + private bool isChannel; + private bool isLocallyMuted; + private bool isModeratorMuted; + private bool isSpeaking; + private int cookie; + //private int returnCode; + private int statusCode; + private int volume; + private int state; + private int participantType; + private float energy; + 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", 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 += _DaemonPipe_OnDisconnected; + _DaemonPipe.OnReceiveLine += _DaemonPipe_OnReceiveLine; + + var se = _DaemonPipe.Connect(address, port); + + if (se == null) + { + return true; + } + 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) + { + var 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('+', '-'); + var idBytes = Convert.FromBase64String(accountName); + + return idBytes.Length == 16 ? new UUID(idBytes, 0) : UUID.Zero; + } + return UUID.Zero; + } + + public string SIPURIFromVoiceAccount(string account) + { + return $"sip:{account}@{VoiceServer}"; + } + + public int RequestCaptureDevices() + { + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes( + $"{REQUEST_TERMINATOR}")); + + return _CommandCookie - 1; + } + 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( + $"{REQUEST_TERMINATOR}")); + + return _CommandCookie - 1; + } + 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; + + var accountServer = $"https://www.{VoiceServer}/api2/"; + var logPath = "."; + + var request = new StringBuilder(); + request.Append($""); + request.Append("V2 SDK"); + request.Append($"{accountServer}"); + request.Append(""); + request.Append("false"); + request.Append($"{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) + { + var url = Client.Network.CurrentSim.Caps.CapabilityURI(capsName); + + if (url != null) + { + var request = new CapsClient(url); + var body = new OSDMap(); + request.OnComplete += callback; + request.PostRequestAsync(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); + + return true; + } + 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) + { + var request = new StringBuilder(); + request.Append($""); + request.Append($"{connectorHandle}"); + request.Append($"{accountName}"); + request.Append($"{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( + $"{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( + $"{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( + $"{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", nameof(volume_)); + + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes( + $"{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", nameof(volume_)); + + if (_DaemonPipe.Connected) + { + _DaemonPipe.SendData(Encoding.ASCII.GetBytes( + $"{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( + $"{_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( + $"{_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) + { + var msg = (RequiredVoiceVersionMessage)message; + + if (VOICE_MAJOR_VERSION != msg.MajorVersion) + { + Logger.Log( + $"Voice version mismatch! Got {msg.MajorVersion}, expecting {VOICE_MAJOR_VERSION}. Disabling the voice manager", 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 respMap)) return; + + if (OnProvisionAccount == null) return; + try { OnProvisionAccount(respMap["username"].AsString(), respMap["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 respMap)) return; + + var regionName = respMap["region_name"].AsString(); + var localID = respMap["parcel_local_id"].AsInteger(); + + string channelURI = null; + if (respMap["voice_credentials"] is OSDMap) + { + var creds = (OSDMap)respMap["voice_credentials"]; + channelURI = creds["channel_uri"].AsString(); + } + + OnParcelVoiceInfo?.Invoke(regionName, localID, channelURI); + } + + private static void _DaemonPipe_OnDisconnected(SocketException se) + { + if (se != null) Console.WriteLine("Disconnected! " + se.Message); + else Console.WriteLine("Disconnected!"); + } + + private void _DaemonPipe_OnReceiveLine(string line) + { + var 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 (var i = 0; i < reader.AttributeCount; i++) + { + reader.MoveToAttribute(i); + + if (reader.Name == "action") + actionString = reader.Value; + else if (reader.Name == "type") + eventTypeString = reader.Value; + } + } + } + else + { + switch (reader.Name) + { + case "InputXml": + cookie = -1; + + // Parse through here to get the cookie value + reader.Read(); + if (reader.Name == "Request") + { + for (var i = 0; i < reader.AttributeCount; i++) + { + reader.MoveToAttribute(i); + + if (reader.Name != "requestId") continue; + int.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; + case XmlNodeType.None: + break; + case XmlNodeType.Attribute: + break; + case XmlNodeType.Text: + break; + case XmlNodeType.CDATA: + break; + case XmlNodeType.EntityReference: + break; + case XmlNodeType.Entity: + break; + case XmlNodeType.ProcessingInstruction: + break; + case XmlNodeType.Comment: + break; + case XmlNodeType.Document: + break; + case XmlNodeType.DocumentType: + break; + case XmlNodeType.DocumentFragment: + break; + case XmlNodeType.Notation: + break; + case XmlNodeType.Whitespace: + break; + case XmlNodeType.SignificantWhitespace: + break; + case XmlNodeType.EndEntity: + break; + case XmlNodeType.XmlDeclaration: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + if (isEvent) + { + } + + //Client.DebugLog("VOICE: " + line); + } + + private void ProcessEvent() + { + if (isEvent) + { + switch (eventTypeString) + { + case "LoginStateChangeEvent": + OnLoginStateChange?.Invoke(cookie, accountHandle, statusCode, statusString, state); + break; + case "SessionNewEvent": + OnNewSession?.Invoke(cookie, accountHandle, eventSessionHandle, state, nameString, uriString); + break; + case "SessionStateChangeEvent": + OnSessionStateChange?.Invoke(cookie, uriString, statusCode, statusString, eventSessionHandle, state, isChannel, nameString); + break; + case "ParticipantStateChangeEvent": + OnParticipantStateChange?.Invoke(cookie, uriString, statusCode, statusString, state, nameString, displayNameString, participantType); + break; + case "ParticipantPropertiesEvent": + OnParticipantProperties?.Invoke(cookie, uriString, statusCode, statusString, isLocallyMuted, isModeratorMuted, isSpeaking, volume, energy); + break; + case "AuxAudioPropertiesEvent": + OnAuxAudioProperties?.Invoke(cookie, energy); + break; + } + } + else + { + switch (actionString) + { + case "Connector.Create.1": + OnConnectorCreated?.Invoke(cookie, statusCode, statusString, connectorHandle); + break; + case "Account.Login.1": + OnLogin?.Invoke(cookie, statusCode, statusString, accountHandle); + break; + case "Session.Create.1": + OnSessionCreated?.Invoke(cookie, statusCode, statusString, sessionHandle); + break; + case "Session.Connect.1": + OnSessionConnected?.Invoke(cookie, statusCode, statusString); + break; + case "Session.Terminate.1": + OnSessionTerminated?.Invoke(cookie, statusCode, statusString); + break; + case "Account.Logout.1": + OnAccountLogout?.Invoke(cookie, statusCode, statusString); + break; + case "Connector.InitiateShutdown.1": + OnConnectorInitiateShutdown?.Invoke(cookie, statusCode, statusString); + break; + case "Account.ChannelGetList.1": + OnAccountChannelGetList?.Invoke(cookie, statusCode, statusString); + break; + case "Aux.GetCaptureDevices.1": + OnCaptureDevices?.Invoke(cookie, statusCode, statusString, nameString); + break; + case "Aux.GetRenderDevices.1": + OnRenderDevices?.Invoke(cookie, statusCode, statusString, nameString); + break; + } + } + } + + #endregion Callbacks + } +} diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceManager.cs.meta b/Assets/Plugins/LibreMetaverse/Voice/VoiceManager.cs.meta new file mode 100644 index 0000000..cb74384 --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41f5cff506a7762458aa0fa06a3a635b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceManagerBlocking.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceManagerBlocking.cs new file mode 100644 index 0000000..e066f60 --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceManagerBlocking.cs @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. + * 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.co 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.Threading; + +namespace LibreMetaverse.Voice +{ + 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() + { + var evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestCaptureDevices() == -1) + { + Events.Remove(_CommandCookie); + return new List(); + } + + return evt.WaitOne(BlockingTimeout, false) ? CurrentCaptureDevices() : new List(); + } + + public List RenderDevices() + { + var evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestRenderDevices() == -1) + { + Events.Remove(_CommandCookie); + return new List(); + } + + return evt.WaitOne(BlockingTimeout, false) ? CurrentRenderDevices() : new List(); + } + + public string CreateConnector(out int status) + { + status = 0; + + var evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestCreateConnector() == -1) + { + Events.Remove(_CommandCookie); + return string.Empty; + } + + var success = evt.WaitOne(BlockingTimeout, false); + status = statusCode; + + return success && statusCode == 0 ? connectorHandle : string.Empty; + } + + public string Login(string accountName, string password, string connectorHandle, out int status) + { + status = 0; + + var evt = new AutoResetEvent(false); + Events[_CommandCookie] = evt; + + if (RequestLogin(accountName, password, connectorHandle) == -1) + { + Events.Remove(_CommandCookie); + return string.Empty; + } + + var success = evt.WaitOne(BlockingTimeout, false); + status = statusCode; + + return success && statusCode == 0 ? accountHandle : string.Empty; + } + + protected void RegisterCallbacks() + { + OnCaptureDevices += VoiceManager_OnCaptureDevices; + OnRenderDevices += VoiceManager_OnRenderDevices; + OnConnectorCreated += VoiceManager_OnConnectorCreated; + OnLogin += 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/Assets/Plugins/LibreMetaverse/Voice/VoiceManagerBlocking.cs.meta b/Assets/Plugins/LibreMetaverse/Voice/VoiceManagerBlocking.cs.meta new file mode 100644 index 0000000..fe29ad2 --- /dev/null +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceManagerBlocking.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b80357650347d34e93d925b1fb0941d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceParticipant.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceParticipant.cs index 135d9a2..6a8a56e 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceParticipant.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceParticipant.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -25,34 +26,29 @@ */ using System; -using System.Collections.Generic; -using System.Linq; using System.Text; using System.Text.RegularExpressions; +using OpenMetaverse; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.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; + private readonly VoiceSession session; - 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 float Energy { get; private set; } + public bool IsSpeaking { get; private set; } + public string URI { get; } + public UUID ID { get; } public VoiceParticipant(string puri, VoiceSession s) { - id = IDFromName(puri); - Sip = puri; + ID = IDFromName(puri); + URI = puri; session = s; } @@ -92,7 +88,7 @@ namespace OpenMetaverse.Voice private static string Encode64(string str) { - byte[] encbuff = System.Text.Encoding.UTF8.GetBytes(str); + byte[] encbuff = Encoding.UTF8.GetBytes(str); return Convert.ToBase64String(encbuff); } private static byte[] Decode64(string str) @@ -116,43 +112,43 @@ namespace OpenMetaverse.Voice public string Name { - get { return AvatarName; } - set { AvatarName = value; } + get => AvatarName; + set => AvatarName = value; } public bool IsMuted { - get { return muted; } + get => 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")); + sb.Append(VoiceGateway.MakeXML("SessionHandle", session.Handle)); + sb.Append(VoiceGateway.MakeXML("ParticipantURI", URI)); + sb.Append(VoiceGateway.MakeXML("Mute", muted ? "1" : "0")); session.Connector.Request("Session.SetParticipantMuteForMe.1", sb.ToString()); } } public int Volume { - get { return volume; } + get => 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())); + sb.Append(VoiceGateway.MakeXML("SessionHandle", session.Handle)); + sb.Append(VoiceGateway.MakeXML("ParticipantURI", URI)); + sb.Append(VoiceGateway.MakeXML("Volume", volume.ToString())); session.Connector.Request("Session.SetParticipantVolumeForMe.1", sb.ToString()); } } internal void SetProperties(bool speak, bool mute, float en) { - speaking = speak; + IsSpeaking = speak; muted = mute; - energy = en; + Energy = en; } } } diff --git a/Assets/Plugins/LibreMetaverse/Voice/VoiceSession.cs b/Assets/Plugins/LibreMetaverse/Voice/VoiceSession.cs index aadc96e..7239275 100644 --- a/Assets/Plugins/LibreMetaverse/Voice/VoiceSession.cs +++ b/Assets/Plugins/LibreMetaverse/Voice/VoiceSession.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021-2022, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -24,27 +25,23 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System; using System.Collections.Generic; +using System.Globalization; using System.Text; -using OpenMetaverse; -namespace OpenMetaverse.Voice +namespace LibreMetaverse.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 bool IsSpatial { get; } - public VoiceGateway Connector { get { return connector; } } - public string Handle { get { return m_Handle; } } + public VoiceGateway Connector { get; } + public string Handle { get; } public event System.EventHandler OnParticipantAdded; public event System.EventHandler OnParticipantUpdate; @@ -52,10 +49,10 @@ namespace OpenMetaverse.Voice public VoiceSession(VoiceGateway conn, string handle) { - m_Handle = handle; - connector = conn; + Handle = handle; + Connector = conn; - m_spatial = true; + IsSpatial = true; knownParticipants = new Dictionary(); } @@ -150,7 +147,7 @@ namespace OpenMetaverse.Voice public void Set3DPosition(VoicePosition SpeakerPosition, VoicePosition ListenerPosition) { - connector.SessionSet3DPosition(m_Handle, SpeakerPosition, ListenerPosition); + Connector.SessionSet3DPosition(Handle, SpeakerPosition, ListenerPosition); } } @@ -263,56 +260,56 @@ namespace OpenMetaverse.Voice 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(VoiceGateway.MakeXML("X", SpeakerPosition.Position.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.Position.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.Position.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", SpeakerPosition.Velocity.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.Velocity.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.Velocity.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", SpeakerPosition.AtOrientation.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.AtOrientation.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.AtOrientation.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", SpeakerPosition.UpOrientation.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.UpOrientation.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.UpOrientation.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", SpeakerPosition.LeftOrientation.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", SpeakerPosition.LeftOrientation.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", SpeakerPosition.LeftOrientation.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", ListenerPosition.Position.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.Position.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.Position.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", ListenerPosition.Velocity.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.Velocity.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.Velocity.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", ListenerPosition.AtOrientation.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.AtOrientation.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.AtOrientation.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", ListenerPosition.UpOrientation.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.UpOrientation.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.UpOrientation.Z.ToString(CultureInfo.InvariantCulture))); 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(VoiceGateway.MakeXML("X", ListenerPosition.LeftOrientation.X.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Y", ListenerPosition.LeftOrientation.Y.ToString(CultureInfo.InvariantCulture))); + sb.Append(VoiceGateway.MakeXML("Z", ListenerPosition.LeftOrientation.Z.ToString(CultureInfo.InvariantCulture))); sb.Append(""); sb.Append(""); return Request("Session.Set3DPosition.1", sb.ToString()); diff --git a/Assets/Plugins/LibreMetaverse/_Packets_.cs b/Assets/Plugins/LibreMetaverse/_Packets_.cs index 6a82ae8..096c5f3 100644 --- a/Assets/Plugins/LibreMetaverse/_Packets_.cs +++ b/Assets/Plugins/LibreMetaverse/_Packets_.cs @@ -25,8 +25,6 @@ */ using System; -using System.Text; -using OpenMetaverse; namespace OpenMetaverse { @@ -76692,7 +76690,7 @@ namespace OpenMetaverse.Packets if (TextureEntry != null) { length += Math.Min(TextureEntry.Length, 65535); } if (TextureAnim != null) { length += (byte)TextureAnim.Length; } if (NameValue != null) { length += Math.Min(NameValue.Length, 65535); } - if (Data != null) { length += Math.Min(Data.Length, 65535); ; } + if (Data != null) { length += Math.Min(Data.Length, 65535); } if (Text != null) { length += (byte)Text.Length; } if (MediaURL != null) { length += (byte)MediaURL.Length; } if (PSBlock != null) { length += (byte)PSBlock.Length; } diff --git a/Assets/Plugins/OggVorbisEncoder.dll b/Assets/Plugins/OggVorbisEncoder.dll new file mode 100644 index 0000000..d019de2 Binary files /dev/null and b/Assets/Plugins/OggVorbisEncoder.dll differ diff --git a/Assets/Plugins/OggVorbisEncoder.dll.meta b/Assets/Plugins/OggVorbisEncoder.dll.meta new file mode 100644 index 0000000..9b4d26a --- /dev/null +++ b/Assets/Plugins/OggVorbisEncoder.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: afe79d3aa99f00f4786a041144e1381c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/OpenJpegDotNet.dll b/Assets/Plugins/OpenJpegDotNet.dll new file mode 100644 index 0000000..ccbad8d Binary files /dev/null and b/Assets/Plugins/OpenJpegDotNet.dll differ diff --git a/Assets/Plugins/OpenJpegDotNet.dll.meta b/Assets/Plugins/OpenJpegDotNet.dll.meta new file mode 100644 index 0000000..30fc99f --- /dev/null +++ b/Assets/Plugins/OpenJpegDotNet.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: b40d6b883361a0d40921720d88966596 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/OpenJpegDotNet.xml b/Assets/Plugins/OpenJpegDotNet.xml new file mode 100644 index 0000000..8078335 --- /dev/null +++ b/Assets/Plugins/OpenJpegDotNet.xml @@ -0,0 +1,1487 @@ + + + + OpenJpegDotNet + + + + + Specifies the Digital cinema operation mode. + + + + + Specifies that not Digital Cinema. + + + + + Specifies that the 2K Digital Cinema at 24 fps. + + + + + Specifies that the 2K Digital Cinema at 48 fps. + + + + + Specifies that the 4K Digital Cinema at 24 fps. + + + + + Defines the JPEG 2000 codec V2. This class cannot be inherited. + + + + + Releases all unmanaged resources. + + + + + Specifies the supported codec. + + + + + Specifies that the place-holder. + + + + + Specifies that the JPEG 2000 codestream. + + + + + Specifies that the JPT-stream (JPEG 2000, JPIP). + + + + + Specifies that the JP2 file format. + + + + + Specifies that the JPP-stream (JPEG 2000, JPIP). + + + + + Specifies that the JPX file format(JPEG 2000 Part-2). + + + + + Specifies the Supported image color spaces. + + + + + Specifies that not supported by the library. + + + + + Specifies that not specified in the codestream. + + + + + Specifies that the sRGB. + + + + + Specifies that the Grayscale. + + + + + Specifies that the sYCC. + + + + + Specifies that the e-YCC. + + + + + Specifies that the CMYK. + + + + + Defines the compression parameters. This class cannot be inherited. + + + + + Initializes a new instance of the class. + + + + + Sets or get the error protection methods for Tile Part Headers (0,1,16,32,37-128). + + This object is disposed. + is invalid length. + + + + Sets or get the tile number of header protection specification (>=0). + + This object is disposed. + is invalid length. + + + + Sets or get the error protection methods for packets (0,1,16,32,37-128). + + This object is disposed. + is invalid length. + + + + Sets or get the packet number of packet protection specification (>=0). + + This object is disposed. + is invalid length. + + + + Sets or get the tile number of packet protection specification (>=0). + + This object is disposed. + is invalid length. + + + + Sets or get the sensitivity methods for Tile Part Headers (-1=no,0-7). + + This object is disposed. + is invalid length. + + + + Sets or get the tile number of sensitivity specification (>=0). + + This object is disposed. + is invalid length. + + + + Sets or get the initial precinct height. + + This object is disposed. + is invalid length. + + + + Sets or get the initial precinct width. + + This object is disposed. + is invalid length. + + + + Sets or get the different PSNR (Peak signal-to-noise ratio) for successive layers. + + This object is disposed. + is invalid length. + + + + Sets or get the rates of layers - might be subsequently limited by the max_cs_size field. + + This object is disposed. + is invalid length. + + + + Sets or get the initial code block height. + + This object is disposed. + + + + Sets or get the initial code block width. + + This object is disposed. + + + + Sets or get the output file format. + + This object is disposed. + + + + Sets or get the Digital Cinema compliance. + + if 0 not compliant, 1 is compliant. + This object is disposed. + + + + Sets or get the RSIZ. + + This object is disposed. + + + + Sets or get the allocation by rate/distortion. + + This object is disposed. + + + + Sets or get the allocation by fixed layer. + + This object is disposed. + + + + Sets or get the add fixed quality. + + This object is disposed. + + + + Sets or get the regions size + + This object is disposed. + + + + Sets or get the XTsiz. + + This object is disposed. + + + + Sets or get the YTsiz. + + This object is disposed. + + + + Sets or get the XTOsiz. + + This object is disposed. + + + + Sets or get the YTOsiz. + + This object is disposed. + + + + Sets or get the coding style. + + This object is disposed. + + + + Sets or get the input file format. + + This object is disposed. + + + + Sets or get the subimage encoding: origin image offset in x direction. + + This object is disposed. + + + + Sets or get the subimage encoding: origin image offset in y direction. + + This object is disposed. + + + + Sets or get the index generation. + + This object is disposed. + + + + Sets or get the value to indicate whether irreversible or not for compression. + + true if use the irreversible DWT 9-7; otherwise, use lossless compression is false. + This object is disposed. + + + + Sets or get the error protection method for Main Header (0,1,16,32,37-128). + + This object is disposed. + + + + Sets or get the sensitivity addressing size (0=auto/2/4 bytes). + + This object is disposed. + + + + Sets or get the sensitivity method for Main Header (-1=no,0-7). + + This object is disposed. + + + + Sets or get the sensitivity range (0-3). + + This object is disposed. + + + + Sets or get the enables writing of ESD, (0=no/1/2 bytes). + + This object is disposed. + + + + Sets or get the maximum size (in bytes) for each component. + + Component size limitation is not considered if 0. + This object is disposed. + + + + Sets or get the maximum size (in bytes) for the whole codestream. + + If 0, codestream size limitation is not considered If it does not comply with , prevails and a warning is issued. + This object is disposed. + + + + Sets or get the mode switch (codeblock coding style). + + This object is disposed. + + + + Sets or get the number of progression order changes (POC). + + This object is disposed. + + + + Sets or get the number of resolutions. + + This object is disposed. + + + + Sets or get the progression order. + + This object is disposed. + + + + Sets or get the number of precinct size specifications. + + This object is disposed. + + + + Sets or get the region of interest: affected component in [0..3], -1 means no ROI. + + This object is disposed. + + + + Sets or get the region of interest: upshift value. + + This object is disposed. + + + + Sets or get the subsampling value for dx. + + This object is disposed. + + + + Sets or get the subsampling value for dy. + + This object is disposed. + + + + Sets or get the number of layers. + + This object is disposed. + + + + Sets or get whether enables JPIP indexing. + + This object is disposed. + + + + Sets or get whether enables writing of EPC in MH, thus activating JPWL. + + This object is disposed. + + + + Sets or get the MCT (multiple component transform). + + This object is disposed. + + + + Sets or get whether enables size of tile. + + This object is disposed. + + + + Sets or get the flag for Tile part generation. + + This object is disposed. + + + + Sets or get the Tile part generation. + + This object is disposed. + + + + Releases all unmanaged resources. + + + + + Defines the decompression parameters. This class cannot be inherited. + + + + + Initializes a new instance of the class. + + + + + Sets or get the output file format. + + This object is disposed. + + + + Sets or get the maximum number of quality layers to decode. + + This object is disposed. + + + + Sets or get the number of highest resolution levels to be discarded. + + This object is disposed. + + + + Sets or get the input file format. + + This object is disposed. + + + + Sets or get the decoding area left boundary. + + This object is disposed. + + + + Sets or get the decoding area right boundary. + + This object is disposed. + + + + Sets or get the decoding area up boundary. + + This object is disposed. + + + + Sets or get the decoding area bottom boundary. + + This object is disposed. + + + + Sets or get the flags. + + This object is disposed. + + + + Sets or get whether activates the JPWL correction capabilities for JPWL (wireless applications). + + This object is disposed. + + + + Sets or get the expected number of components for JPWL (wireless applications). + + This object is disposed. + + + + Sets or get the maximum number of tiles for JPWL (wireless applications). + + This object is disposed. + + + + Sets or get the number of blocks of tile to decode. + + This object is disposed. + + + + Sets or get the tile number of the decoded tile. + + This object is disposed. + + + + Sets or get whether enables verbose mode. + + This object is disposed. + + + + Releases all unmanaged resources. + + + + + Callback function prototype for read. + + The event message. + The client object where will be return the event message. + + + + Callback function prototype for read. + + The position to read. + The length of . + The data pointer to have beee passed to . + + + + Callback function prototype for write. + + The position to write. + The length of . + The data pointer to have beee passed to . + + + + Callback function prototype for skip. + + The position to skip. + The data pointer to have beee passed to . + + + + Callback function prototype for seek. + + The position to seek. + The data pointer to have beee passed to . + + + + Callback function to free user data. + + The data pointer to have beee passed to . + + + + Specifies the supported codec. + + + + + Specifies that the place-holder. + + + + + Specifies that the JPEG 2000 codestream. + + + + + Specifies that the JP2 file format. + + + + + Specifies that the JPT-stream (JPEG 2000, JPIP). + + + + + Specifies that the Pixelmator file format. + + + + + Specifies that the PGX (JPEG 2000) file format. + + + + + Specifies that the Bitmap file format. + + + + + Specifies that the YUV file format. + + + + + Specifies that the Tagged Image file format. + + + + + Specifies that the Raw (big endian) Image file format. + + + + + Specifies that the Truevision Graphics Adapter file format. + + + + + Specifies that the Portable Network Graphics file format. + + + + + Specifies that the Raw (little endian) Image file format. + + + + + Defines the image data and characteristics. This class cannot be inherited. + + + + + Gets or sets the horizontal offset from the origin of the reference grid to the left side of the image area. + + This object is disposed. + + + + Gets or sets the width of the reference grid. + + This object is disposed. + + + + Gets or sets the vertical offset from the origin of the reference grid to the top side of the image area. + + This object is disposed. + + + + Gets or sets the height of the reference grid. + + This object is disposed. + + + + Gets the number of components in the image. + + This object is disposed. + + + + Gets or sets the color space. + + This object is disposed. + + + + Gets the image components. + + This object is disposed. + + + + Gets the 'restricted' ICC profile. + + This object is disposed. + + + + Converts this to a GDI+ . + + Export alpha channel + A that represents the converted . + This object is disposed. + This object is not supported. + + + + Converts this to a Bitmap . + + Export alpha channel + A that represents the converted . + This object is not supported. + + + + Converts this to a TARGA . + + A that represents the converted . + This object is not supported. + + + + Releases all unmanaged resources. + + + + + Defines the image component. This class cannot be inherited. + + + + + Get the alpha channel. + + This object is disposed. + + + + Get the image depth in bits. + + This object is disposed. + + + + Get the image component data. + + This object is disposed. + + + + Get the horizontal separation of a sample of ith component with respect to the reference grid. + + This object is disposed. + + + + Get the vertical separation of a sample of ith component with respect to the reference grid. + + This object is disposed. + + + + Get the number of division by 2 of the out image compared to the original size of image. + + This object is disposed. + + + + Get the data height. + + This object is disposed. + + + + Get the precision. + + This object is disposed. + + + + Get the number of decoded resolution. + + This object is disposed. + + + + Get the value to indicate whether data with signed or unsigned. + + true if data with signed; otherwise, false. + This object is disposed. + + + + Get the data width. + + This object is disposed. + + + + Get the x component offset compared to the whole image. + + This object is disposed. + + + + Get the y component offset compared to the whole image. + + This object is disposed. + + + + Releases all unmanaged resources. + + + + + Defines the component parameters. This class cannot be inherited. + + + + + Initializes a new instance of the class. + + + + + Sets or get the image depth in bits. + + This object is disposed. + + + + Sets or get the horizontal separation of a sample of ith component with respect to the reference grid. + + This object is disposed. + + + + Sets or get the vertical separation of a sample of ith component with respect to the reference grid. + + This object is disposed. + + + + Sets or get the data height. + + This object is disposed. + + + + Sets or get the precision. + + This object is disposed. + + + + Sets or get the value to indicate whether data with signed or unsigned. + + true if data with signed; otherwise, false. + This object is disposed. + + + + Sets or get the data width. + + This object is disposed. + + + + Sets or get the x component offset compared to the whole image. + + This object is disposed. + + + + Sets or get the y component offset compared to the whole image. + + This object is disposed. + + + + Releases all unmanaged resources. + + + + + Gets a value indicating whether this instance has been disposed. + + true if this instance has been disposed; otherwise, false. + + + + Releases all resources used by this . + + + + + Releases all resources used by this . + + Indicate value whether method was called. + + + + Gets a value indicating whether this instance has been disposed. + + true if this instance has been disposed; otherwise, false. + + + + Releases all resources used by this . + + + + + Releases all resources used by this . + + Indicate value whether method was called. + + + + Provides the methods of OpenJpeg. + + + Provides the methods of OpenJpeg. + + + + + Creates a J2K/JP2 compression structure. + + The codec format to create. + The . + + + + Start to compress the current image. + + the Jpeg 2000 codec to compress. + The image that receives encoded datum. + The Jpeg 2000 stream. + true if the start to compress is correctly set; otherwise, false. + , or is null. + , or is disposed. + + + + End to compress the current image. + + the Jpeg 2000 codec to compress. + The Jpeg 2000 stream. + true if the end to compress is correctly set; otherwise, false. + or is null. + or is disposed. + + + + Encode an image into a JPEG-2000 codestream. + + the Jpeg 2000 codec to compress. + The Jpeg 2000 stream. + true if the end to compress is correctly set; otherwise, false. + or is null. + or is disposed. + + + + Set encoding parameters to default values. + + The to compress image. + is null. + is disposed. + + + + Setup the encoder with compression parameters provided by the user and with the message handler provided by the user. + + The to compress image. + The for image compression. + Input filled image. + true if the decoder is correctly set; otherwise, false. + , or is null. + , or is disposed. + + + + Creates a J2K/JP2 decompression structure. + + The codec format to create. + The . + + + + Decode an image from a JPEG 2000 codestream. + + the Jpeg 2000 codec to read. + The Jpeg 2000 stream. + The image that receives decoded datum. + true if success; otherwise, false. + , or is null. + , or is disposed. + + + + Read after the codestream if necessary. + + the Jpeg 2000 codec to read. + The Jpeg 2000 stream. + true if success; otherwise, false. + or is null. + or is disposed. + + + + Decodes an image header. + + The Jpeg 2000 stream. + the Jpeg 2000 codec to read. + When this method returns, contains the read from stream. This parameter is passed uninitialized. + true if the main header of the codestream and the JP2 header is correctly read; otherwise, false. + or is null. + or is disposed. + + + + Sets the given area to be decoded. + + The Jpeg 2000 codec. + The decoded previously set by . + The left position of the rectangle to decode in image. + The top position of the rectangle to decode in image. + The right position of the rectangle to decode in image. + The bottom position of the rectangle to decode in image. + true if the area is correctly set; otherwise, false. + or is null. + or is disposed. + + + + Set decoding parameters to default values. + + The to decompress image. + is null. + is disposed. + + + + Setup the decoder with decompression parameters provided by the user and with the message handler provided by the user. + + The to decompress image. + The to decompress image. + true if the decoder is correctly set; otherwise, false. + or is null. + or is disposed. + + + + Allocates worker threads for the compressor/decompressor. + + The to compress or decompress image. + The number of threads. + true if the function succeeds; otherwise, false. + or is null. + or is disposed. + This function must be called after and before for the decoding side, or after () and before for the encoding side. + + + + Writes a tile with the given data. + + The to write tile. + The index of the tile to write. + The buffer to the data to write. + The length of datum to write. This value os used to make sure the data being written is correct. + The stream to write data to. + true if the data could be written; otherwise, false. + or is null. + or is disposed. + + + + Get the string representation of the OpenJpeg version. + + The string representation of the OpenJpeg version. + + + + Get the string representation of the version of wrapper library of OpenJpeg. + + The string representation of the version of wrapper library of OpenJpeg. + + + + Set the info handler. + + The codec previously initialise. + The callback function which will be used. + The client object where will be returned the message. + or is null. + is disposed. + + + + Set the warning handler. + + The codec previously initialise. + The callback function which will be used. + The client object where will be returned the message. + or is null. + is disposed. + + + + Set the warning handler. + + The codec previously initialise. + The callback function which will be used. + The client object where will be returned the message. + or is null. + is disposed. + + + + Create an image. + + The number of components. + The components parameters. + The image color space. + A new . + + + + Creates an image without allocating memory for the image. + + The number of components. + The components parameters. + The image color space. + A new . + + + + Allocates new memory buffer for . + + The number of bytes to allocate. + The new pointer to indicate allocated memory buffer if success; otherwise, . + + + + Unallocates memory buffer for . + + The pointer to indicate allocated memory buffer by . + + + + Sets the MCT matrix to use. + + The to change. + The encoding matrix. + The dc shift coefficients to use. + The number of components of the image. + true if the parameters could be set; otherwise, false. + , or is null. + is disposed. + The length of must be x or less. Or The length of must be or less + + + + Creates an abstract stream. + + The value whether the stream is a read stream. + The . + + + + Creates an abstract stream with a specific buffer size. + + The size of the chunk used to stream. + The value whether the stream is a read stream. + The . + + + + Sets the given callback to be used as a read function. + + The stream to modify. + The callback to free user data when reads data stream. + or is null. + is disposed. + + + + Sets the given callback to be used as a write function. + + The stream to modify. + The callback to free user data when writes data stream. + or is null. + is disposed. + + + + Sets the given callback to be used as a skip function. + + The stream to modify. + The callback to free user data when skips data stream. + or is null. + is disposed. + + + + Sets the given callback to be used as a seek function, the stream is then seekable, + + The stream to modify. + The callback to free user data when seeks data stream. + or is null. + is disposed. + + + + Sets the given data to be used as a user data for the stream. + + The stream to modify. + The data to set. + The callback to free user data when is disposed. + or is null. + is disposed. + + + + Sets the length of the user data for the stream. + + The stream to modify. + The length of the user_data. + is null. + is disposed. + + + + Create a stream from a file identified with its filename with default parameters. + + The filename of the file to input to stream. + The value whether the stream is a read stream. + The . + is null. + The specified path does not exist. + + + + Create a stream from a file identified with its filename with a specific buffer size. + + The filename of the file to input to stream. + The size of the chunk used to stream. + The value whether the stream is a read stream. + The . + is null. + The specified path does not exist. + + + + Returns if the library is built with thread support. + + true if mutex, condition, thread, thread pool are available; otherwise, false. + + + + Return the number of virtual CPUs. + + The number of virtual CPUs. + + + + A class which has a pointer of native structure. + + + + + Initializes a new instance of the class with the specified value indicating whether this instance is disposable. + + true if this instance is disposable; otherwise, false. + + + + Gets a value indicating whether this instance has been disposed. + + true if this instance has been disposed; otherwise, false. + + + + Gets a value indicating whether this instance is disposable. + + true if this instance is disposable; otherwise, false. + + + + Gets a pointer of native structure. + > + + + + If this object is disposed, then is thrown. + + + + + Determines whether this instance and another specified object have the same value. + + The to compare to this instance. + true if the value of the parameter is the same as the value of this instance; otherwise, false. If is null, the method returns false. + + + + Determines whether this instance and a specified object, which must also be a object, have the same value. + + The to compare to this instance. + true if is a and its value is the same as this instance; otherwise, false. If is null, the method returns false. + + + + Returns the hash code for this string. + + A 32-bit signed integer hash code. + + + + Releases all managed resources. + + + + + Releases all unmanaged resources. + + + + + Releases all resources used by this . + + + + + Releases all resources used by this . + + Indicate value whether method was called. + + + + Specifies the progression order. + + + + + Specifies that place-holder. + + + + + Specifies that layer-resolution-component-precinct order. + + + + + Specifies that resolution-layer-component-precinct order. + + + + + Specifies that resolution-precinct-component-layer order. + + + + + Specifies that precinct-component-resolution-layer order. + + + + + Specifies that component-precinct-resolution-layer order. + + + + + Defines the raw bitmap image data. This class cannot be inherited. + + + + + Gets the number of channels, of this . + + The number of channels, of this . + + + + Gets the pixel data of this . + + The pixel data. + + + + Gets the height, in pixels, of this . + + The height, in pixels, of this . + + + + Gets the width, in pixels, of this . + + The width, in pixels, of this . + + + + Gets the specified for the object. + + The type of image storeed as + + + + Specifies the region size capabilities. + + + + + Specifies that Standard JPEG 2000 profile. + + + + + Specifies that Profile name for a 2K image. + + + + + Specifies that Profile name for a 4K image. + + + + + Specifies that multiple component transformation. + + + + + A stream that represents a JPEG 2000. This class cannot be inherited. + + + + + Releases all unmanaged resources. + + + + diff --git a/Assets/Plugins/OpenJpegDotNet.xml.meta b/Assets/Plugins/OpenJpegDotNet.xml.meta new file mode 100644 index 0000000..c15d75c --- /dev/null +++ b/Assets/Plugins/OpenJpegDotNet.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ef87fb698153618479434b8b658dc0a4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: