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);
- }
- }
-
-}