From 434d772705f7d1c6849f4ca4ca99d5f457b09136 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Wed, 21 Sep 2022 19:47:28 +0100 Subject: [PATCH] on Events support --- SecondBotEvents/Commands/Funds.cs | 3 +- SecondBotEvents/Config/EventsConfig.cs | 125 ++++++ SecondBotEvents/EventsSecondBot.cs | 2 + SecondBotEvents/Services/DataStoreService.cs | 18 + SecondBotEvents/Services/EventsService.cs | 398 +++++++++++++++++++ SecondBotEvents/Services/Services.cs | 8 + 6 files changed, 553 insertions(+), 1 deletion(-) create mode 100644 SecondBotEvents/Config/EventsConfig.cs create mode 100644 SecondBotEvents/Services/EventsService.cs diff --git a/SecondBotEvents/Commands/Funds.cs b/SecondBotEvents/Commands/Funds.cs index 4c07224..db5f3d1 100644 --- a/SecondBotEvents/Commands/Funds.cs +++ b/SecondBotEvents/Commands/Funds.cs @@ -47,7 +47,8 @@ namespace SecondBotEvents.Commands } if ((amountvalue < 0) || (amountvalue > GetClient().Self.Balance)) { - return Failure("Amount out of range", new [] { avatar, amount }); + GetClient().Self.RequestBalance(); + return Failure("Amount out of range current max: "+ GetClient().Self.Balance.ToString(), new [] { avatar, amount }); } GetClient().Self.GiveAvatarMoney(avataruuid, amountvalue); return BasicReply("Accepted", new [] { avatar, amount }); diff --git a/SecondBotEvents/Config/EventsConfig.cs b/SecondBotEvents/Config/EventsConfig.cs new file mode 100644 index 0000000..444fbe7 --- /dev/null +++ b/SecondBotEvents/Config/EventsConfig.cs @@ -0,0 +1,125 @@ +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SecondBotEvents.Config +{ + public class EventsConfig : Config + { + public EventsConfig(bool fromENV, string fromFolder = "") : base(fromENV, fromFolder) { } + protected override void MakeSettings() + { + filename = "events"; + settings.Add("Enabled"); + settings.Add("GroupMemberJoins"); + settings.Add("GroupMemberLeaves"); + settings.Add("GroupMemberEventsGroupUUID"); + + settings.Add("GuestEntersArea"); + settings.Add("GuestLeavesArea"); + settings.Add("GuestTrackingSimname"); + settings.Add("GuestTrackingParcelname"); + + + settings.Add("SimAlertMessage"); + settings.Add("StatusMessage"); + settings.Add("MoneyEvent"); + + + settings.Add("ChangeSim"); + settings.Add("ChangeParcel"); + + settings.Add("OutputChannel"); + settings.Add("OutputIMuuid"); + settings.Add("OutputHttpURL"); + settings.Add("OutputSecret"); + } + + public string GetOutputSecret() + { + return ReadSettingAsString("OutputSecret", "donttellanyone"); + } + + public string GetGuestTrackingSimname() + { + return ReadSettingAsString("GuestTrackingSimname", "example"); + } + + public string GetGuestTrackingParcelname() + { + return ReadSettingAsString("GuestTrackingParcelname", "example"); + } + + public string GetGroupMemberEventsGroupUUID() + { + return ReadSettingAsString("GroupMemberEventsGroupUUID", UUID.Zero.ToString()); + } + + public string GetOutputHttpURL() + { + return ReadSettingAsString("OutputHttpURL", "n/a"); + } + + public string GetOutputIMuuid() + { + return ReadSettingAsString("OutputIMuuid", UUID.Zero.ToString()); + } + + public int GetOutputChannel() + { + return ReadSettingAsInt("OutputChannel", -1); + } + + public bool GetGroupMemberJoins() + { + return ReadSettingAsBool("GroupMemberJoins", true); + } + + public bool GetGroupMemberLeaves() + { + return ReadSettingAsBool("GroupMemberLeaves", true); + } + + public bool GetGuestEntersArea() + { + return ReadSettingAsBool("GuestEntersArea", true); + } + + public bool GetGuestLeavesArea() + { + return ReadSettingAsBool("GuestLeavesArea", true); + } + + public bool GetChangeSim() + { + return ReadSettingAsBool("ChangeSim", true); + } + + public bool GetChangeParcel() + { + return ReadSettingAsBool("ChangeParcel", true); + } + + public bool GetSimAlertMessage() + { + return ReadSettingAsBool("SimAlertMessage", true); + } + + public bool GetStatusMessage() + { + return ReadSettingAsBool("StatusMessage", true); + } + + public bool GetMoneyEvent() + { + return ReadSettingAsBool("MoneyEvent", true); + } + + public bool GetEnabled() + { + return ReadSettingAsBool("Enabled", false); + } + } + +} \ No newline at end of file diff --git a/SecondBotEvents/EventsSecondBot.cs b/SecondBotEvents/EventsSecondBot.cs index 35adc62..de81870 100644 --- a/SecondBotEvents/EventsSecondBot.cs +++ b/SecondBotEvents/EventsSecondBot.cs @@ -36,6 +36,7 @@ namespace SecondBotEvents public InteractionService InteractionService { get { return (InteractionService)GetService("InteractionService"); } } public DataStoreService DataStoreService { get { return (DataStoreService)GetService("DataStoreService"); } } public HomeboundService HomeboundService { get { return (HomeboundService)GetService("HomeboundService"); } } + public EventsService EventsService { get { return (EventsService)GetService("EventsService"); } } private EventHandler SystemStatusMessages; @@ -145,6 +146,7 @@ namespace SecondBotEvents RegisterService("DiscordService"); RegisterService("InteractionService"); RegisterService("HomeboundService"); + RegisterService("EventsService"); if (BotClient.IsLoaded() == false) { Console.WriteLine("Config is not loaded :("); diff --git a/SecondBotEvents/Services/DataStoreService.cs b/SecondBotEvents/Services/DataStoreService.cs index 1b22cf1..c31c4de 100644 --- a/SecondBotEvents/Services/DataStoreService.cs +++ b/SecondBotEvents/Services/DataStoreService.cs @@ -583,6 +583,23 @@ namespace SecondBotEvents.Services return true; } + public void GetAvatarNames(List avatars) + { + List lookup = new List(); + foreach (UUID id in avatars) + { + if (avatarsName2Key.ContainsValue(id) == false) + { + lookup.Add(id); + } + } + if(lookup.Count == 0) + { + return; + } + GetClient().Avatars.RequestAvatarNames(lookup); + } + public string GetAvatarName(UUID avatarId) { string reply = "lookup"; @@ -856,6 +873,7 @@ namespace SecondBotEvents.Services GetClient().Groups.RequestCurrentGroups(); botConnected = true; Console.WriteLine("DataStore Service [Active]"); + GetAvatarName(GetClient().Self.AgentID); } readonly string[] hard_blocked_agents = new[] { "secondlife", "second life" }; protected void ChatFromSim(object o, ChatEventArgs e) diff --git a/SecondBotEvents/Services/EventsService.cs b/SecondBotEvents/Services/EventsService.cs new file mode 100644 index 0000000..753635b --- /dev/null +++ b/SecondBotEvents/Services/EventsService.cs @@ -0,0 +1,398 @@ +using OpenMetaverse; +using SecondBotEvents.Config; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Newtonsoft.Json; +using System.Linq; +using Swan; + +namespace SecondBotEvents.Services +{ + public class EventsService : BotServices + { + protected EventsConfig myConfig; + protected bool botConnected = false; + protected string lastSimName = ""; + protected UUID TrackGroupUUID = UUID.Zero; + protected List GroupMembers = new List(); + protected bool GroupLoaded = false; + protected List AvatarsOnSim = new List(); + protected bool GuestListLoaded = false; + protected string lastparcelname = ""; + protected UUID OutputAvatar = UUID.Zero; + protected long lastGroupMembershipUpdate = 0; + + public EventsService(EventsSecondBot setMaster) : base(setMaster) + { + myConfig = new EventsConfig(master.fromEnv, master.fromFolder); + if(myConfig.GetEnabled() == false) + { + return; + } + if (UUID.TryParse(myConfig.GetOutputIMuuid(), out OutputAvatar) == false) + { + OutputAvatar = UUID.Zero; + } + if (UUID.TryParse(myConfig.GetGroupMemberEventsGroupUUID(), out TrackGroupUUID) == false) + { + TrackGroupUUID = UUID.Zero; + } + } + public override string Status() + { + if (myConfig == null) + { + return "Config broken"; + } + if (myConfig.GetEnabled() == false) + { + return "- Not requested -"; + } + if (botConnected == false) + { + return "Waiting for bot"; + } + TimedEvents(); + return "Active"; + } + + protected void BotClientRestart(object o, BotClientNotice e) + { + Console.WriteLine("Events service [Attached to new client]"); + GetClient().Network.LoggedOut += BotLoggedOut; + GetClient().Network.SimConnected += BotLoggedIn; + } + + protected void BotLoggedOut(object o, LoggedOutEventArgs e) + { + GetClient().Network.SimConnected += BotLoggedIn; + Console.WriteLine("Events service [Bot commands disabled]"); + removeEvents(); + } + + protected void BotLoggedIn(object o, SimConnectedEventArgs e) + { + GetClient().Network.SimConnected -= BotLoggedIn; + botConnected = true; + // attach events + GetClient().Self.MoneyBalanceReply += BotMoneyEvent; + GetClient().Network.SimChanged += BotChangedSim; + GetClient().Groups.GroupMembersReply += BotGroupMembers; + GetClient().Self.AlertMessage += BotAlertMessage; + } + + protected string avatarhash = ""; + protected void TrackAvatarsOnParcel() + { + if ((myConfig.GetGuestTrackingSimname() != GetClient().Network.CurrentSim.Name) || (myConfig.GetGuestTrackingParcelname() != lastparcelname)) + { + AvatarsOnSim = new List(); + GuestListLoaded = false; + return; + } + + string hashstring = ""; + List avs = new List(); + foreach(Avatar A in GetClient().Network.CurrentSim.ObjectsAvatars.Copy().Values) + { + avs.Add(A.ID); + hashstring = hashstring+A.ID.ToString(); + } + string hash = SecondbotHelpers.GetSHA1(hashstring); + if (hash == avatarhash) + { + return; + } + avatarhash = hash; + + if (GuestListLoaded == true) + { + List joined = new List(); + List tracked = new List(); + foreach (UUID a in AvatarsOnSim) + { + tracked.Add(a); + } + foreach (UUID a in avs) + { + if (tracked.Contains(a) == true) + { + tracked.Remove(a); + continue; + } + joined.Add(a); + } + if ((tracked.Count > 0) || (joined.Count > 0)) + { + if ((tracked.Count > 0) && (myConfig.GetGuestLeavesArea() == true)) + { + foreach (UUID a in tracked) + { + GuestTrackingEvent(a, "exit"); + } + } + if ((joined.Count > 0) && (myConfig.GetGuestEntersArea() == true)) + { + foreach (UUID a in joined) + { + GuestTrackingEvent(a, "enter"); + } + } + } + } + AvatarsOnSim = avs; + GuestListLoaded = true; + } + protected void TimedEvents() + { + int localid = GetClient().Parcels.GetParcelLocalID(GetClient().Network.CurrentSim, GetClient().Self.SimPosition); + if (GetClient().Network.CurrentSim.Parcels.ContainsKey(localid) == false) + { + GetClient().Parcels.GetParcelLocalID(GetClient().Network.CurrentSim, GetClient().Self.SimPosition); + return; + } + if(lastparcelname != GetClient().Network.CurrentSim.Parcels[localid].Name) + { + BotChangedParcel(GetClient().Network.CurrentSim.Parcels[localid].Name); + } + TrackAvatarsOnParcel(); + if(TrackGroupUUID != UUID.Zero) + { + long dif = SecondbotHelpers.UnixTimeNow() - lastGroupMembershipUpdate; + if (dif > 120) + { + lastGroupMembershipUpdate = SecondbotHelpers.UnixTimeNow(); + GetClient().Groups.RequestGroupMembers(TrackGroupUUID); + } + } + } + + protected void removeEvents() + { + botConnected = false; + if (GetClient() != null) + { + GetClient().Self.MoneyBalanceReply -= BotMoneyEvent; + GetClient().Network.SimChanged -= BotChangedSim; + GetClient().Groups.GroupMembersReply -= BotGroupMembers; + GetClient().Self.AlertMessage -= BotAlertMessage; + } + } + + protected void PushEvent(string eventname, Dictionary args) + { + OnEvent e = new OnEvent( + GetClient().Self.AgentID.ToString(), + eventname, + args, + myConfig.GetOutputSecret() + ); + string output = JsonConvert.SerializeObject(e); + if(myConfig.GetOutputChannel() >= 0) + { + GetClient().Self.Chat(output, myConfig.GetOutputChannel(), ChatType.Normal); + } + if(OutputAvatar != UUID.Zero) + { + GetClient().Self.InstantMessage(OutputAvatar, output); + } + // @todo add HTTP output + + } + + protected void BotAlertMessage(object senderm, AlertMessageEventArgs e) + { + if(myConfig.GetSimAlertMessage() == false) + { + return; + } + Dictionary args = new Dictionary(); + args.Add("Message", e.Message); + args.Add("NotificationId", e.NotificationId); + PushEvent("AlertMessage", args); + } + + protected void BotChangedParcel(string newparcelname) + { + if (myConfig.GetChangeParcel() == false) + { + return; + } + Dictionary args = new Dictionary(); + args.Add("oldparcel", lastparcelname); + args.Add("newparcel", newparcelname); + lastparcelname = newparcelname; + PushEvent("ChangedParcel", args); + } + + protected void BotStatusMessage(object sender, SystemStatusMessage e) + { + if((e.changed == false) || (myConfig.GetStatusMessage() == false)) + { + return; + } + Dictionary args = new Dictionary(); + args.Add("Message", e.message); + PushEvent("StatusMessage", args); + } + + protected void BotGroupMembers(object sender, GroupMembersReplyEventArgs e) + { + if(e.GroupID != TrackGroupUUID) + { + return; + } + if(GroupLoaded == true) + { + List joined = new List(); + List tracked = new List(); + foreach (UUID a in GroupMembers) + { + tracked.Add(a); + } + master.DataStoreService.GetAvatarNames(tracked); + foreach (UUID a in e.Members.Keys) + { + if(tracked.Contains(a) == true) + { + tracked.Remove(a); + continue; + } + joined.Add(a); + } + if((tracked.Count > 0) && (myConfig.GetGroupMemberLeaves() == true)) + { + foreach(UUID a in tracked) + { + GroupMembershipEvent(a, "leave"); + } + } + if ((joined.Count > 0) && (myConfig.GetGroupMemberJoins() == true)) + { + foreach (UUID a in joined) + { + GroupMembershipEvent(a, "join"); + } + } + } + + GroupMembers = new List(); + foreach (UUID a in e.Members.Keys) + { + GroupMembers.Add(a); + } + GroupLoaded = true; + } + + protected void GroupMembershipEvent(UUID avatar, string action) + { + Dictionary args = new Dictionary(); + args.Add("uuid", avatar.ToString()); + args.Add("name", master.DataStoreService.GetAvatarName(avatar)); + args.Add("action", action); + PushEvent("GroupMembership", args); + } + + protected void GuestTrackingEvent(UUID avatar, string action) + { + Dictionary args = new Dictionary(); + args.Add("uuid", avatar.ToString()); + args.Add("name", master.DataStoreService.GetAvatarName(avatar)); + args.Add("action", action); + PushEvent("GuestTracking", args); + } + + protected void BotChangedSim(object sender, SimChangedEventArgs e) + { + if(myConfig.GetChangeSim() == false) + { + return; + } + Dictionary args = new Dictionary(); + args.Add("lastsim", lastSimName); + args.Add("newsim", GetClient().Network.CurrentSim.Name); + PushEvent("ChangedSim", args); + lastSimName = e.PreviousSimulator.Name; + } + + protected void BotMoneyEvent(object sender, MoneyBalanceReplyEventArgs e) + { + if(myConfig.GetMoneyEvent() == false) + { + return; + } + Dictionary args = new Dictionary(); + args.Add("fromuuid", e.TransactionInfo.SourceID.ToString()); + args.Add("touuid", e.TransactionInfo.DestID.ToString()); + args.Add("amount", e.TransactionInfo.Amount.ToString()); + args.Add("balance", e.Balance.ToString()); + args.Add("fromname", master.DataStoreService.GetAvatarName(e.TransactionInfo.SourceID)); + args.Add("toname", master.DataStoreService.GetAvatarName(e.TransactionInfo.DestID)); + args.Add("transactionid", e.TransactionID.ToString()); + PushEvent("MoneyEvent", args); + } + + + + public override void Start() + { + if (myConfig.GetEnabled() == false) + { + Console.WriteLine("Events service [Disabled]"); + return; + } + Stop(); + master.BotClientNoticeEvent += BotClientRestart; + master.SystemStatusMessagesEvent += BotStatusMessage; + } + + public override void Stop() + { + if (myConfig.GetEnabled() == false) + { + return; + } + master.BotClientNoticeEvent -= BotClientRestart; + master.SystemStatusMessagesEvent -= BotStatusMessage; + removeEvents(); + } + } + + public class OnEvent + { + public string EventName = ""; + public Dictionary Data = new Dictionary(); + public string Hash = ""; + public long Unixtime = 0; + public string BotUUID = ""; + + public OnEvent(string eventBotUUID, string setEventName, Dictionary eventData, string Secret) + { + BotUUID = eventBotUUID; + EventName = setEventName; + Data = eventData; + Unixtime = SecondbotHelpers.UnixTimeNow(); + SignEvent(Secret); + } + + public string getJson() + { + return ""; + } + + + + protected void SignEvent(string Secret) + { + string raw = BotUUID+ EventName; + foreach(string A in Data.Values) + { + raw = raw + A; + } + raw = raw + Unixtime.ToString() + Secret; + Hash = SecondbotHelpers.GetSHA1(raw); + } + } +} diff --git a/SecondBotEvents/Services/Services.cs b/SecondBotEvents/Services/Services.cs index 99a7233..6884fbf 100644 --- a/SecondBotEvents/Services/Services.cs +++ b/SecondBotEvents/Services/Services.cs @@ -15,6 +15,14 @@ namespace SecondBotEvents.Services public GridClient GetClient() { + if(master == null) + { + return null; + } + else if(master.BotClient == null) + { + return null; + } return master.BotClient.client; } public virtual string Status()