This commit is contained in:
Madpeter 2023-12-01 15:20:19 +00:00
parent 3e58148299
commit 25ebadc39b
5 changed files with 536 additions and 1 deletions

View file

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SecondBotEvents.Config
{
public class RlvConfig : Config
{
public RlvConfig(bool fromENV, string fromFolder = "") : base(fromENV, fromFolder) { }
protected override void MakeSettings()
{
filename = "rlv";
settings.Add("Enabled");
settings.Add("AllowRlvViaIm");
settings.Add("AllowRlvViaObjectOwnerSay");
settings.Add("HideStatusOutput");
}
public bool GetAllowRlvViaIm()
{
return ReadSettingAsBool("AllowRlvViaIm", false);
}
public bool GetAllowRlvViaObjectOwnerSay()
{
return ReadSettingAsBool("AllowRlvViaObjectOwnerSay", false);
}
public bool GetEnabled()
{
return ReadSettingAsBool("Enabled", false);
}
}
}

View file

@ -168,6 +168,22 @@ namespace SecondBotEvents.Services
CommandInterfaceCaller(e.IM.Message, requireSigning); CommandInterfaceCaller(e.IM.Message, requireSigning);
} }
public bool AvatarUUIDIsMaster(UUID avatar)
{
foreach(string name in myConfig.GetMastersCSV())
{
string find = master.DataStoreService.GetAvatarUUID(name);
if (find != "lookup")
{
if(avatar.ToString() == find)
{
return true;
}
}
}
return false;
}
public KeyValuePair<bool, string> CommandInterfaceCaller(string message, bool requireSigning=false, bool viaCustomCommand=false) public KeyValuePair<bool, string> CommandInterfaceCaller(string message, bool requireSigning=false, bool viaCustomCommand=false)
{ {
string source = "command interface"; string source = "command interface";

View file

@ -6,6 +6,7 @@ using System.Linq;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using SecondBotEvents.Commands;
namespace SecondBotEvents.Services namespace SecondBotEvents.Services
{ {
@ -505,7 +506,6 @@ namespace SecondBotEvents.Services
* if not the bot will attempt to * if not the bot will attempt to
* lookup the avatar * lookup the avatar
*/ */
public bool KnownAvatar(string name) public bool KnownAvatar(string name)
{ {
return KnownAvatar(name, UUID.Zero); return KnownAvatar(name, UUID.Zero);

View file

@ -73,6 +73,7 @@ namespace SecondBotEvents.Services
protected void BotLoggedOut(object o, LoggedOutEventArgs e) protected void BotLoggedOut(object o, LoggedOutEventArgs e)
{ {
GetClient().Network.SimConnected += BotLoggedIn; GetClient().Network.SimConnected += BotLoggedIn;
botConnected = false;
LogFormater.Info("Events service [Bot commands disabled]"); LogFormater.Info("Events service [Bot commands disabled]");
removeEvents(); removeEvents();
} }

View file

@ -0,0 +1,486 @@
namespace SecondBotEvents.Services
{
using Discord;
using global::SecondBotEvents.Commands;
using global::SecondBotEvents.Config;
using OpenMetaverse;
using OpenMetaverse.ImportExport.Collada14;
using SecondBotEvents.Commands;
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 "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 "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 "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 "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);
}
}
}