From 4cdda7bc6649c98c79ccbba481aafaeff3d79e23 Mon Sep 17 00:00:00 2001 From: cinder Date: Thu, 28 Aug 2025 11:55:08 -0500 Subject: [PATCH] Support AgentProfile PUT profiles --- LibreMetaverse/AgentManager.cs | 173 +++++++++++++++++++++++++++------ 1 file changed, 144 insertions(+), 29 deletions(-) diff --git a/LibreMetaverse/AgentManager.cs b/LibreMetaverse/AgentManager.cs index 2c77e8cc..7fa93c2b 100644 --- a/LibreMetaverse/AgentManager.cs +++ b/LibreMetaverse/AgentManager.cs @@ -1253,6 +1253,8 @@ namespace OpenMetaverse } #endregion Callbacks + private const string AGENT_PROFILE_CAP = "AgentProfile"; + /// Reference to the GridClient instance private readonly GridClient Client; /// Used for movement and camera tracking @@ -1269,7 +1271,7 @@ namespace OpenMetaverse #region Properties - /// Your (client) avatars + /// Your (client) avatar's /// "client", "agent", and "avatar" all represent the same thing public UUID AgentID { get; private set; } @@ -1491,6 +1493,7 @@ namespace OpenMetaverse private readonly ManualResetEvent teleportEvent = new ManualResetEvent(false); private uint heightWidthGenCounter; private readonly Dictionary gestureCache = new Dictionary(); + #endregion Private Members /// @@ -3430,14 +3433,36 @@ namespace OpenMetaverse #endregion Teleporting - #region Misc + #region Profile /// /// Update agent profile /// - /// struct containing updated + /// struct containing updated /// profile information + /// + /// The behavior between LLUDP and Http Capability differs. See each method's remarks + /// + /// + /// public void UpdateProfile(Avatar.AvatarProperties profile) + { + if (Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP) != null) + { + UpdateProfileHttp(profile); + } + else + { + UpdateProfileUdp(profile); + } + } + + /// + /// Update agent profile via simulator LLUDP + /// + /// struct containing updated + /// profile information + public void UpdateProfileUdp(Avatar.AvatarProperties profile) { AvatarPropertiesUpdatePacket apup = new AvatarPropertiesUpdatePacket { @@ -3461,10 +3486,51 @@ namespace OpenMetaverse Client.Network.SendPacket(apup); } + /// + /// Update agent profile + /// + /// struct containing updated + /// profile information + /// + /// + /// Only updates about text fields, profile url, and allow_publish. + /// Does not update image UUID, etc. like the legacy LLUDP request. + /// + public async void UpdateProfileHttp(Avatar.AvatarProperties profile, CancellationToken cancellationToken = default) + { + var payload = new OSDMap + { + ["sl_about_text"] = profile.AboutText, + ["fl_about_text"] = profile.FirstLifeText, + ["profile_url"] = profile.ProfileURL, + ["allow_publish"] = profile.AllowPublish, + // This next pair may or may not do anything! It would be nice if it did. + ["sl_image_id"] = profile.ProfileImage, + ["fl_image_id"] = profile.FirstLifeImage + }; + + var capability = Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP); + var uri = new Uri($"{capability}/{AgentID}"); + await Client.HttpCapsClient.PutRequestAsync(uri, OSDFormat.Xml, payload, cancellationToken, + (response, data, error) => + { + if (error != null) + { + Logger.Log($"AgentProfile update failed: {error.Message}", Helpers.LogLevel.Warning); + return; + } + + if (response.IsSuccessStatusCode) + { + Logger.Log("AgentProfile update succeeded.", Helpers.LogLevel.Debug); + } + }); + } + /// /// Update agent's profile interests /// - /// selection of interests from struct + /// selection of interests from struct public void UpdateInterests(Avatar.Interests interests) { AvatarInterestsUpdatePacket aiup = new AvatarInterestsUpdatePacket @@ -3492,7 +3558,21 @@ namespace OpenMetaverse /// /// target avatar for notes /// notes to store + /// + /// public void UpdateProfileNotes(UUID target, string notes) + { + if (Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP) != null) + { + UpdateProfileNotesHttp(target, notes); + } + else + { + UpdateProfileNotesUdp(target, notes); + } + } + + private void UpdateProfileNotesUdp(UUID target, string notes) { AvatarNotesUpdatePacket anup = new AvatarNotesUpdatePacket { @@ -3511,32 +3591,36 @@ namespace OpenMetaverse } /// - /// 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 + /// Update agent's private notes for target avatar using HTTP capability system /// - /// New height of the viewer window - /// New width of the viewer window - public void SetHeightWidth(ushort height, ushort width) + /// target avatar for notes + /// notes to store + /// + public async void UpdateProfileNotesHttp(UUID target, string notes, CancellationToken cancellationToken = default) { - AgentHeightWidthPacket heightwidth = new AgentHeightWidthPacket - { - AgentData = - { - AgentID = Client.Self.AgentID, - SessionID = Client.Self.SessionID, - CircuitCode = Client.Network.CircuitCode - }, - HeightWidthBlock = - { - Height = height, - Width = width, - GenCounter = heightWidthGenCounter++ - } - }; + var payload = new OSDMap { ["notes"] = notes }; - Client.Network.SendPacket(heightwidth); + var capability = Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP); + var uri = new Uri($"{capability}/{target}"); + await Client.HttpCapsClient.PutRequestAsync(uri, OSDFormat.Xml, payload, cancellationToken, + (response, data, error) => + { + if (error != null) + { + Logger.Log($"AgentProfile notes update failed: {error.Message}", Helpers.LogLevel.Warning); + } + + if (response.IsSuccessStatusCode) + { + Logger.Log("AgentProfile notes update succeeded.", Helpers.LogLevel.Debug); + } + }); } + #endregion Profile + + #region Mute List + /// /// Request the list of muted objects and avatars for this agent /// @@ -3644,10 +3728,41 @@ namespace OpenMetaverse } } + #endregion Mute List + + #region Misc + + /// + /// Set the height and the width of the client window. This is used + /// by the server to build a virtual camera frustum for our avatar + /// + /// New height of the viewer window + /// New width of the viewer window + public void SetHeightWidth(ushort height, ushort width) + { + AgentHeightWidthPacket heightwidth = new AgentHeightWidthPacket + { + AgentData = + { + AgentID = Client.Self.AgentID, + SessionID = Client.Self.SessionID, + CircuitCode = Client.Network.CircuitCode + }, + HeightWidthBlock = + { + Height = height, + Width = width, + GenCounter = heightWidthGenCounter++ + } + }; + + Client.Network.SendPacket(heightwidth); + } + /// /// Sets home location to agents current position /// - /// will fire an AlertMessage () with + /// will fire an AlertMessage () with /// success or failure message public void SetHome() { @@ -3673,7 +3788,7 @@ namespace OpenMetaverse /// Move an agent in to a simulator. This packet is the last packet /// needed to complete the transition in to a new simulator /// - /// Object + /// Object public void CompleteAgentMovement(Simulator simulator) { CompleteAgentMovementPacket move = new CompleteAgentMovementPacket @@ -3693,10 +3808,10 @@ namespace OpenMetaverse /// /// Reply to script permissions request /// - /// Object + /// Object /// of the itemID requesting permissions /// of the taskID requesting permissions - /// list of permissions to allow + /// list of permissions to allow public void ScriptQuestionReply(Simulator simulator, UUID itemID, UUID taskID, ScriptPermission permissions) { ScriptAnswerYesPacket yes = new ScriptAnswerYesPacket