From ad2aab419f50ce04d7ee88f573e90d63a3a544e0 Mon Sep 17 00:00:00 2001 From: RebeccaNod1 Date: Mon, 11 May 2026 16:29:44 -0600 Subject: [PATCH] Dashboard enhancements: LoadURL relay, nearby object scanning, and bug fixes --- SecondBotEvents/Commands/Avatars.cs | 4 +- SecondBotEvents/Commands/Dialogs.cs | 12 ++++- SecondBotEvents/Commands/Info.cs | 53 +++++++++++++++++++++++ SecondBotEvents/Services/DialogService.cs | 41 +++++++++++++++++- 4 files changed, 105 insertions(+), 5 deletions(-) diff --git a/SecondBotEvents/Commands/Avatars.cs b/SecondBotEvents/Commands/Avatars.cs index 14eaed4..d3bf5ee 100644 --- a/SecondBotEvents/Commands/Avatars.cs +++ b/SecondBotEvents/Commands/Avatars.cs @@ -314,11 +314,11 @@ namespace SecondBotEvents.Commands [CmdTypeDo()] public object Key2Name(string uuid) { - if (UUID.TryParse(uuid, out _) == false) + if (UUID.TryParse(uuid, out UUID parsedUUID) == false) { return Failure("Not a vaild UUID"); } - return BasicReply(master.DataStoreService.GetAvatarName(UUID.Zero)); + return BasicReply(master.DataStoreService.GetAvatarName(parsedUUID)); } [About("searchs the AV database if not found triggers a lookup")] diff --git a/SecondBotEvents/Commands/Dialogs.cs b/SecondBotEvents/Commands/Dialogs.cs index 5f25769..d6c2303 100644 --- a/SecondBotEvents/Commands/Dialogs.cs +++ b/SecondBotEvents/Commands/Dialogs.cs @@ -1,5 +1,7 @@ -using OpenMetaverse; +using OpenMetaverse; using SecondBotEvents.Services; +using System.Text.Json; +using System.Collections.Generic; namespace SecondBotEvents.Commands @@ -84,5 +86,13 @@ namespace SecondBotEvents.Commands return BasicReply(master.DialogService.DialogAction(dialogidnum, buttontext)); } + [About("Lists all active dialogs currently waiting for a response")] + [ReturnHints("A JSON array of active dialogs")] + [CmdTypeGet()] + public object GetDialogs() + { + var dialogs = master.DialogService.GetActiveDialogs(); + return BasicReply(JsonSerializer.Serialize(dialogs, JsonOptions.UnsafeRelaxed)); + } } } diff --git a/SecondBotEvents/Commands/Info.cs b/SecondBotEvents/Commands/Info.cs index f0e1c2f..154b00e 100644 --- a/SecondBotEvents/Commands/Info.cs +++ b/SecondBotEvents/Commands/Info.cs @@ -200,6 +200,59 @@ namespace SecondBotEvents.Commands if (rules == null) return BasicReply("[]"); return BasicReply(JsonSerializer.Serialize(rules, JsonOptions.UnsafeRelaxed)); } + + [About("Lists objects near the bot (within 20m)")] + [ReturnHints("A JSON array of nearby objects")] + [CmdTypeGet()] + public object GetNearbyObjects() + { + if (GetClient().Network.CurrentSim == null) return Failure("Not in a sim"); + + Vector3 botPos = GetClient().Self.SimPosition; + uint sittingOn = GetClient().Self.SittingOn; + List localIDsToRequest = []; + + // First pass: Find objects and collect localIDs for properties we don't have + foreach (var prim in GetClient().Network.CurrentSim.ObjectsPrimitives.Values) + { + if (prim.ParentID != 0) continue; + if (Vector3.Distance(botPos, prim.Position) <= 20.0f) + { + if (prim.Properties == null) localIDsToRequest.Add(prim.LocalID); + } + } + + // If we have missing names, request them and wait a short moment + if (localIDsToRequest.Count > 0) + { + GetClient().Objects.SelectObjects(GetClient().Network.CurrentSim, localIDsToRequest.ToArray()); + Thread.Sleep(500); // Wait for properties to arrive + } + + List reply = []; + foreach (var prim in GetClient().Network.CurrentSim.ObjectsPrimitives.Values) + { + if (prim.ParentID != 0) continue; + + float dist = Vector3.Distance(botPos, prim.Position); + if (dist <= 20.0f) + { + string name = prim.Properties?.Name; + if (string.IsNullOrEmpty(name)) name = "Object #" + prim.LocalID; + + reply.Add(new { + name = name, + uuid = prim.ID.ToString(), + local_id = prim.LocalID, + dist = Math.Round(dist, 1), + pos = prim.Position.ToString(), + is_sitting = (prim.LocalID == sittingOn) + }); + } + } + + return BasicReply(JsonSerializer.Serialize(reply, JsonOptions.UnsafeRelaxed)); + } } public class SculptysInfo diff --git a/SecondBotEvents/Services/DialogService.cs b/SecondBotEvents/Services/DialogService.cs index 1a69ba6..8eb1b9a 100644 --- a/SecondBotEvents/Services/DialogService.cs +++ b/SecondBotEvents/Services/DialogService.cs @@ -1,4 +1,4 @@ -using OpenMetaverse; +using OpenMetaverse; using SecondBotEvents.Config; using System; using System.Collections.Generic; @@ -108,6 +108,28 @@ namespace SecondBotEvents.Services } } + public List GetActiveDialogs() + { + lock (DialogWindows) + { + CleanUp(); + List reply = []; + foreach (var kvp in DialogWindows) + { + var e = kvp.Value; + reply.Add(new DialogWindow + { + buttons = [.. e.ButtonLabels], + dialogid = kvp.Key, + message = e.Message, + objectname = e.ObjectName, + expires = DialogWindowsExpire[kvp.Key] + }); + } + return reply; + } + } + public string DialogAction(int dialogID, string button) { lock(DialogWindows) @@ -141,7 +163,7 @@ namespace SecondBotEvents.Services List removeids = []; foreach(KeyValuePair a in DialogWindowsExpire) { - if(a.Value > unixtime) + if(a.Value < unixtime) { removeids.Add(a.Key); } @@ -240,6 +262,7 @@ namespace SecondBotEvents.Services if (GetClient() != null) { GetClient().Self.ScriptDialog -= DialogWindowEvent; + GetClient().Self.LoadURL -= LoadUrlEvent; } } @@ -249,6 +272,20 @@ namespace SecondBotEvents.Services botConnected = true; // attach events GetClient().Self.ScriptDialog += DialogWindowEvent; + GetClient().Self.LoadURL += LoadUrlEvent; + } + + protected void LoadUrlEvent(object sender, LoadUrlEventArgs e) + { + // We'll relay this as a special chat message so it shows up in the dashboard chat log + // In this version of LibOMV, the property is 'URL' (all caps). + string address = e.URL; + string message = " [SYSTEM] Object '" + e.ObjectName + "' sent a link: " + e.Message + " URL: " + address; + + // Record it in the bot's local chat history so the dashboard picks it up on the next poll + master.DataStoreService.BotRecordLocalchatReply(message, "[SYSTEM] "); + + LogFormater.Info("[LoadURL] " + e.ObjectName + " sent: " + e.Message + " (" + address + ")"); } public override void Start(bool updateEnabled = false, bool setEnabledTo = false)