Merge pull request #93 from Madpeterz/debug

Debug
This commit is contained in:
Madpeter 2024-06-24 15:45:32 +01:00 committed by GitHub
commit 3c7baf2838
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 272 additions and 600 deletions

View file

@ -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' \

View file

@ -43,11 +43,11 @@
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
<PackageReference Include="log4net" Version="2.0.17" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.6" />
<PackageReference Include="OggVorbisEncoder" Version="1.2.2" />
<PackageReference Include="OpenJpegDotNet-LMV" Version="2.4.0.5" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.6" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />

View file

@ -116,7 +116,7 @@ namespace OpenMetaverse
/// <summary>Milliseconds without receiving a packet before the
/// connection to a simulator is assumed lost</summary>
public int SIMULATOR_TIMEOUT = 30 * 1000;
public int SIMULATOR_TIMEOUT = 60 * 1000;
/// <summary>Milliseconds to wait for a simulator info request through
/// the grid interface</summary>
@ -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
/// </summary>
public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.None;
public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.Error;
/// <summary>Attach avatar names to log messages</summary>
public bool LOG_NAMES = true;

View file

@ -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<bool, List<string>> 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")]

View file

@ -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<InventoryItem> toBeRemoved = new List<InventoryItem>();
foreach (KeyValuePair<UUID, AttachmentPoint> 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<uint, Primitive> 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;

View file

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

View file

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

View file

@ -10,17 +10,17 @@
<DockerfileRunEnvironmentFiles>settings.env</DockerfileRunEnvironmentFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Discord.Net" Version="3.13.0" />
<PackageReference Include="Discord.Net.WebSocket" Version="3.13.0" />
<PackageReference Include="Discord.Net" Version="3.15.2" />
<PackageReference Include="Discord.Net.WebSocket" Version="3.15.2" />
<PackageReference Include="EmbedIO" Version="3.4.3" />
<PackageReference Include="Microsoft.NET.Build.Containers" Version="8.0.100" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageReference Include="Microsoft.NET.Build.Containers" Version="8.0.302" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
<PackageReference Include="MSBuildGitHash" Version="2.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="RestSharp" Version="110.2.0" />
<PackageReference Include="RestSharp" Version="111.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LibreMetaverse\LibreMetaverse.csproj" />

View file

@ -298,7 +298,7 @@ namespace SecondBotEvents.Services
return new KeyValuePair<bool, string>(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<bool, string>(status, reply);
}
return new KeyValuePair<bool, string>(false, "theMethod is null");

View file

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

View file

@ -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<bool, List<string>> DiscordMemerRoles(string givenserverid, string givenmemberid)
{
if (GetReadyForDiscordActions() == false)
{
// bot is not ready this message should not have got here yet.
return new KeyValuePair<bool, List<string>>(false,new List<string>() { "not ready"});
}
if (ulong.TryParse(givenserverid, out ulong serverid) == false)
{
return new KeyValuePair<bool, List<string>>(false, new List<string>() { "invaild server"});
}
if (ulong.TryParse(givenmemberid, out ulong memberid) == false)
{
return new KeyValuePair<bool, List<string>>(false, new List<string>() { "invaild member"});
}
SocketGuild server = DiscordClient.GetGuild(serverid);
if (server == null)
{
return new KeyValuePair<bool, List<string>>(false, new List<string>() { "Cant get server"});
}
SocketGuildUser user = server.GetUser(memberid);
if(user == null)
{
return new KeyValuePair<bool, List<string>>(false, new List<string>() { "Cant get user" });
}
List<string> roleids = new List<string>();
foreach(SocketRole role in user.Roles)
{
roleids.Add(role.Id.ToString());
}
return new KeyValuePair<bool, List<string>>(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<string, string> values = new Dictionary<string, string>
{
{ "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)

View file

@ -25,6 +25,60 @@ namespace SecondBotEvents.Services
protected UUID OutputAvatar = UUID.Zero;
protected long lastGroupMembershipUpdate = 0;
public void InventoryUpdateEvent(Dictionary<string, string> 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<string, List<string>> InventoryEvents = new Dictionary<string, List<string>>();
public void AddInventoryEvent(string inventoryType, string outputTarget)
{
if(InventoryEvents.ContainsKey(inventoryType) == false)
{
InventoryEvents.Add(inventoryType, new List<string>());
}
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);

View file

@ -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");

View file

@ -165,11 +165,17 @@ namespace SecondBotEvents.Services
protected void BotInventoryAdd(object o, InventoryObjectAddedEventArgs e)
{
InventoryItem F = (InventoryItem)e.Obj;
Dictionary<string, string> details = new Dictionary<string, string>
{
{ "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");
}

View file

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

View file

@ -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<RLVRule> RlvRules = new List<RLVRule>();
protected List<RLVRule> NotifyRules = new List<RLVRule>();
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<RLVRule> 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<RLVRule> 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<RLVRule> GetRules(string command)
{
List<RLVRule> reply = new List<RLVRule>();
foreach(RLVRule rule in RlvRules)
{
if(rule.Behaviour == command)
{
reply.Add(rule);
}
}
return reply;
}
protected List<RLVRule> AddRule(UUID Source,string Behaviour, string Option, string Param, List<RLVRule> ruleset)
{
RLVRule newRule = new RLVRule();
newRule.Behaviour = "permissive";
newRule.Sender = Source;
newRule.Option = "*";
newRule.Param = "*";
ruleset.Add(newRule);
return ruleset;
}
protected List<RLVRule> RemoveRule(string Behaviour, string Option,string Param,List<RLVRule> 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);
}
}
}