using System.Text.Json; using OpenMetaverse; using SecondBotEvents.Services; using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace SecondBotEvents.Commands { [ClassInfo("What is going on with the bot")] public class Info(EventsSecondBot setmaster) : CommandsAPI(setmaster) { [About("Requests a 6-digit login token to be sent via IM to the avatar")] [ArgHints("avatar", "The avatar to send the token to", "AVATAR")] [CmdTypeDo()] public object RequestLoginToken(string avatar) { ProcessAvatar(avatar); if (avataruuid == UUID.Zero) return Failure("Unknown avatar - are you sure the name is correct? (Firstname Lastname)"); string token = master.DataStoreService.RequestLoginToken(avataruuid); GetClient().Self.InstantMessage(avataruuid, $"[Bot Dashboard] Your login verification code is: {token} (Expires in 5 minutes)"); return BasicReply("Sent"); } [About("Verifies a 6-digit login token")] [ArgHints("avatar", "The avatar verifying", "AVATAR")] [ArgHints("token", "The 6-digit token", "STRING")] [CmdTypeGet()] public object VerifyLoginToken(string avatar, string token) { ProcessAvatar(avatar); if (avataruuid == UUID.Zero) return Failure("Unknown avatar"); bool ok = master.DataStoreService.VerifyLoginToken(avataruuid, token); if (ok) return BasicReply(avataruuid.ToString()); return BasicReply("False"); } [About("Fetchs the current region type the bot is in")] [ReturnHints("Region type as string")] [ReturnHintsFailure("Error not in a sim")] [CmdTypeGet()] public object GetCurrentRegionType() { if(GetClient().Network.CurrentSim == null) { return Failure("Error not in a sim"); } return BasicReply(GetClient().Network.CurrentSim.ProductName); } [About("Lists objects that are sculpty type in the current sim that the bot can see")] [ReturnHints("A json object")] [CmdTypeGet()] public object ListSculptys() { Dictionary objects_copy = GetClient().Network.CurrentSim.ObjectsPrimitives.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); Dictionary mapLocalID = []; Dictionary sculpts = []; foreach (KeyValuePair Obj in objects_copy) { mapLocalID.Add(Obj.Value.LocalID, Obj.Key); if (PrimType.Sculpt.Equals(Obj.Value.Type) == true) { sculpts.Add(Obj.Key, Obj.Value); } } List reply = []; foreach (KeyValuePair Obj in sculpts) { Vector3 pos = Obj.Value.Position; string name = "?"; if (Obj.Value.NameValues != null) { name = Obj.Value.NameValues[0].Value.ToString(); } UUID key = Obj.Value.ID; UUID owner = Obj.Value.OwnerID; bool asLink = false; if (Obj.Value.ParentID > 0) { if(mapLocalID.ContainsKey(Obj.Value.ParentID) == true) { Primitive wip = objects_copy[mapLocalID[Obj.Value.ParentID]]; pos = wip.Position; asLink = true; owner = wip.OwnerID; if (wip.NameValues != null) { name = wip.NameValues[0].Value.ToString(); } key = wip.ID; } } SculptysInfo A = new() { isLinked = asLink.ToString(), name = name.ToString(), owner = owner.ToString(), uuid = key.ToString(), pos = pos.ToString() }; reply.Add(A); } if (reply.Count == 0) { return Failure("No objects found"); } return BasicReply(JsonSerializer.Serialize(reply, JsonOptions.UnsafeRelaxed)); } [About("Fetchs the current bot")] [ReturnHints("The build ID of the bot")] [CmdTypeGet()] public object Version() { return BasicReply(master.GetVersion()); } [About("Fetchs the name of the bot")] [ReturnHints("Firstname Lastname")] [CmdTypeGet()] public object Name() { return BasicReply(GetClient().Self.FirstName + " " + GetClient().Self.LastName); } [About("Fetchs the current parcels name")] [ReturnHints("Parcelname")] [ReturnHintsFailure("Error parcel not found")] [ReturnHintsFailure("Error not in a sim")] [CmdTypeGet()] public object ParcelName() { if (GetClient().Network.CurrentSim == null) { return Failure("Error not in a sim"); } int localid = GetClient().Parcels.GetParcelLocalID(GetClient().Network.CurrentSim, GetClient().Self.SimPosition); if (GetClient().Network.CurrentSim.Parcels.ContainsKey(localid) == false) { return Failure("Error parcel not found"); } return BasicReply(GetClient().Network.CurrentSim.Parcels[localid].Name); } [About("Requests the current unixtime at the bot")] [ReturnHints("Unixtime")] [CmdTypeGet()] public object UnixTimeNow() { return BasicReply(SecondbotHelpers.UnixTimeNow().ToString()); } [About("Fetchs the current region name")] [ReturnHints("Regionname")] [ReturnHintsFailure("Error not in a sim")] [CmdTypeGet()] public object SimName() { if (GetClient().Network.CurrentSim == null) { return Failure("Error not in a sim"); } return BasicReply(GetClient().Network.CurrentSim.Name); } [About("Fetchs the current location of the bot")] [ReturnHints("array of X,Y,Z values")] [ReturnHintsFailure("Error not in a sim")] [CmdTypeGet()] public object GetPosition() { if (GetClient().Network.CurrentSim == null) { return Failure("Error not in a sim"); } Dictionary pos = new() { { "x", (int)Math.Round(GetClient().Self.SimPosition.X) }, { "y", (int)Math.Round(GetClient().Self.SimPosition.Y) }, { "z", (int)Math.Round(GetClient().Self.SimPosition.Z) } }; return BasicReply(JsonSerializer.Serialize(pos, JsonOptions.UnsafeRelaxed)); } [About("Fetchs the current RLV restrictions applied to the bot")] [ReturnHints("A JSON array of RLV rules")] [CmdTypeGet()] public object RLVStatus() { if (master.RLV == null) { return Failure("RLV service is not running"); } var rules = master.RLV.Rules; 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 { public string name = ""; public string isLinked = "False"; public string owner = "?"; public string uuid = "?"; public string pos = "<0,0,0>"; } }