diff --git a/Dockerfile b/Dockerfile index 2a2b428..1c5ecc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -73,6 +73,7 @@ ENV basic_Username='' \ homebound_AtHomeSeekLocation='false' \ homebound_AtBackupSeekLocation='false' \ homebound_AtHomeAutoSitUuid='00000000-0000-0000-0000-000000000000' \ + homebound_ReturnToHomeSimAfterMins=5 \ http_Enabled='false' \ http_Port=80 \ interaction_Enabled='true' \ diff --git a/LibreMetaverse/LibreMetaverse.csproj b/LibreMetaverse/LibreMetaverse.csproj index c8b6416..1a50ef3 100644 --- a/LibreMetaverse/LibreMetaverse.csproj +++ b/LibreMetaverse/LibreMetaverse.csproj @@ -43,11 +43,11 @@ True - - + + - + diff --git a/LibreMetaverse/Settings.cs b/LibreMetaverse/Settings.cs index 748ae9e..4c20650 100644 --- a/LibreMetaverse/Settings.cs +++ b/LibreMetaverse/Settings.cs @@ -116,7 +116,7 @@ namespace OpenMetaverse /// Milliseconds without receiving a packet before the /// connection to a simulator is assumed lost - public int SIMULATOR_TIMEOUT = 30 * 1000; + public int SIMULATOR_TIMEOUT = 60 * 1000; /// Milliseconds to wait for a simulator info request through /// the grid interface @@ -338,7 +338,7 @@ namespace OpenMetaverse /// You will get no output on the console. This behavior can be overriden by creating /// a logger configuration file for log4net /// - public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.None; + public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.Error; /// Attach avatar names to log messages public bool LOG_NAMES = true; diff --git a/SecondBotEvents/Commands/Discord.cs b/SecondBotEvents/Commands/Discord.cs index 5fb54d0..710c832 100644 --- a/SecondBotEvents/Commands/Discord.cs +++ b/SecondBotEvents/Commands/Discord.cs @@ -1,4 +1,7 @@ -using SecondBotEvents.Services; +using Newtonsoft.Json; +using SecondBotEvents.Services; +using System.Collections.Generic; +using System.Linq; namespace SecondBotEvents.Commands { @@ -42,6 +45,20 @@ namespace SecondBotEvents.Commands return BasicReply(master.DiscordService.BanMember(serverid, memberid, why).Result.ToString(), new [] { serverid, memberid, why }); } + public object Discord_GetMemberRoles(string serverid, string memberid) + { + if (master.DiscordService.DiscordReady() == false) + { + return Failure("Discord client not ready"); + } + KeyValuePair> reply = master.DiscordService.DiscordMemerRoles(serverid, memberid); + if(reply.Key == false) + { + return Failure(reply.Value.First()); + } + return BasicReply(JsonConvert.SerializeObject(reply.Value)); + } + [About("Clears messages on the server sent by the member in the last 13 days, 22hours 59mins")] [ReturnHintsFailure("Discord client not ready")] [ReturnHints("true|false")] diff --git a/SecondBotEvents/Commands/Inventory.cs b/SecondBotEvents/Commands/Inventory.cs index 4cdd9cc..ef01df6 100644 --- a/SecondBotEvents/Commands/Inventory.cs +++ b/SecondBotEvents/Commands/Inventory.cs @@ -24,7 +24,12 @@ namespace SecondBotEvents.Commands [ArgHints("outputTarget", "HTTP url, channel, avatar UUID or clear to remove all events for the selected type")] public object SetInventoryUpdate(string inventoryType, string outputTarget) { - return Failure("@todo inventory update events"); + if (master.EventsService.isRunning() == true) + { + master.EventsService.AddInventoryEvent(inventoryType, outputTarget); + return BasicReply("Ok"); + } + return Failure("Events service is not running"); } [About("Uploads a new sound file to inventory")] @@ -151,7 +156,7 @@ namespace SecondBotEvents.Commands [ReturnHints("ok")] [ReturnHints("okMulti")] [ReturnHints("invaild item uuid pr invaild attach point")] - [ArgHints("item", "UUID of item, or the attach point")] + [ArgHints("item", "UUID of item, or the attach point, or * to remove everything")] public object Detach(string item) { if (UUID.TryParse(item, out UUID itemuuid) == false) @@ -159,7 +164,7 @@ namespace SecondBotEvents.Commands List toBeRemoved = new List(); foreach (KeyValuePair pair in GetClient().Appearance.GetAttachmentsByItemId()) { - if(pair.Value.ToString() != item) + if((pair.Value.ToString() != item) || (item == "*")) { continue; } @@ -425,6 +430,15 @@ namespace SecondBotEvents.Commands } if (RealObject.Value == null) { + GetClient().Objects.RequestObjectMedia(objectUUID, GetClient().Network.CurrentSim, null); + foreach (KeyValuePair Obj in objects_copy) + { + if (Obj.Value.ID == objectUUID) + { + RealObject = Obj; + break; + } + } return Failure("Unable to find object", new [] { item, objectuuid, running }); } bool scriptState = runscript; diff --git a/SecondBotEvents/Config/DiscordConfig.cs b/SecondBotEvents/Config/DiscordConfig.cs index 69bfae6..857d44d 100644 --- a/SecondBotEvents/Config/DiscordConfig.cs +++ b/SecondBotEvents/Config/DiscordConfig.cs @@ -14,6 +14,10 @@ namespace SecondBotEvents.Config settings.Add("ServerID"); settings.Add("ClientToken"); settings.Add("AllowDiscordCommands"); + settings.Add("InteractionEnabled"); + settings.Add("InteractionCommandName"); + settings.Add("InteractionHttpTarget"); + settings.Add("InteractionChannelNumber"); settings.Add("HideStatusOutput"); } @@ -36,5 +40,30 @@ namespace SecondBotEvents.Config { return ReadSettingAsBool("AllowDiscordCommands"); } + + public bool GetInteractionEnabled() + { + return ReadSettingAsBool("InteractionEnabled"); + } + + public string GetInteractionHttpTarget() + { + return ReadSettingAsString("InteractionHttpTarget", "https://localhost/interaction.php"); + } + + public string GetInteractionCommandName() + { + return ReadSettingAsString("InteractionCommandName","Go"); + } + + public string GetInteractionChannelNumber() + { + return ReadSettingAsString("InteractionChannelNumber", "-1"); + } + + public void SetInteractionEnabled(bool enabled) + { + mysettings["InteractionEnabled"] = enabled.ToString(); + } } } \ No newline at end of file diff --git a/SecondBotEvents/Config/HomeboundConfig.cs b/SecondBotEvents/Config/HomeboundConfig.cs index e1e497f..d697d75 100644 --- a/SecondBotEvents/Config/HomeboundConfig.cs +++ b/SecondBotEvents/Config/HomeboundConfig.cs @@ -14,6 +14,7 @@ namespace SecondBotEvents.Config settings.Add("Enabled"); settings.Add("HomeSimSlUrl"); settings.Add("BackupSimSLUrl"); + settings.Add("ReturnToHomeSimAfterMins"); settings.Add("AtHomeSeekLocation"); settings.Add("AtBackupSeekLocation"); settings.Add("AtHomeAutoSitUuid"); @@ -25,6 +26,11 @@ namespace SecondBotEvents.Config return ReadSettingAsString("AtHomeAutoSitUuid", UUID.Zero.ToString()); } + public int GetReturnToHomeSimAfterMins() + { + return ReadSettingAsInt("ReturnToHomeSimAfterMins", 1); + } + public bool GetAtHomeSeekLocation() { return ReadSettingAsBool("AtHomeSeekLocation", true); diff --git a/SecondBotEvents/SecondBotEvents.csproj b/SecondBotEvents/SecondBotEvents.csproj index 04ee535..dceb712 100644 --- a/SecondBotEvents/SecondBotEvents.csproj +++ b/SecondBotEvents/SecondBotEvents.csproj @@ -10,17 +10,17 @@ settings.env - - + + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/SecondBotEvents/Services/CommandsService.cs b/SecondBotEvents/Services/CommandsService.cs index f3f0970..936cfce 100644 --- a/SecondBotEvents/Services/CommandsService.cs +++ b/SecondBotEvents/Services/CommandsService.cs @@ -298,7 +298,7 @@ namespace SecondBotEvents.Services return new KeyValuePair(false, e.Message); } } - CommandNotice(C.command, source + " ~~ Failure: incorrect number of args", String.Join("@@@", C.args), false); + CommandNotice(C.command, source + " ~~ Failure: incorrect number of args expected: "+ theMethod.GetParameters().Count().ToString()+" but got "+ argsList.Count.ToString()+"", String.Join("@@@", C.args), false); return new KeyValuePair(status, reply); } return new KeyValuePair(false, "theMethod is null"); diff --git a/SecondBotEvents/Services/DialogService.cs b/SecondBotEvents/Services/DialogService.cs index 5330d29..9f2893c 100644 --- a/SecondBotEvents/Services/DialogService.cs +++ b/SecondBotEvents/Services/DialogService.cs @@ -203,7 +203,7 @@ namespace SecondBotEvents.Services foreach(string url in DialogRelayHTTP) { long unixtime = SecondbotHelpers.UnixTimeNow(); - string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "DialogRelay"+GetClient().Self.AgentID+ eventMessage); + string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "DialogRelay"+GetClient().Self.AgentID+ eventMessage + master.CommandsService.myConfig.GetSharedSecret()); var client = new RestClient(url); var request = new RestRequest("Dialog/Relay", Method.Post); request.AddParameter("token", token); diff --git a/SecondBotEvents/Services/DiscordService.cs b/SecondBotEvents/Services/DiscordService.cs index 680ebe1..208998e 100644 --- a/SecondBotEvents/Services/DiscordService.cs +++ b/SecondBotEvents/Services/DiscordService.cs @@ -6,6 +6,7 @@ using SecondBotEvents.Commands; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -94,6 +95,86 @@ namespace SecondBotEvents.Services remove { lock (m_discordEventChatLock) { m_discordChatEvent -= value; } } } + public KeyValuePair> DiscordMemerRoles(string givenserverid, string givenmemberid) + { + if (GetReadyForDiscordActions() == false) + { + // bot is not ready this message should not have got here yet. + return new KeyValuePair>(false,new List() { "not ready"}); + } + if (ulong.TryParse(givenserverid, out ulong serverid) == false) + { + return new KeyValuePair>(false, new List() { "invaild server"}); + } + if (ulong.TryParse(givenmemberid, out ulong memberid) == false) + { + return new KeyValuePair>(false, new List() { "invaild member"}); + } + SocketGuild server = DiscordClient.GetGuild(serverid); + if (server == null) + { + return new KeyValuePair>(false, new List() { "Cant get server"}); + } + SocketGuildUser user = server.GetUser(memberid); + if(user == null) + { + return new KeyValuePair>(false, new List() { "Cant get user" }); + } + List roleids = new List(); + foreach(SocketRole role in user.Roles) + { + roleids.Add(role.Id.ToString()); + } + return new KeyValuePair>(true, roleids); + } + + protected HttpClient HTTPclient = new HttpClient(); + protected bool MessageInteractionEvent(SocketMessage message, SocketChannel socketChannel) + { + if (myConfig.GetInteractionEnabled() != true) + { + return false; + } + if (myConfig.GetInteractionChannelNumber() != socketChannel.Id.ToString()) + { + return false; + } + if(message.Content.StartsWith(myConfig.GetInteractionCommandName()) == false) + { + return false; + } + if(myConfig.GetInteractionHttpTarget().StartsWith("http") == false) + { + myConfig.SetInteractionEnabled(false); + return false; + } + string getmessage = message.Content.Replace(myConfig.GetInteractionCommandName(), ""); + long unixtime = SecondbotHelpers.UnixTimeNow(); + string hash = SecondbotHelpers.GetSHA1(unixtime.ToString()+getmessage + master.CommandsService.myConfig.GetSharedSecret()); + Dictionary values = new Dictionary + { + { "message", getmessage }, + { "username", message.Author.Username }, + { "userid", message.Author.Id.ToString() }, + { "unixtime", unixtime.ToString() }, + { "hash", hash } + }; + var content = new FormUrlEncodedContent(values); + try + { + HTTPclient.PostAsync(myConfig.GetInteractionHttpTarget(), content); + _ = MarkMessage((IUserMessage)message, "✅"); + } + catch (Exception e) + { + LogFormater.Crit("[MessageInteractionEvent] HTTP failed: " + e.Message + ""); + _ = MarkMessage((IUserMessage)message, "❌"); + return false; + } + return true; + + } + protected Task DiscordClientMessageReceived(SocketMessage message) { if(GetReadyForDiscordActions() == false) @@ -102,6 +183,10 @@ namespace SecondBotEvents.Services return Task.CompletedTask; } SocketChannel socketChannel = DiscordClient.GetChannel(message.Channel.Id); + if(MessageInteractionEvent(message, socketChannel) == true) + { + return Task.CompletedTask; + } if(socketChannel.GetChannelType() != Discord.ChannelType.Text) { // bot only does stuff on text channels. @@ -471,6 +556,20 @@ namespace SecondBotEvents.Services _ = DiscordClient.LoginAsync(TokenType.Bot, myConfig.GetClientToken()).ConfigureAwait(false); } + protected Task DiscordInteraction(SocketMessageCommand msg) + { + if (myConfig.GetInteractionEnabled() == false) + { + return Task.CompletedTask; + } + if (msg.CommandName != myConfig.GetInteractionCommandName()) + { + return Task.CompletedTask; + } + + return Task.CompletedTask; + } + public override void Stop() { if(running == true) diff --git a/SecondBotEvents/Services/EventsService.cs b/SecondBotEvents/Services/EventsService.cs index 44013f3..9a7123f 100644 --- a/SecondBotEvents/Services/EventsService.cs +++ b/SecondBotEvents/Services/EventsService.cs @@ -25,6 +25,60 @@ namespace SecondBotEvents.Services protected UUID OutputAvatar = UUID.Zero; protected long lastGroupMembershipUpdate = 0; + public void InventoryUpdateEvent(Dictionary detail) + { + if (InventoryEvents.ContainsKey(detail["itemtype"]) == true) + { + foreach(string A in InventoryEvents[detail["itemtype"]]) + { + string output = JsonConvert.SerializeObject(detail); + if(UUID.TryParse(A, out UUID OutputAvatar) == true) + { + if (OutputAvatar != UUID.Zero) + { + GetClient().Self.InstantMessage(OutputAvatar, output); + } + } + else if (A.StartsWith("http") == true) + { + long unixtime = SecondbotHelpers.UnixTimeNow(); + string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "EventService" + GetClient().Self.AgentID + output+master.CommandsService.myConfig.GetSharedSecret()); + var client = new RestClient(A); + var request = new RestRequest("Inventory/Update", Method.Post); + request.AddParameter("token", token); + request.AddParameter("unixtime", unixtime.ToString()); + request.AddParameter("method", "Inventory"); + request.AddParameter("action", "Update"); + request.AddParameter("botname", GetClient().Self.Name); + request.AddParameter("event", output); + request.AddHeader("content-type", "application/x-www-form-urlencoded"); + client.ExecutePostAsync(request); + } + else if (int.TryParse(A, out int chann) == true) + { + if (chann >= 0) + { + GetClient().Self.Chat(output, chann, ChatType.Normal); + } + } + + } + } + } + + Dictionary> InventoryEvents = new Dictionary>(); + public void AddInventoryEvent(string inventoryType, string outputTarget) + { + if(InventoryEvents.ContainsKey(inventoryType) == false) + { + InventoryEvents.Add(inventoryType, new List()); + } + if (InventoryEvents[inventoryType].Contains(outputTarget) == false) + { + InventoryEvents[inventoryType].Add(outputTarget); + } + } + public EventsService(EventsSecondBot setMaster) : base(setMaster) { myConfig = new EventsConfig(master.fromEnv, master.fromFolder); @@ -207,7 +261,7 @@ namespace SecondBotEvents.Services if(myConfig.GetOutputHttpURL() != null) { long unixtime = SecondbotHelpers.UnixTimeNow(); - string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "EventService" + GetClient().Self.AgentID + output); + string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "EventService" + GetClient().Self.AgentID + output + master.CommandsService.myConfig.GetSharedSecret()); var client = new RestClient(myConfig.GetOutputHttpURL()); var request = new RestRequest("Event/Service", Method.Post); request.AddParameter("token", token); diff --git a/SecondBotEvents/Services/HomeboundService.cs b/SecondBotEvents/Services/HomeboundService.cs index 9dd5751..8d475ee 100644 --- a/SecondBotEvents/Services/HomeboundService.cs +++ b/SecondBotEvents/Services/HomeboundService.cs @@ -17,9 +17,11 @@ namespace SecondBotEvents.Services protected UUID sitTarget = UUID.Zero; protected long lastAlertTeleport = 0; protected bool evacWanted = false; + protected bool evacTeleport = false; protected bool gotoPosAttemptedTp = false; protected bool gotoPosAttemptedWalk = false; protected long lastGotoAction = 0; + protected long lastTeleportHomeAttempt = 0; protected bool softDisable = false; protected bool closeToHome = false; protected bool softDisableSit = false; @@ -67,11 +69,13 @@ namespace SecondBotEvents.Services public bool GoHome() { attemptedTeleportHome = true; + lastTeleportHomeAttempt = SecondbotHelpers.UnixTimeNow(); LogFormater.Info("Teleporting to home sim"); return GetClient().Self.Teleport(home.name, new Vector3(home.x, home.y, home.z), new Vector3(0, 0, 0)); } protected void Tick() { + long dif = 0; if (evacWanted == true) { BotAlertMessage(null, new AlertMessageEventArgs("restart", "999", new OpenMetaverse.StructuredData.OSDMap())); @@ -79,6 +83,7 @@ namespace SecondBotEvents.Services if (GetClient().Network.CurrentSim.Name == home.name) { simNickname = "Home # "; + evacTeleport = false; if (sitTarget != UUID.Zero) { if (GetClient().Self.SittingOn == 0) @@ -102,6 +107,7 @@ namespace SecondBotEvents.Services { GetToPos(backup); } + TryGoHome(); return; } if (simNickname == "") @@ -115,26 +121,38 @@ namespace SecondBotEvents.Services simNickname = "Someplace # "; } } + TryGoHome(); + } + + protected void TryGoHome() + { long dif = SecondbotHelpers.UnixTimeNow() - teleportActionLockout; - if(dif < 30) + if (dif < 30) { return; } teleportActionLockout = SecondbotHelpers.UnixTimeNow(); if (attemptedTeleportHome == false) { - if(GoHome() == false) + dif = SecondbotHelpers.UnixTimeNow() - lastTeleportHomeAttempt; + if ((dif / 60) >= myConfig.GetReturnToHomeSimAfterMins()) { - LogFormater.Warn("Unable to teleport to home sim"); + attemptedTeleportHome = false; + evacTeleport = false; + LogFormater.Info("trying to return to home sim"); + if (GoHome() == false) + { + LogFormater.Warn("Unable to teleport to home sim"); + } } return; } - else if(attemptedTeleportBackup == false) + else if (attemptedTeleportBackup == false) { attemptedTeleportBackup = true; LogFormater.Info("Teleporting to backup sim"); teleportActionLockout = SecondbotHelpers.UnixTimeNow(); - if(GetClient().Self.Teleport(backup.name, new Vector3(backup.x, backup.y, backup.z), new Vector3(0, 0, 0)) == false) + if (GetClient().Self.Teleport(backup.name, new Vector3(backup.x, backup.y, backup.z), new Vector3(0, 0, 0)) == false) { LogFormater.Warn("Unable to teleport to backup sim"); } @@ -170,6 +188,10 @@ namespace SecondBotEvents.Services { return simNickname + "Sitting on a thing"; } + else if(evacTeleport == true) + { + return simNickname + "Evac teleport"; + } else if(closeToHome == true) { return simNickname + "In a safe space"; @@ -258,6 +280,7 @@ namespace SecondBotEvents.Services return; } evacWanted = false; + evacTeleport = true; if (GetClient().Network.CurrentSim.Name == home.name) { LogFormater.Info("Teleporting to backup sim to avoid restart"); diff --git a/SecondBotEvents/Services/InteractionService.cs b/SecondBotEvents/Services/InteractionService.cs index 5ed403a..284f515 100644 --- a/SecondBotEvents/Services/InteractionService.cs +++ b/SecondBotEvents/Services/InteractionService.cs @@ -165,11 +165,17 @@ namespace SecondBotEvents.Services protected void BotInventoryAdd(object o, InventoryObjectAddedEventArgs e) { + InventoryItem F = (InventoryItem)e.Obj; Dictionary details = new Dictionary { { "itemname", e.Obj.Name }, { "itemuuid", e.Obj.UUID.ToString() }, + { "itemtype", F.AssetType.ToString() }, }; + if (master.EventsService.isRunning() == true) + { + master.EventsService.InventoryUpdateEvent(details); + } JsonOuputCleaner(details, "InventoryAdd"); } diff --git a/SecondBotEvents/Services/RelayService.cs b/SecondBotEvents/Services/RelayService.cs index 9c8d2af..35a4634 100644 --- a/SecondBotEvents/Services/RelayService.cs +++ b/SecondBotEvents/Services/RelayService.cs @@ -204,7 +204,7 @@ namespace SecondBotEvents.Services else if(targetType == "http") { long unixtime = SecondbotHelpers.UnixTimeNow(); - string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "RelayService" + GetClient().Self.AgentID + eventMessage); + string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "RelayService" + GetClient().Self.AgentID + eventMessage + master.CommandsService.myConfig.GetSharedSecret()); var client = new RestClient(targetOption); var request = new RestRequest("Relay/Service", Method.Post); request.AddParameter("token", token); diff --git a/SecondBotEvents/Services/RlvService.cs b/SecondBotEvents/Services/RlvService.cs deleted file mode 100644 index 23bdbce..0000000 --- a/SecondBotEvents/Services/RlvService.cs +++ /dev/null @@ -1,577 +0,0 @@ -namespace SecondBotEvents.Services -{ - using global::SecondBotEvents.Commands; - using global::SecondBotEvents.Config; - using OpenMetaverse; - using System; - using System.Collections.Generic; - using System.Data; - - namespace SecondBotEvents.Services - { - public class RlvService : BotServices - { - protected bool botConnected = false; - protected RlvConfig myConfig; - protected List RlvRules = new List(); - - protected List NotifyRules = new List(); - - - public RlvService(EventsSecondBot setMaster) : base(setMaster) - { - myConfig = new RlvConfig(master.fromEnv, master.fromFolder); - } - public override string Status() - { - if (myConfig == null) - { - return "Config broken"; - } - else if(myConfig.GetEnabled() == false) - { - return "Disabled by config"; - } - else if (myConfig.GetHideStatusOutput() == true) - { - return "hidden"; - } - else if (botConnected == false) - { - return "Waiting for client"; - } - return "Active"; - } - - protected void BotClientRestart(object o, BotClientNotice e) - { - LogFormater.Info("Rlv service [Attached to new client]"); - GetClient().Network.LoggedOut += BotLoggedOut; - GetClient().Network.SimConnected += BotLoggedIn; - } - - protected void BotLoggedOut(object o, LoggedOutEventArgs e) - { - GetClient().Network.SimConnected += BotLoggedIn; - GetClient().Self.IM -= BotImMessage; - GetClient().Self.ChatFromSimulator -= LocalChat; - botConnected = false; - LogFormater.Info("Rlv service [waiting for new client]"); - } - - protected void BotLoggedIn(object o, SimConnectedEventArgs e) - { - GetClient().Network.SimConnected -= BotLoggedIn; - GetClient().Self.IM += BotImMessage; - GetClient().Self.ChatFromSimulator += LocalChat; - botConnected = true; - } - - public override void Start() - { - if (myConfig.GetEnabled() == false) - { - return; - } - running = true; - master.BotClientNoticeEvent += BotClientRestart; - } - - public override void Stop() - { - if (myConfig.GetEnabled() == false) - { - return; - } - running = false; - master.BotClientNoticeEvent -= BotClientRestart; - } - - protected int RlvoutputChannel = 0; - - protected void rlvEvent(UUID fromAvatar, string message, bool fromAv, UUID Source) - { - if((fromAvatar != GetClient().Self.AgentID) && (master.CommandsService.AvatarUUIDIsMaster(fromAvatar) == false)) - { - return; - } - if(message.StartsWith("@") == false) - { - return; - } - - string[] bits = message.Split(','); - foreach(string bit in bits) - { - string[] subbits = bit.Split("=", 2); - // if 2 subbits then command = args - // if 1 then just command - string command = subbits[0]; - string? subcommand = null; - string args = ""; - if (subbits.Length > 1) - { - args = subbits[1]; - } - subbits = command.Split(":"); - command = subbits[0]; - if (subbits.Length > 1) - { - subcommand = subbits[1]; - } - rlvCommand(command, subcommand, args, fromAv, Source); - } - } - // https://wiki.secondlife.com/wiki/LSL_Protocol/RestrainedLoveAPI#Audience - // currently to inventory - - protected void rlvCommand(string command,string? subcommand, string args,bool fromAv,UUID Source) - { - int argAsInt = RlvoutputChannel; - if(int.TryParse(args, out argAsInt) == false) - { - argAsInt = RlvoutputChannel; - } - switch(command) - { - case "version": - case "versionnew": - { - ChatOutput("RestrainedLife viewer v2.8 (Secondbot [Events] "+master.GetVersion()+")", argAsInt); - break; - } - case "versionnum": - { - ChatOutput("2080000", argAsInt); - break; - } - case "versionnumbl": - { - ChatOutput("2080000" + GetBlackListAsString(subcommand), argAsInt); - break; - } - case "getblacklist": - { - if(fromAv == false) - { - break; - } - ImChatOutput(Source, "Current RLV blacklist is "+GetBlackListAsString(subcommand)); - break; - } - case "notify": - { - string[] bits = subcommand.Split(';'); - if (bits.Length == 1) - { - bits = new string[] { "*", bits[0] }; - } - if ((args == "add") || (args == "y")) - { - NotifyRules = AddRule(Source, bits[0], bits[1], "*", NotifyRules); - break; - } - NotifyRules = RemoveRule(bits[0], bits[1],"*", NotifyRules); - break; - } - case "sitground": - { - if (args != "force") - { - break; - } - Self A = new Self(master); - A.Sit("ground"); - break; - } - case "sit": - { - if ((args == "add") || (args == "y") || (args == "rem") || (args == "n")) - { - RlvRules = RemoveRule(command, "*", "*", RlvRules); - if ((args == "add") || (args == "y")) - { - RlvRules = AddRule(Source, command, "*", "*", RlvRules); - } - break; - } - if (args != "force") - { - break; - } - Self A = new Self(master); - A.Sit(subcommand); - break; - } - case "unsit": - { - if ((args == "add") || (args == "y") || (args == "rem") || (args == "n")) - { - RlvRules = RemoveRule(command, "*", "*", RlvRules); - if ((args == "add") || (args == "y")) - { - RlvRules = AddRule(Source, command, "*", "*", RlvRules); - } - break; - } - if (args != "force") - { - break; - } - Self A = new Self(master); - A.Stand(); - break; - } - case "detach": - { - if ((args == "add") || (args == "y") || (args == "rem") || (args == "n")) - { - RlvRules = RemoveRule(command, subcommand, "*", RlvRules); - if ((args == "add") || (args == "y")) - { - RlvRules = AddRule(Source, command, subcommand, "*", RlvRules); - } - break; - } - if (args != "force") - { - break; - } - InventoryCommands A = new InventoryCommands(master); - A.Detach(subcommand); - break; - } - case "getsitid": - { - uint index = GetClient().Self.SittingOn; - if (index > 0) - { - if (!GetClient().Network.CurrentSim.ObjectsPrimitives.ContainsKey(index)) - { - ChatOutput("!", argAsInt); - break; - } - ChatOutput(GetClient().Network.CurrentSim.ObjectsPrimitives[index].ID.ToString(), argAsInt); - break; - } - ChatOutput(UUID.Zero.ToString(), argAsInt); - break; - } - case "chatwhisper": - case "chatnormal": - case "chatshout": - case "sendchat": - case "setcam_unlock": - case "camunlock": - case "alwaysrun": - case "temprun": - case "fly": - case "recvchat_sec": - case "sendgesture": - case "emote": - case "recvemote_sec": - case "sendim_sec": - case "tplm": - case "tploc": - case "tplure_sec": - case "showinv": - case "viewnote": - case "viewscript": - case "viewtexture": - case "rez": - case "editworld": - case "editattach": - case "share_sec": - case "permissive": - { - RlvRules = RemoveRule(command, "*", "*", RlvRules); - if ((args == "add") || (args == "y")) - { - RlvRules = AddRule(Source, command, "*", "*", RlvRules); - } - break; - } - case "setrot": - { - if(args != "force") - { - break; - } - if(double.TryParse(subcommand, System.Globalization.NumberStyles.Float, Utils.EnUsCulture, out double rot) == false) - { - break; - } - GetClient().Self.Movement.UpdateFromHeading(Math.PI / 2d - rot, true); - break; - } - case "tpto": - { - if (args != "force") - { - break; - } - if (subcommand == null) - { - break; - } - string[] bits = subcommand.Split(';'); - if(bits.Length == 2) - { - // look at (ignored as docs suck) - subcommand = bits[0]; - } - bits = subcommand.Split('/'); - if(bits.Length == 3) - { - master.HomeboundService.MarkTeleport(); - Movement A = new Movement(master); - A.Teleport(GetClient().Network.CurrentSim.Name, bits[0], bits[1], bits[2]); - break; - } - else if(bits.Length == 4) - { - master.HomeboundService.MarkTeleport(); - Movement A = new Movement(master); - A.Teleport(bits[0], bits[1], bits[2], bits[3]); - break; - } - break; - } - case "edit": - case "getcam_fov": - case "camtextures": - case "camavdist": - case "camdrawmax": - case "camdrawmin": - case "camdistmax": - case "camzoommin": - case "camzoommax": - case "setcam_textures": - case "setcam_fov": - case "adjustheight": - case "standtp": - { - break; - } - case "redirchat": - case "camdrawalphamax": - case "camdrawalphamin": - case "setcam_avdistmin": - case "setcam_avdistmax": - case "setcam_fovmax": - case "setcam_fovmin": - case "recvchat": - case "recvchatfrom": - case "rediremote": - case "recvemotefrom": - case "recvemote": - case "sendchannel": - case "sendchannel_sec": - case "sendchannel_except": - case "sendim": - case "sendimto": - case "startim": - case "startimto": - case "recvim": - case "recvimfrom": - case "tplocal": - case "accepttp": - case "accepttprequest": - case "tprequest": - case "editobj": - case "share": - case "tplure": - { - RlvRules = RemoveRule(command, subcommand, "*", RlvRules); - if ((args == "add") || (args == "y")) - { - RlvRules = AddRule(Source, command, subcommand, "*", RlvRules); - } - break; - } - case "getcam_fovmax": - case "getcam_avdistmax": - { - GetMaxRulesetValue(command.Replace("get", "set"), argAsInt); - break; - } - case "getcam_zoommin": - case "getcam_avdistmin": - case "getcam_fovmin": - { - GetMinRulesetValue(command.Replace("get","set"), argAsInt); - break; - } - } - } - protected void GetMaxRulesetValue(string ruleName, int channelout) - { - List appliedRules = GetRules(ruleName); - int maxDis = 9999; - foreach (RLVRule rule in appliedRules) - { - if (int.TryParse(rule.Option, out int value) == true) - { - if (value < maxDis) - { - maxDis = value; - } - } - } - ChatOutput(maxDis.ToString(), channelout); - } - - protected void GetMinRulesetValue(string ruleName, int channelout) - { - List appliedRules = GetRules(ruleName); - int minDis = 0; - foreach (RLVRule rule in appliedRules) - { - if (int.TryParse(rule.Option, out int value) == true) - { - if (value > minDis) - { - minDis = value; - } - } - } - ChatOutput(minDis.ToString(), channelout); - } - - protected List GetRules(string command) - { - List reply = new List(); - foreach(RLVRule rule in RlvRules) - { - if(rule.Behaviour == command) - { - reply.Add(rule); - } - } - return reply; - - } - - protected List AddRule(UUID Source,string Behaviour, string Option, string Param, List ruleset) - { - RLVRule newRule = new RLVRule(); - newRule.Behaviour = "permissive"; - newRule.Sender = Source; - newRule.Option = "*"; - newRule.Param = "*"; - ruleset.Add(newRule); - return ruleset; - } - - protected List RemoveRule(string Behaviour, string Option,string Param,List ruleset) - { - bool foundRule = true; - while (foundRule == true) - { - foundRule = false; - int index = -1; - foreach (RLVRule rule in ruleset) - { - if ((rule.Behaviour == Behaviour) && (rule.Option == Option) && (rule.Param == Param)) - { - index = NotifyRules.IndexOf(rule); - break; - } - } - if (index != -1) - { - foundRule = true; - ruleset.RemoveAt(index); - } - } - return ruleset; - } - - protected string GetBlackListAsString(string? filter=null) - { - return ""; - } - - protected void ImChatOutput(UUID target, string message) - { - - } - - protected void ChatOutput(string message, int chan=0) - { - GetClient().Self.Chat(message, chan, ChatType.Normal); - } - - protected void LocalChat(object o, ChatEventArgs e) - { - if(myConfig.GetAllowRlvViaObjectOwnerSay() == false) - { - return; - } - switch (e.Type) - { - case ChatType.OwnerSay: - { - rlvEvent(e.OwnerID, e.Message,false, e.SourceID); - break; - } - case ChatType.Whisper: - case ChatType.Normal: - case ChatType.Shout: - case ChatType.RegionSayTo: - default: - { - break; - } - } - } - - protected void BotImMessage(object o, InstantMessageEventArgs e) - { - if (myConfig.GetAllowRlvViaIm() == false) - { - return; - } - switch (e.IM.Dialog) - { - case InstantMessageDialog.MessageFromObject: - { - // trigger object IM - rlvEvent(e.IM.FromAgentID, e.IM.Message,false, e.IM.FromAgentID); - break; - } - case InstantMessageDialog.MessageFromAgent: // shared with SessionSend - case InstantMessageDialog.SessionSend: - { - if (master.DataStoreService.GetIsGroup(e.IM.IMSessionID) == true) - { - break; - } - // trigger avatar IM - rlvEvent(e.IM.FromAgentID, e.IM.Message, true, e.IM.FromAgentID); - break; - } - default: - { - break; - } - } - } - } - } - - public class RLVRule - { - public string Behaviour { set; get; } - public string Option { set; get; } - public string Param { set; get; } - public UUID Sender { set; get; } - public string SenderName { set; get; } - - public override string ToString() - { - return string.Format("{0}: {1}:{2}={3} [{4}]", SenderName, Behaviour, Option, Param, Sender); - } - } - -}