From 6eaa112f8188573aeb08e2c088bd664c680691e7 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Fri, 28 Jun 2024 21:27:07 +0100 Subject: [PATCH 01/17] wip --- SecondBotEvents/Config/OnEventConfig.cs | 129 ++++ SecondBotEvents/Services/EventsService.cs | 18 + .../Services/InteractionService.cs | 1 - .../Services/TriggerOnEventService.cs | 550 ++++++++++++++++++ 4 files changed, 697 insertions(+), 1 deletion(-) create mode 100644 SecondBotEvents/Config/OnEventConfig.cs create mode 100644 SecondBotEvents/Services/TriggerOnEventService.cs diff --git a/SecondBotEvents/Config/OnEventConfig.cs b/SecondBotEvents/Config/OnEventConfig.cs new file mode 100644 index 0000000..ee6c89d --- /dev/null +++ b/SecondBotEvents/Config/OnEventConfig.cs @@ -0,0 +1,129 @@ +using OpenMetaverse; +using SecondBotEvents.Services; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SecondBotEvents.Config +{ + public class OnEventConfig : Config + { + public OnEventConfig(bool fromENV, string fromFolder = "") : base(fromENV, fromFolder) { } + protected override void MakeSettings() + { + filename = "onevent"; + settings.Add("Enabled"); + settings.Add("Count"); + int loop = 1; + while (loop <= GetCount()) + { + settings.Add("Event" + loop.ToString() + "Enabled"); + if(GetEventEnabled(loop) == false) + { + loop++; + continue; + } + settings.Add("Event" + loop.ToString() + "Source"); + settings.Add("Event" + loop.ToString() + "Monitor"); + settings.Add("Event" + loop.ToString() + "WhereCount"); + int loop2 = 1; + while (loop2 <= GetWhereCount(loop)) + { + settings.Add("Event" + loop.ToString() + "Where" + loop2.ToString()); + loop2++; + } + settings.Add("Event" + loop.ToString() + "ActionCount"); + loop2 = 1; + while (loop2 <= GetActionCount(loop)) + { + settings.Add("Event" + loop.ToString() + "Action" + loop2.ToString()); + loop2++; + } + loop++; + } + settings.Add("HideStatusOutput"); + return; + } + + public void unloadEvents() + { + int loop = 1; + while (loop <= GetCount()) + { + if (GetEventEnabled(loop) == false) + { + loop++; + continue; + } + RemoveSetting("Event" + loop.ToString() + "Enabled"); + RemoveSetting("Event" + loop.ToString() + "Source"); + RemoveSetting("Event" + loop.ToString() + "Monitor"); + int loop2 = 1; + while (loop2 <= GetWhereCount(loop)) + { + RemoveSetting("Event" + loop.ToString() + "Where" + loop2.ToString()); + loop2++; + } + RemoveSetting("Event" + loop.ToString() + "WhereCount"); + loop2 = 1; + while (loop2 <= GetActionCount(loop)) + { + settings.Remove("Event" + loop.ToString() + "Action" + loop2.ToString()); + loop2++; + } + RemoveSetting("Event" + loop.ToString() + "ActionCount"); + loop++; + } + } + + protected void RemoveSetting(string name) + { + mysettings.Remove(name); + settings.Remove(name); + } + + public bool GetEnabled() + { + return ReadSettingAsBool("Enabled", false); + } + + public int GetCount() + { + return ReadSettingAsInt("Count", 0); + } + + public int GetActionCount(int oneventid) + { + return ReadSettingAsInt("Event" + oneventid.ToString() + "ActionCount", 0); + } + + public string GetActionStep(int oneventid, int stepid) + { + return ReadSettingAsString("Event" + oneventid.ToString() + "Action" + stepid.ToString(), ""); + } + + public string GetWhereCheck(int oneventid, int checkid) + { + return ReadSettingAsString("Event" + oneventid.ToString() + "Where" + checkid.ToString(), ""); + } + + public int GetWhereCount(int oneventid) + { + return ReadSettingAsInt("Event" + oneventid.ToString() + "WhereCount", 0); + } + + public bool GetEventEnabled(int oneventid) + { + return ReadSettingAsBool("Event" + oneventid.ToString() + "Enabled", false); + } + + public string GetSource(int oneventid) + { + return ReadSettingAsString("Event" + oneventid.ToString() + "Source", ""); + } + public string GetSourceMonitor(int oneventid) + { + return ReadSettingAsString("Event" + oneventid.ToString() + "Monitor", ""); + } + } +} \ No newline at end of file diff --git a/SecondBotEvents/Services/EventsService.cs b/SecondBotEvents/Services/EventsService.cs index 9a7123f..e5e5dbb 100644 --- a/SecondBotEvents/Services/EventsService.cs +++ b/SecondBotEvents/Services/EventsService.cs @@ -25,6 +25,7 @@ namespace SecondBotEvents.Services protected UUID OutputAvatar = UUID.Zero; protected long lastGroupMembershipUpdate = 0; + public void InventoryUpdateEvent(Dictionary detail) { if (InventoryEvents.ContainsKey(detail["itemtype"]) == true) @@ -143,6 +144,7 @@ namespace SecondBotEvents.Services GetClient().Self.AlertMessage += BotAlertMessage; } + protected long lastAvUpdate = 0; protected string avatarhash = ""; protected void TrackAvatarsOnParcel() { @@ -152,6 +154,13 @@ namespace SecondBotEvents.Services GuestListLoaded = false; return; } + long dif = SecondbotHelpers.UnixTimeNow() - lastAvUpdate; + if(dif < 30) + { + // only check for changes every 30 secs + return; + } + lastAvUpdate = SecondbotHelpers.UnixTimeNow(); string hashstring = ""; List avs = new List(); @@ -471,4 +480,13 @@ namespace SecondBotEvents.Services Hash = SecondbotHelpers.GetSHA1(raw); } } + + public class GuestUpdateEvent + { + public string parcelName = ""; + public string regionName = ""; + public string avatarName = ""; + public UUID avatarUUID = UUID.Zero; + public bool entered = false; + } } diff --git a/SecondBotEvents/Services/InteractionService.cs b/SecondBotEvents/Services/InteractionService.cs index 284f515..dcd26d2 100644 --- a/SecondBotEvents/Services/InteractionService.cs +++ b/SecondBotEvents/Services/InteractionService.cs @@ -278,7 +278,6 @@ namespace SecondBotEvents.Services GetClient().Groups.GroupInvitation -= BotGroupInviteOffer; } } - } } diff --git a/SecondBotEvents/Services/TriggerOnEventService.cs b/SecondBotEvents/Services/TriggerOnEventService.cs new file mode 100644 index 0000000..4014f61 --- /dev/null +++ b/SecondBotEvents/Services/TriggerOnEventService.cs @@ -0,0 +1,550 @@ +using OpenMetaverse; +using SecondBotEvents.Config; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SecondBotEvents.Services +{ + public class TriggerOnEventService : BotServices + { + protected OnEventConfig myConfig; + protected bool botConnected = false; + Dictionary> MyCustomEvents = new Dictionary>(); + Dictionary lockouts = new Dictionary(); + public TriggerOnEventService(EventsSecondBot setMaster) : base(setMaster) + { + myConfig = new OnEventConfig(master.fromEnv, master.fromFolder); + int loop = 1; + string[] delimiterChars = new string[] { "{IS}", "{NOT}", "{IS_UUD}", "{MISSING}", "{CONTAINS}", "{IN_GROUP}", "{NOT_IN_GROUP}", "{LESSTHAN}", "{MORETHAN}", "{LOCKOUT}" }; + while (loop < myConfig.GetCount()) + { + if(myConfig.GetEventEnabled(loop) == false) + { + loop++; + continue; + } + CustomOnEvent Event = new CustomOnEvent(); + Event.Source = myConfig.GetSource(loop); + Event.MonitorFlags = myConfig.GetSourceMonitor(loop).Split(',').ToList(); + bool eventWhereOk = true; + int loop2 = 1; + while(loop2 < myConfig.GetWhereCount(loop)) + { + string check = myConfig.GetWhereCheck(loop, loop2); + foreach (string delimiterChar in delimiterChars) + { + if(check.Contains(delimiterChar) == false) + { + continue; + } + string[] bits = check.Split(delimiterChar, StringSplitOptions.RemoveEmptyEntries); + if (bits.Length == 2) + { + string delimiterCharU = delimiterChar.Replace("{", ""); + delimiterCharU = delimiterCharU.Replace("}", ""); + delimiterCharU = delimiterCharU.Trim(); + Event.WhereChecksLeft.Add(bits[0].Trim()); + Event.WhereChecksCenter.Add(delimiterCharU); + Event.WhereChecksRight.Add(bits[1].Trim()); + } + else + { + eventWhereOk = false; + } + break; + } + loop2++; + } + if(eventWhereOk == false) + { + continue; + } + loop2 = 1; + while (loop2 < myConfig.GetActionCount(loop)) + { + Event.Actions.Add(myConfig.GetActionStep(loop, loop2)); + loop2++; + } + if(MyCustomEvents.ContainsKey(Event.Source) == false) + { + MyCustomEvents.Add(Event.Source, new List()); + } + MyCustomEvents[Event.Source].Add(Event); + loop++; + } + myConfig.unloadEvents(); // remove unneeded copy of events from the config as we wont be using it + } + + protected void BotClientRestart(object o, BotClientNotice e) + { + botConnected = false; + LogFormater.Info("OnEvent Service [Attached to new client]"); + GetClient().Network.LoggedOut += BotLoggedOut; + GetClient().Network.SimConnected += BotLoggedIn; + } + + protected void BotLoggedOut(object o, LoggedOutEventArgs e) + { + botConnected = false; + GetClient().Network.SimConnected += BotLoggedIn; + LogFormater.Info("OnEvent Service [Standby]"); + } + + protected void BotImMessage(object o, InstantMessageEventArgs e) + { + switch (e.IM.Dialog) + { + case InstantMessageDialog.MessageFromObject: + { + break; + } + case InstantMessageDialog.MessageFromAgent: // shared with SessionSend + case InstantMessageDialog.SessionSend: + { + if (e.IM.GroupIM == true) + { + break; + } + // trigger avatar IM + TriggerEvent("AvatarIm", new Dictionary() { + { "message", e.IM.Message} , + { "avatarname", e.IM.FromAgentName}, + { "avataruuid", e.IM.FromAgentID.ToString() }, + }); + break; + } + default: + { + break; + } + } + } + + protected void RemoveEvents() + { + if (master.BotClient != null) + { + if (GetClient() != null) + { + GetClient().Self.IM -= BotImMessage; + } + } + } + + protected void AttachEvents() + { + GetClient().Self.IM += BotImMessage; + } + + protected string GetAvName(string avataruuid) + { + string avatarname = "lookup"; + if (avataruuid != null) + { + if (UUID.TryParse(avataruuid, out UUID avUUID) == true) + { + avatarname = master.DataStoreService.GetAvatarName(avUUID); + } + } + return avatarname; + } + + protected bool IsLockedout(string uuid) + { + lock (lockouts) + { + if (lockouts.ContainsKey(uuid) == false) + { + return false; + } + long now = SecondbotHelpers.UnixTimeNow(); + if(now >= lockouts[uuid]) + { + lockouts.Remove(uuid); + return false; + } + return true; + } + } + + protected void AddToLockout(string uuid, int mins) + { + lock (lockouts) + { + long newvalue = SecondbotHelpers.UnixTimeNow() + (mins * 60); + if (lockouts.ContainsKey(uuid) == true) + { + if (lockouts[uuid] < newvalue) + { + lockouts[uuid] = newvalue; + } + return; + } + lockouts.Add(uuid, newvalue); + } + } + + long lastCleanedLockouts = 0; + protected void CleanLockouts() + { + long dif = SecondbotHelpers.UnixTimeNow() - lastCleanedLockouts; + if(dif < 60) + { + return; + } + lastCleanedLockouts = SecondbotHelpers.UnixTimeNow(); + long now = SecondbotHelpers.UnixTimeNow(); + lock (lockouts) + { + List toberemoved = new List(); + foreach(KeyValuePair pair in lockouts) + { + if(pair.Value > now) + { + continue; + } + toberemoved.Add(pair.Key); + } + foreach(string A in toberemoved) + { + lockouts.Remove(A); + } + } + } + + protected void TriggerEvent(string eventName, Dictionary args) + { + if (MyCustomEvents.ContainsKey(eventName) == false) + { + return; + } + string avataruuid = null; + if (args.ContainsKey("avataruuid") == true) + { + avataruuid = args["avataruuid"]; + } + Dictionary values = new Dictionary(); + values.Add("eventype", eventName); + values.Add("avatarname", GetAvName(avataruuid)); + values.Add("avatarparcel", GetAvParcel(avataruuid)); + values.Add("botsim", GetClient().Network.CurrentSim.Name); + values.Add("botparcel", GetBotParcel()); + List AvPos = GetAvPos(avataruuid); + values.Add("avatarx", AvPos[0].ToString()); + values.Add("avatary", AvPos[1].ToString()); + values.Add("avatarz", AvPos[2].ToString()); + values.Add("avatardistance", AvPos[3].ToString()); + Vector3 A = GetClient().Self.SimPosition; + List BotPos = new List() { (int)Math.Round(A.X), (int)Math.Round(A.Y), (int)Math.Round(A.Z) }; + values.Add("botx", AvPos[0].ToString()); + values.Add("boty", AvPos[1].ToString()); + values.Add("botz", AvPos[2].ToString()); + values.Add("clockhour", DateTime.Now.ToString("HH")); + values.Add("clockmin", DateTime.Now.ToString("mm")); + values.Add("dayofweek", ((int)DateTime.Now.DayOfWeek).ToString()); + + + if (avataruuid == null) + { + avataruuid = "none"; + } + if(args.ContainsKey("message") == false) + { + args["message"] = "none"; + } + values.Add("avataruuid", avataruuid); + foreach (CustomOnEvent E in MyCustomEvents[eventName]) + { + bool canFireEvent = true; + int loop = 0; + while(loop < E.WhereChecksLeft.Count()) + { + string left = swapvalues(E.WhereChecksLeft[loop],values); + string center = E.WhereChecksCenter[loop]; + string right = swapvalues(E.WhereChecksRight[loop], values); + int leftAsInt = -1; + int rightAsInt = -1; + int.TryParse(left, out leftAsInt); + int.TryParse(right, out rightAsInt); + bool leftAsBool = false; + if(left == "true") leftAsBool = true; + bool rightAsBool = false; + if (right == "true") rightAsBool = true; + bool leftContactinsRight = left.Contains(right); + UUID leftAsUUID = UUID.Zero; + bool leftIsUUID = UUID.TryParse(left, out leftAsUUID); + UUID rightAsUUID = UUID.Zero; + bool rightIsUUID = UUID.TryParse(right, out rightAsUUID); + bool leftIsInGroup = false; + bool leftIsLockedout = IsLockedout(left); + bool leftIsEven = (leftAsInt % 2 == 0); + bool leftIsDivs = (leftAsInt % rightAsInt == 0); + if ((leftIsUUID == true) && (rightIsUUID == true)) + { + leftIsInGroup = master.DataStoreService.IsGroupMember(rightAsUUID, leftAsUUID); + } + if ((center == "IS") && (left != right)) { canFireEvent = false; } + else if ((center == "NOT") && (left == right)) { canFireEvent = false; } + else if ((center == "IS_UUID") && (leftIsUUID != rightAsBool)) { canFireEvent = false; } + else if ((center == "MISSING") && (leftContactinsRight == true)) { canFireEvent = false; } + else if ((center == "CONTAINS") && (leftContactinsRight == false)) { canFireEvent = false; } + else if ((center == "IN_GROUP") && (leftIsInGroup == false)) { canFireEvent = false; } + else if ((center == "NOT_IN_GROUP") && (leftIsUUID == true) && (rightIsUUID == true) && (leftIsInGroup == true)) { canFireEvent = false; } + else if ((center == "LESSTHAN") && (leftAsInt >= rightAsInt)) { canFireEvent = false; } + else if ((center == "MORETHAN") && (leftAsInt <= rightAsInt)) { canFireEvent = false; } + else if ((center == "LOCKOUT") && (leftIsLockedout != rightAsBool)) { canFireEvent = false; } + else if ((center == "IS_EVEN") && (leftIsEven != rightAsBool)) { canFireEvent = false; } + else if ((center == "DIVISIBLE") && (leftIsDivs == false)) { canFireEvent = false; } + if (canFireEvent == false) + { + break; + } + loop++; + } + if (canFireEvent == false) + { + continue; + } + foreach(string action in E.Actions) + { + string useaction = swapvalues(action, values); + string[] bits = useaction.Split('='); + if(bits.Length == 2) + { + if (bits[0] == "lockout") + { + bits = bits[1].Split("+"); + if(bits.Length == 2) + { + if (int.TryParse(bits[1],out int mins) == true) + { + AddToLockout(bits[0], mins); + } + } + continue; + } + } + master.CommandsService.CommandInterfaceCaller(useaction, false, false, "OnEvents"); + } + } + } + + protected string swapvalues(string input, Dictionary values) + { + foreach(KeyValuePair pair in values) + { + input = input.Replace("["+pair.Key+"]", pair.Value); + } + return input; + } + + protected List GetAvPos(string avataruuid) + { + if (UUID.TryParse(avataruuid, out UUID avUUID) == false) + { + return new List() { -1, -1, -1, -1 }; + } + foreach (Avatar A in GetClient().Network.CurrentSim.ObjectsAvatars.Copy().Values) + { + if (A.ID != avUUID) + { + continue; + } + Vector3 avpos = A.Position; + int dist = (int)Math.Round(Vector3.Distance(avpos, GetClient().Self.SimPosition)); + return new List() { (int)Math.Round(A.Position.X), (int)Math.Round(A.Position.Y), (int)Math.Round(A.Position.Z), dist }; + } + return new List() { -1, -1, -1, -1 }; + } + + protected string GetAvParcel(string avataruuid) + { + if (UUID.TryParse(avataruuid, out UUID avUUID) == false) + { + return "?"; + } + foreach (Avatar A in GetClient().Network.CurrentSim.ObjectsAvatars.Copy().Values) + { + if(A.ID != avUUID) + { + continue; + } + int localid = GetClient().Parcels.GetParcelLocalID(GetClient().Network.CurrentSim, A.Position); + if (GetClient().Network.CurrentSim.Parcels.ContainsKey(localid) == false) + { + return "?"; + } + return GetClient().Network.CurrentSim.Parcels[localid].Name; + } + return "?"; + } + + protected string GetBotParcel() + { + int localid = GetClient().Parcels.GetParcelLocalID(GetClient().Network.CurrentSim, GetClient().Self.SimPosition); + if (GetClient().Network.CurrentSim.Parcels.ContainsKey(localid) == false) + { + return "-"; + } + return GetClient().Network.CurrentSim.Parcels[localid].Name; + } + + string avatarhash = ""; + bool GuestListLoaded = false; + protected List AvatarsOnSim = new List(); + protected void TrackAvatarsOnParcel() + { + long dif = SecondbotHelpers.UnixTimeNow() - lastAvUpdate; + if (dif < 30) + { + // only check for changes every 30 secs + return; + } + lastAvUpdate = SecondbotHelpers.UnixTimeNow(); + 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) + { + // no changes + 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) + { + foreach (UUID a in tracked) + { + TriggerEvent("GuestLeaves", new Dictionary() { { "avataruuid", a.ToString() } }); + } + } + if (joined.Count > 0) + { + foreach (UUID a in joined) + { + TriggerEvent("GuestJoins", new Dictionary() { { "avataruuid", a.ToString() } }); + } + } + } + } + AvatarsOnSim = avs; + GuestListLoaded = true; + } + + long lastClockEvent = 0; + protected void ClockEvent() + { + long dif = SecondbotHelpers.UnixTimeNow() - lastClockEvent; + if (dif < 60) + { + return; + } + lastClockEvent = SecondbotHelpers.UnixTimeNow(); + TriggerEvent("Clock", new Dictionary()); + } + + long lastAvUpdate = 0; + protected void TimedEvents() + { + TrackAvatarsOnParcel(); + CleanLockouts(); + ClockEvent(); + } + + public override string Status() + { + if (myConfig == null) + { + return "No Config"; + } + else if (myConfig.GetEnabled() == false) + { + return "- Not requested -"; + } + if (botConnected == true) + { + TimedEvents(); + } + if (myConfig.GetHideStatusOutput() == true) + { + return "hidden"; + } + else if (botConnected == false) + { + return "Waiting for bot"; + } + return "Active"; + } + + protected void BotLoggedIn(object o, SimConnectedEventArgs e) + { + GetClient().Network.SimConnected -= BotLoggedIn; + botConnected = true; + LogFormater.Info("OnEvent Service [Active]"); + AttachEvents(); + } + + public override void Start() + { + if (myConfig.GetEnabled() == false) + { + LogFormater.Info("OnEvent Service [- Not requested -]"); + return; + } + Stop(); + running = true; + master.BotClientNoticeEvent += BotClientRestart; + LogFormater.Info("OnEvent Service [Starting]"); + } + + public override void Stop() + { + if (running == true) + { + LogFormater.Info("OnEvent Service [Stopping]"); + } + running = false; + if (myConfig.GetEnabled() == false) + { + return; + } + master.BotClientNoticeEvent -= BotClientRestart; + RemoveEvents(); + } + } + + public class CustomOnEvent + { + public string Source = ""; + public List MonitorFlags = new List(); + public List WhereChecksLeft = new List(); + public List WhereChecksCenter = new List(); + public List WhereChecksRight = new List(); + public List Actions = new List(); + } +} From f761eacbe95f41b498efe28008cd1cbc42ea3552 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Fri, 28 Jun 2024 23:15:07 +0100 Subject: [PATCH 02/17] wip --- .../Services/TriggerOnEventService.cs | 172 ++++++++++++++++-- 1 file changed, 155 insertions(+), 17 deletions(-) diff --git a/SecondBotEvents/Services/TriggerOnEventService.cs b/SecondBotEvents/Services/TriggerOnEventService.cs index 4014f61..68de26d 100644 --- a/SecondBotEvents/Services/TriggerOnEventService.cs +++ b/SecondBotEvents/Services/TriggerOnEventService.cs @@ -1,8 +1,11 @@ using OpenMetaverse; +using OpenMetaverse.Rendering; using SecondBotEvents.Config; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Reflection.Metadata.Ecma335; namespace SecondBotEvents.Services { @@ -128,6 +131,7 @@ namespace SecondBotEvents.Services if (GetClient() != null) { GetClient().Self.IM -= BotImMessage; + GetClient().Groups.GroupMembersReply -= BotGroupMembers; } } } @@ -135,6 +139,125 @@ namespace SecondBotEvents.Services protected void AttachEvents() { GetClient().Self.IM += BotImMessage; + GetClient().Groups.GroupMembersReply += BotGroupMembers; + GetClient().Groups.CurrentGroups += BotGroupsCurrent; + GetClient().Groups.RequestCurrentGroups(); + } + + protected void BotGroupsCurrent(object o, CurrentGroupsEventArgs e) + { + lock (GroupMembership) lock (GroupMembershipUpdated) lock(GroupNames) + { + foreach(Group G in e.Groups.Values) + { + if (GroupNames.ContainsKey(G.ID) == true) + { + continue; + } + GroupNames.Add(G.ID, G.Name); + GroupMembership.Add(G.ID, new List()); + GroupMembershipUpdated.Add(G.ID, 0); + } + } + } + + protected Dictionary> GroupMembership = new Dictionary>(); + protected Dictionary GroupNames = new Dictionary(); + protected Dictionary GroupMembershipUpdated = new Dictionary(); + protected long lastGroupMembershipUpdate = 0; + // request group membership updates max of once per 60 secs + // request membership update for group once every 15 mins + protected void GroupMembershipUpkeep() + { + lock (GroupMembershipUpdated) + { + long dif = SecondbotHelpers.UnixTimeNow() - lastGroupMembershipUpdate; + if (dif < 60) + { + return; + } + UUID updateGroup = UUID.Zero; + foreach (KeyValuePair entry in GroupMembershipUpdated) + { + dif = SecondbotHelpers.UnixTimeNow() - entry.Value; + if (dif > (15 * 60)) + { + updateGroup = entry.Key; + break; + } + } + if (updateGroup != UUID.Zero) + { + lastGroupMembershipUpdate = SecondbotHelpers.UnixTimeNow(); + GroupMembershipUpdated[updateGroup] = SecondbotHelpers.UnixTimeNow(); + GetClient().Groups.RequestGroupMembers(updateGroup); + } + } + } + + protected void BotGroupMembers(object sender, GroupMembersReplyEventArgs e) + { + lock (GroupMembership) lock(GroupMembershipUpdated) + { + bool GroupLoaded = false; + if (GroupMembership.ContainsKey(e.GroupID) == true) + { + if (GroupMembership[e.GroupID].Count > 0) + { + GroupLoaded = true; + } + } + if (GroupLoaded == false) + { + foreach (GroupMember a in e.Members.Values) + { + GroupMembership[e.GroupID].Add(a.ID); + } + return; + } + List joined = new List(); + List tracked = new List(); + foreach (UUID a in GroupMembership[e.GroupID]) + { + 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); + + } + string groupname = "none"; + if(GroupNames.ContainsKey(e.GroupID) == true) + { + groupname = GroupNames[e.GroupID]; + } + foreach (UUID a in tracked) + { + // leave + GroupMembership[e.GroupID].Remove(a); + TriggerEvent("GroupMemberLeave", new Dictionary() { + { "groupuuid", e.GroupID.ToString()}, + { "groupname", groupname }, + { "avataruuid", a.ToString() } + }); + } + foreach (UUID a in joined) + { + // join + GroupMembership[e.GroupID].Add(a); + TriggerEvent("GroupMemberJoin", new Dictionary() { + { "groupuuid", e.GroupID.ToString()}, + { "groupname", groupname }, + { "avataruuid", a.ToString() } + }); + } + } } protected string GetAvName(string avataruuid) @@ -224,26 +347,40 @@ namespace SecondBotEvents.Services { avataruuid = args["avataruuid"]; } - Dictionary values = new Dictionary(); - values.Add("eventype", eventName); - values.Add("avatarname", GetAvName(avataruuid)); - values.Add("avatarparcel", GetAvParcel(avataruuid)); - values.Add("botsim", GetClient().Network.CurrentSim.Name); - values.Add("botparcel", GetBotParcel()); + string groupuuid = "none"; + string groupname = "none"; + if (args.ContainsKey("groupuuid") == true) + { + groupuuid = args["groupuuid"]; + } + if (args.ContainsKey("groupname") == true) + { + groupname = args["groupname"]; + } List AvPos = GetAvPos(avataruuid); - values.Add("avatarx", AvPos[0].ToString()); - values.Add("avatary", AvPos[1].ToString()); - values.Add("avatarz", AvPos[2].ToString()); - values.Add("avatardistance", AvPos[3].ToString()); Vector3 A = GetClient().Self.SimPosition; List BotPos = new List() { (int)Math.Round(A.X), (int)Math.Round(A.Y), (int)Math.Round(A.Z) }; - values.Add("botx", AvPos[0].ToString()); - values.Add("boty", AvPos[1].ToString()); - values.Add("botz", AvPos[2].ToString()); - values.Add("clockhour", DateTime.Now.ToString("HH")); - values.Add("clockmin", DateTime.Now.ToString("mm")); - values.Add("dayofweek", ((int)DateTime.Now.DayOfWeek).ToString()); - + Dictionary values = new Dictionary + { + { "eventype", eventName }, + { "groupuuid", groupuuid }, + { "groupname", groupname }, + { "avatarname", GetAvName(avataruuid) }, + { "avatarparcel", GetAvParcel(avataruuid) }, + { "botsim", GetClient().Network.CurrentSim.Name }, + { "botparcel", GetBotParcel() }, + { "avatarx", AvPos[0].ToString() }, + { "avatary", AvPos[1].ToString() }, + { "avatarz", AvPos[2].ToString() }, + { "avatardistance", AvPos[3].ToString() }, + { "botx", AvPos[0].ToString() }, + { "boty", AvPos[1].ToString() }, + { "botz", AvPos[2].ToString() }, + { "clockhour", DateTime.Now.ToString("HH") }, + { "clockmin", DateTime.Now.ToString("mm") }, + { "dayofweek", ((int)DateTime.Now.DayOfWeek).ToString() } + }; + if (avataruuid == null) { @@ -474,6 +611,7 @@ namespace SecondBotEvents.Services TrackAvatarsOnParcel(); CleanLockouts(); ClockEvent(); + GroupMembershipUpkeep(); } public override string Status() From 82db7e54a4b82eb3116c32611940171997c9e2bb Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Sun, 30 Jun 2024 01:01:56 +0100 Subject: [PATCH 03/17] fix issues with json configs --- SecondBotEvents/Config/OnEventConfig.cs | 28 ---------------------- SecondBotEvents/Config/RelayConfig.cs | 10 -------- SecondBotEvents/Config/config.cs | 31 ++++++++++++++----------- 3 files changed, 18 insertions(+), 51 deletions(-) diff --git a/SecondBotEvents/Config/OnEventConfig.cs b/SecondBotEvents/Config/OnEventConfig.cs index ee6c89d..775a6dd 100644 --- a/SecondBotEvents/Config/OnEventConfig.cs +++ b/SecondBotEvents/Config/OnEventConfig.cs @@ -14,35 +14,7 @@ namespace SecondBotEvents.Config filename = "onevent"; settings.Add("Enabled"); settings.Add("Count"); - int loop = 1; - while (loop <= GetCount()) - { - settings.Add("Event" + loop.ToString() + "Enabled"); - if(GetEventEnabled(loop) == false) - { - loop++; - continue; - } - settings.Add("Event" + loop.ToString() + "Source"); - settings.Add("Event" + loop.ToString() + "Monitor"); - settings.Add("Event" + loop.ToString() + "WhereCount"); - int loop2 = 1; - while (loop2 <= GetWhereCount(loop)) - { - settings.Add("Event" + loop.ToString() + "Where" + loop2.ToString()); - loop2++; - } - settings.Add("Event" + loop.ToString() + "ActionCount"); - loop2 = 1; - while (loop2 <= GetActionCount(loop)) - { - settings.Add("Event" + loop.ToString() + "Action" + loop2.ToString()); - loop2++; - } - loop++; - } settings.Add("HideStatusOutput"); - return; } public void unloadEvents() diff --git a/SecondBotEvents/Config/RelayConfig.cs b/SecondBotEvents/Config/RelayConfig.cs index 7a6d390..0202f03 100644 --- a/SecondBotEvents/Config/RelayConfig.cs +++ b/SecondBotEvents/Config/RelayConfig.cs @@ -13,16 +13,6 @@ namespace SecondBotEvents.Config filename = "relay"; settings.Add("count"); settings.Add("HideStatusOutput"); - int loop = 1; - while(loop <= GetRelayCount()) - { - settings.Add(loop.ToString() + "_enabled"); - settings.Add(loop.ToString() + "_source_type"); - settings.Add(loop.ToString() + "_source_option"); - settings.Add(loop.ToString() + "_target_type"); - settings.Add(loop.ToString() + "_target_option"); - loop++; - } } public int GetRelayCount() diff --git a/SecondBotEvents/Config/config.cs b/SecondBotEvents/Config/config.cs index 4825d33..119e502 100644 --- a/SecondBotEvents/Config/config.cs +++ b/SecondBotEvents/Config/config.cs @@ -79,22 +79,26 @@ namespace SecondBotEvents.Config MakeSettingsFile(fromFolder); return; } - JObject result = JObject.Parse(IO.ReadFile(readfile)); - foreach (string setting in settings) + try { - if(result.ContainsKey(setting) == false) + JObject result = JObject.Parse(IO.ReadFile(readfile)); + foreach (var x in result) { - continue; + settings.Add(x.Key); + string value = x.Value.ToString(); + if (SecondbotHelpers.notempty(value) == false) + { + mysettings.Add(x.Key, ""); + continue; + } + mysettings.Add(x.Key, value); } - string value = result[setting].ToString(); - if (SecondbotHelpers.notempty(value) == false) - { - mysettings.Add(setting, ""); - continue; - } - mysettings.Add(setting, value); + loaded = true; + } + catch (Exception ex) + { + LogFormater.Warn("Json format for " + readfile + " is broken: " + ex.Message); } - loaded = true; } protected void LoadSettingsFromEnv() @@ -152,7 +156,8 @@ namespace SecondBotEvents.Config protected int ReadSettingAsInt(string key, int defaultValue = 30) { - bool result = int.TryParse(ReadSettingAsString(key, defaultValue.ToString()), out int value); + string read = ReadSettingAsString(key, defaultValue.ToString()); + bool result = int.TryParse(read, out int value); if (result == false) { return defaultValue; From 7856262b9dd0ce8dbb39fbf6ecc4001464c41b68 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Sun, 30 Jun 2024 01:02:10 +0100 Subject: [PATCH 04/17] first working version of OnEvents --- SecondBotEvents/EventsSecondBot.cs | 3 + .../Services/TriggerOnEventService.cs | 183 +++++++++++++++--- 2 files changed, 164 insertions(+), 22 deletions(-) diff --git a/SecondBotEvents/EventsSecondBot.cs b/SecondBotEvents/EventsSecondBot.cs index ca60329..9743909 100644 --- a/SecondBotEvents/EventsSecondBot.cs +++ b/SecondBotEvents/EventsSecondBot.cs @@ -42,6 +42,8 @@ namespace SecondBotEvents public EventsService EventsService { get { return (EventsService)GetService("EventsService"); } } public DialogService DialogService { get { return (DialogService)GetService("DialogService"); } } + public TriggerOnEventService TriggerOnEventService { get { return (TriggerOnEventService)GetService("TriggerOnEventService"); } } + public CurrentOutfitFolder CurrentOutfitFolder { get { return (CurrentOutfitFolder)GetService("CurrentOutfitFolder"); } } public RLVService RLV { get { return (RLVService)GetService("RLVService"); } } @@ -161,6 +163,7 @@ namespace SecondBotEvents RegisterService("EventsService"); RegisterService("DialogService"); RegisterService("CustomCommandsService"); + RegisterService("TriggerOnEventService"); if (BotClient.IsLoaded() == false) { LogFormater.Info("Config is not loaded :("); diff --git a/SecondBotEvents/Services/TriggerOnEventService.cs b/SecondBotEvents/Services/TriggerOnEventService.cs index 68de26d..90cc596 100644 --- a/SecondBotEvents/Services/TriggerOnEventService.cs +++ b/SecondBotEvents/Services/TriggerOnEventService.cs @@ -1,6 +1,7 @@ using OpenMetaverse; using OpenMetaverse.Rendering; using SecondBotEvents.Config; +using Swan.Logging; using System; using System.Collections.Generic; using System.Diagnostics; @@ -15,24 +16,31 @@ namespace SecondBotEvents.Services protected bool botConnected = false; Dictionary> MyCustomEvents = new Dictionary>(); Dictionary lockouts = new Dictionary(); + List trackEventGroups = new List(); public TriggerOnEventService(EventsSecondBot setMaster) : base(setMaster) { myConfig = new OnEventConfig(master.fromEnv, master.fromFolder); int loop = 1; string[] delimiterChars = new string[] { "{IS}", "{NOT}", "{IS_UUD}", "{MISSING}", "{CONTAINS}", "{IN_GROUP}", "{NOT_IN_GROUP}", "{LESSTHAN}", "{MORETHAN}", "{LOCKOUT}" }; - while (loop < myConfig.GetCount()) + if(myConfig.GetCount() == 0) + { + myConfig.setEnabled(false); + LogFormater.Info("OnEvent Service - No events enabled stopping"); + } + while (loop <= myConfig.GetCount()) { if(myConfig.GetEventEnabled(loop) == false) { + LogFormater.Info("OnEvent Service - Event "+loop.ToString()+" is not enabled"); loop++; continue; } CustomOnEvent Event = new CustomOnEvent(); Event.Source = myConfig.GetSource(loop); - Event.MonitorFlags = myConfig.GetSourceMonitor(loop).Split(',').ToList(); + Event.MonitorFlags = myConfig.GetSourceMonitor(loop).Split("=#=").ToList(); bool eventWhereOk = true; int loop2 = 1; - while(loop2 < myConfig.GetWhereCount(loop)) + while(loop2 <= myConfig.GetWhereCount(loop)) { string check = myConfig.GetWhereCheck(loop, loop2); foreach (string delimiterChar in delimiterChars) @@ -59,16 +67,72 @@ namespace SecondBotEvents.Services } loop2++; } - if(eventWhereOk == false) + if (eventWhereOk == false) { + LogFormater.Info("OnEvent Service - Event " + loop.ToString() + " failed where config checks"); + loop++; continue; } + Event.Source = myConfig.GetSource(loop); + Event.MonitorFlags = myConfig.GetSourceMonitor(loop).Split("=#=").ToList(); + if ((Event.Source == "GroupMemberJoin") || (Event.Source == "GroupMemberLeave")) + { + UUID groupUUID = UUID.Zero; + if (Event.MonitorFlags.Count != 1) + { + LogFormater.Info("OnEvent Service - Event " + loop.ToString() + " GroupMember monitor flags not vaild"); + loop++; + continue; + } + if (UUID.TryParse(Event.MonitorFlags[0], out groupUUID) == false) + { + LogFormater.Info("OnEvent Service - Event " + loop.ToString() + " GroupMember monitor flags not vaild"); + loop++; + continue; + } + if (trackEventGroups.Contains(groupUUID) == false) + { + trackEventGroups.Add(groupUUID); + } + } + else if ((Event.Source == "GuestJoins") || (Event.Source == "GuestLeaves")) + { + if(Event.MonitorFlags.Count != 2) + { + LogFormater.Info("OnEvent Service - Event " + loop.ToString() + " Guest monitor flags not vaild"); + loop++; + continue; + } + } + else if (Event.Source == "AvatarIm") + { + if (Event.MonitorFlags.Count != 1) + { + LogFormater.Info("OnEvent Service - Event " + loop.ToString() + " AvatarIm monitor flags not vaild"); + loop++; + continue; + } + UUID testUUID = UUID.Zero; + UUID.TryParse(Event.MonitorFlags[0],out testUUID); + if ((Event.MonitorFlags[0] != "Any") && (testUUID != UUID.Zero)) + { + LogFormater.Info("OnEvent Service - Event " + loop.ToString() + " AvatarIm monitor flags not vaild"); + loop++; + continue; + } + } loop2 = 1; - while (loop2 < myConfig.GetActionCount(loop)) + while (loop2 <= myConfig.GetActionCount(loop)) { Event.Actions.Add(myConfig.GetActionStep(loop, loop2)); loop2++; } + if(Event.Actions.Count == 0) + { + LogFormater.Info("OnEvent Service - Event " + loop.ToString() + " Actions are not setup"); + loop++; + continue; + } if(MyCustomEvents.ContainsKey(Event.Source) == false) { MyCustomEvents.Add(Event.Source, new List()); @@ -77,8 +141,14 @@ namespace SecondBotEvents.Services loop++; } myConfig.unloadEvents(); // remove unneeded copy of events from the config as we wont be using it + if (MyCustomEvents.Count == 0) + { + myConfig.setEnabled(false); + LogFormater.Info("OnEvent Service - failed to load any events stopping"); + } } + protected void BotClientRestart(object o, BotClientNotice e) { botConnected = false; @@ -132,6 +202,10 @@ namespace SecondBotEvents.Services { GetClient().Self.IM -= BotImMessage; GetClient().Groups.GroupMembersReply -= BotGroupMembers; + GetClient().Groups.CurrentGroups -= BotGroupsCurrent; + GetClient().Network.SimChanged -= BotChangedSim; + GetClient().Self.MoneyBalance -= BotFundsEvent; + GetClient().Self.AlertMessage -= BotAlertMessage; } } } @@ -141,7 +215,25 @@ namespace SecondBotEvents.Services GetClient().Self.IM += BotImMessage; GetClient().Groups.GroupMembersReply += BotGroupMembers; GetClient().Groups.CurrentGroups += BotGroupsCurrent; + GetClient().Network.SimChanged += BotChangedSim; + GetClient().Self.MoneyBalance += BotFundsEvent; + GetClient().Self.AlertMessage += BotAlertMessage; GetClient().Groups.RequestCurrentGroups(); + GetClient().Self.RequestBalance(); + } + + protected void BotAlertMessage(object o, AlertMessageEventArgs e) + { + TriggerEvent("SimAlert", new Dictionary() { + { "alertmessage", e.Message}, + }); + } + + protected void BotFundsEvent(object o, BalanceEventArgs e) + { + TriggerEvent("BalanceUpdate", new Dictionary() { + { "funds", e.Balance.ToString()}, + }); } protected void BotGroupsCurrent(object o, CurrentGroupsEventArgs e) @@ -150,6 +242,10 @@ namespace SecondBotEvents.Services { foreach(Group G in e.Groups.Values) { + if (trackEventGroups.Contains(G.ID) == false) + { + return; + } if (GroupNames.ContainsKey(G.ID) == true) { continue; @@ -197,6 +293,10 @@ namespace SecondBotEvents.Services protected void BotGroupMembers(object sender, GroupMembersReplyEventArgs e) { + if(trackEventGroups.Contains(e.GroupID) == false) + { + return; + } lock (GroupMembership) lock(GroupMembershipUpdated) { bool GroupLoaded = false; @@ -335,36 +435,49 @@ namespace SecondBotEvents.Services } } } + protected void BotChangedSim(object sender, SimChangedEventArgs e) + { + TriggerEvent("ChangeSim", new Dictionary() + { + { "oldsimname", e.PreviousSimulator.Name }, + { "newsimname", GetClient().Network.CurrentSim.Name }, + }); + } + protected string inArgsOrDefault(string arg, Dictionary args, string defaultvalue) + { + if (args.ContainsKey(arg) == true) + { + return args[arg]; + } + return defaultvalue; + } protected void TriggerEvent(string eventName, Dictionary args) { if (MyCustomEvents.ContainsKey(eventName) == false) { return; } - string avataruuid = null; - if (args.ContainsKey("avataruuid") == true) - { - avataruuid = args["avataruuid"]; - } - string groupuuid = "none"; - string groupname = "none"; - if (args.ContainsKey("groupuuid") == true) - { - groupuuid = args["groupuuid"]; - } - if (args.ContainsKey("groupname") == true) - { - groupname = args["groupname"]; - } + string avataruuid = inArgsOrDefault("avataruuid", args, null); + string groupuuid = inArgsOrDefault("groupuuid", args, "none"); + string groupname = inArgsOrDefault("groupname", args, "none"); + string funds = inArgsOrDefault("funds", args, "-1"); + string alertmessage = inArgsOrDefault("alertmessage", args, "none"); + string oldsimname = inArgsOrDefault("oldsimname", args, "none"); + string newsimname = inArgsOrDefault("newsimname", args, "none"); + List AvPos = GetAvPos(avataruuid); Vector3 A = GetClient().Self.SimPosition; List BotPos = new List() { (int)Math.Round(A.X), (int)Math.Round(A.Y), (int)Math.Round(A.Z) }; Dictionary values = new Dictionary { + { "alertmessage", alertmessage }, + { "funds", funds }, { "eventype", eventName }, { "groupuuid", groupuuid }, { "groupname", groupname }, + { "oldsimname", oldsimname }, + { "newsimname", newsimname }, { "avatarname", GetAvName(avataruuid) }, { "avatarparcel", GetAvParcel(avataruuid) }, { "botsim", GetClient().Network.CurrentSim.Name }, @@ -394,6 +507,24 @@ namespace SecondBotEvents.Services foreach (CustomOnEvent E in MyCustomEvents[eventName]) { bool canFireEvent = true; + if ((E.Source == "GroupMemberJoin") || (E.Source == "GroupMemberLeave")) + { + if (E.MonitorFlags[0] != values["groupuuid"]) + { + continue; + } + } + else if ((E.Source == "GuestJoins") || (E.Source == "GuestLeaves")) + { + if ( + (E.MonitorFlags[0] != values["botsim"]) || + (E.MonitorFlags[1] != values["botparcel"]) || + (E.MonitorFlags[1] != values["avatarparcel"]) + ) + { + continue; + } + } int loop = 0; while(loop < E.WhereChecksLeft.Count()) { @@ -415,8 +546,16 @@ namespace SecondBotEvents.Services bool rightIsUUID = UUID.TryParse(right, out rightAsUUID); bool leftIsInGroup = false; bool leftIsLockedout = IsLockedout(left); - bool leftIsEven = (leftAsInt % 2 == 0); - bool leftIsDivs = (leftAsInt % rightAsInt == 0); + bool leftIsEven = true; + bool leftIsDivs = true; + if (leftAsInt != 0) + { + leftIsEven = ((leftAsInt % 2) == 0); + if(rightAsInt != 0) + { + leftIsDivs = ((leftAsInt % rightAsInt) == 0); + } + } if ((leftIsUUID == true) && (rightIsUUID == true)) { leftIsInGroup = master.DataStoreService.IsGroupMember(rightAsUUID, leftAsUUID); From c68dfc20d0d5047d2136c862fa5345957b1131db Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Sun, 30 Jun 2024 02:09:31 +0100 Subject: [PATCH 05/17] expose the AddAvatar function so other systems can add --- SecondBotEvents/Services/DataStoreService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SecondBotEvents/Services/DataStoreService.cs b/SecondBotEvents/Services/DataStoreService.cs index 62bc1be..79cf00c 100644 --- a/SecondBotEvents/Services/DataStoreService.cs +++ b/SecondBotEvents/Services/DataStoreService.cs @@ -976,7 +976,7 @@ namespace SecondBotEvents.Services GetClient().Groups.RequestCurrentGroups(); } - protected void AddAvatar(UUID id, string name) + public void AddAvatar(UUID id, string name) { lock (avatarsName2Key) lock (avatarLastUsed) { From 38338da2191dae647269cd09a2f61a3f8e42b4f2 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Sun, 30 Jun 2024 02:09:45 +0100 Subject: [PATCH 06/17] add AddAvatar triggers --- SecondBotEvents/Services/CommandsService.cs | 1 + SecondBotEvents/Services/InteractionService.cs | 2 ++ SecondBotEvents/Services/TriggerOnEventService.cs | 2 ++ 3 files changed, 5 insertions(+) diff --git a/SecondBotEvents/Services/CommandsService.cs b/SecondBotEvents/Services/CommandsService.cs index 936cfce..e08bafa 100644 --- a/SecondBotEvents/Services/CommandsService.cs +++ b/SecondBotEvents/Services/CommandsService.cs @@ -153,6 +153,7 @@ namespace SecondBotEvents.Services { break; } + master.DataStoreService.AddAvatar(e.IM.FromAgentID, e.IM.FromAgentName); requireSigning = false; acceptMessage = myConfig.GetMastersCSV().Contains(e.IM.FromAgentName); break; diff --git a/SecondBotEvents/Services/InteractionService.cs b/SecondBotEvents/Services/InteractionService.cs index dcd26d2..21833b2 100644 --- a/SecondBotEvents/Services/InteractionService.cs +++ b/SecondBotEvents/Services/InteractionService.cs @@ -196,6 +196,7 @@ namespace SecondBotEvents.Services }; if(e.FromTask == false) { + master.DataStoreService.AddAvatar(e.Offer.FromAgentID, e.Offer.FromAgentName); details.Add("itemuuid", e.ObjectID.ToString()); details.Add("itemname", "?"); InventoryItem itm = GetClient().Inventory.FetchItem(e.ObjectID, GetClient().Self.AgentID, 2000); @@ -213,6 +214,7 @@ namespace SecondBotEvents.Services { return; } + master.DataStoreService.AddAvatar(e.AgentID, e.AgentName); GetClient().Friends.AcceptFriendship(e.AgentID, e.SessionID); JsonOuputCleaner(e.AgentName, "FriendRequest"); diff --git a/SecondBotEvents/Services/TriggerOnEventService.cs b/SecondBotEvents/Services/TriggerOnEventService.cs index 90cc596..164c467 100644 --- a/SecondBotEvents/Services/TriggerOnEventService.cs +++ b/SecondBotEvents/Services/TriggerOnEventService.cs @@ -179,6 +179,7 @@ namespace SecondBotEvents.Services { break; } + master.DataStoreService.AddAvatar(e.IM.FromAgentID, e.IM.FromAgentName); // trigger avatar IM TriggerEvent("AvatarIm", new Dictionary() { { "message", e.IM.Message} , @@ -683,6 +684,7 @@ namespace SecondBotEvents.Services foreach (Avatar A in GetClient().Network.CurrentSim.ObjectsAvatars.Copy().Values) { avs.Add(A.ID); + master.DataStoreService.AddAvatar(A.ID, A.Name); hashstring = hashstring + A.ID.ToString(); } string hash = SecondbotHelpers.GetSHA1(hashstring); From 973fdb56b064068695f7a8522a4ef5b2c7579dd8 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Sun, 30 Jun 2024 13:02:18 +0100 Subject: [PATCH 07/17] tidy up the event values code --- .../Services/TriggerOnEventService.cs | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/SecondBotEvents/Services/TriggerOnEventService.cs b/SecondBotEvents/Services/TriggerOnEventService.cs index 164c467..6295c16 100644 --- a/SecondBotEvents/Services/TriggerOnEventService.cs +++ b/SecondBotEvents/Services/TriggerOnEventService.cs @@ -460,25 +460,21 @@ namespace SecondBotEvents.Services return; } string avataruuid = inArgsOrDefault("avataruuid", args, null); - string groupuuid = inArgsOrDefault("groupuuid", args, "none"); - string groupname = inArgsOrDefault("groupname", args, "none"); - string funds = inArgsOrDefault("funds", args, "-1"); - string alertmessage = inArgsOrDefault("alertmessage", args, "none"); - string oldsimname = inArgsOrDefault("oldsimname", args, "none"); - string newsimname = inArgsOrDefault("newsimname", args, "none"); List AvPos = GetAvPos(avataruuid); Vector3 A = GetClient().Self.SimPosition; List BotPos = new List() { (int)Math.Round(A.X), (int)Math.Round(A.Y), (int)Math.Round(A.Z) }; Dictionary values = new Dictionary { - { "alertmessage", alertmessage }, - { "funds", funds }, + { "alertmessage", inArgsOrDefault("alertmessage", args, "none") }, + { "message", inArgsOrDefault("message", args, "none") }, + { "funds", inArgsOrDefault("funds", args, "-1") }, { "eventype", eventName }, - { "groupuuid", groupuuid }, - { "groupname", groupname }, - { "oldsimname", oldsimname }, - { "newsimname", newsimname }, + { "groupuuid", inArgsOrDefault("groupuuid", args, "none") }, + { "groupname", inArgsOrDefault("groupname", args, "none") }, + { "oldsimname", inArgsOrDefault("oldsimname", args, "none") }, + { "newsimname", inArgsOrDefault("newsimname", args, "none") }, + { "avataruuid", avataruuid }, { "avatarname", GetAvName(avataruuid) }, { "avatarparcel", GetAvParcel(avataruuid) }, { "botsim", GetClient().Network.CurrentSim.Name }, @@ -495,16 +491,6 @@ namespace SecondBotEvents.Services { "dayofweek", ((int)DateTime.Now.DayOfWeek).ToString() } }; - - if (avataruuid == null) - { - avataruuid = "none"; - } - if(args.ContainsKey("message") == false) - { - args["message"] = "none"; - } - values.Add("avataruuid", avataruuid); foreach (CustomOnEvent E in MyCustomEvents[eventName]) { bool canFireEvent = true; @@ -527,7 +513,7 @@ namespace SecondBotEvents.Services } } int loop = 0; - while(loop < E.WhereChecksLeft.Count()) + while(loop < E.WhereChecksLeft.Count) { string left = swapvalues(E.WhereChecksLeft[loop],values); string center = E.WhereChecksCenter[loop]; From 3a83f39adaa5c6d79194ed465343fc4ca4d61f43 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Sun, 30 Jun 2024 13:02:29 +0100 Subject: [PATCH 08/17] enable debug for testing --- LibreMetaverse/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibreMetaverse/Settings.cs b/LibreMetaverse/Settings.cs index 2bcdc62..024c1cc 100644 --- a/LibreMetaverse/Settings.cs +++ b/LibreMetaverse/Settings.cs @@ -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.Debug; /// Attach avatar names to log messages public bool LOG_NAMES = true; From a5c58c2363cbd5a69f180f64a37c2c35fbfba907 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Wed, 3 Jul 2024 23:30:40 +0100 Subject: [PATCH 09/17] adjust network timeouts and ticks to be more accepting --- LibreMetaverse/Settings.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/LibreMetaverse/Settings.cs b/LibreMetaverse/Settings.cs index 024c1cc..9962794 100644 --- a/LibreMetaverse/Settings.cs +++ b/LibreMetaverse/Settings.cs @@ -106,27 +106,27 @@ namespace OpenMetaverse /// Number of milliseconds before a CAPS call will time out /// Setting this too low will cause web requests time out and /// possibly retry repeatedly - public int CAPS_TIMEOUT = 60 * 1000; + public int CAPS_TIMEOUT = 63 * 1000; /// Number of milliseconds for xml-rpc to timeout - public int LOGIN_TIMEOUT = 60 * 1000; + public int LOGIN_TIMEOUT = 63 * 1000; /// Milliseconds before a packet is assumed lost and resent public int RESEND_TIMEOUT = 4000; /// Milliseconds without receiving a packet before the /// connection to a simulator is assumed lost - public int SIMULATOR_TIMEOUT = 60 * 1000; + public int SIMULATOR_TIMEOUT = 75 * 1000; /// Milliseconds to wait for a simulator info request through /// the grid interface public int MAP_REQUEST_TIMEOUT = 5 * 1000; /// Number of milliseconds between sending pings to each sim - public const int PING_INTERVAL = 2200; + public const int PING_INTERVAL = 3000; /// Number of milliseconds between sending camera updates - public const int DEFAULT_AGENT_UPDATE_INTERVAL = 500; + public const int DEFAULT_AGENT_UPDATE_INTERVAL = 1000; /// Number of milliseconds between updating the current /// positions of moving, non-accelerating and non-colliding objects @@ -134,7 +134,7 @@ namespace OpenMetaverse /// Millisecond interval between ticks, where all ACKs are /// sent out and the age of unACKed packets is checked - public const int NETWORK_TICK_INTERVAL = 500; + public const int NETWORK_TICK_INTERVAL = 650; #endregion #region Sizes From f7dd65781fe5bc79eb9093471f6a2b0168fcbc9d Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Wed, 3 Jul 2024 23:30:55 +0100 Subject: [PATCH 10/17] enable auto recovery of bot --- SecondBotEvents/Commands/Self.cs | 1 + SecondBotEvents/Services/BotClientService.cs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/SecondBotEvents/Commands/Self.cs b/SecondBotEvents/Commands/Self.cs index b8e6841..baac4e9 100644 --- a/SecondBotEvents/Commands/Self.cs +++ b/SecondBotEvents/Commands/Self.cs @@ -145,6 +145,7 @@ namespace SecondBotEvents.Commands [ReturnHints("ok")] public object Logoff() { + master.BotClient.flagLogoutExpected(); GetClient().Network.BeginLogout(); return BasicReply("ok"); } diff --git a/SecondBotEvents/Services/BotClientService.cs b/SecondBotEvents/Services/BotClientService.cs index 46da80a..d06df79 100644 --- a/SecondBotEvents/Services/BotClientService.cs +++ b/SecondBotEvents/Services/BotClientService.cs @@ -15,6 +15,12 @@ namespace SecondBotEvents.Services public GridClient client = null; public BasicConfig basicCfg = null; + protected bool LogoutExpected = false; + public void flagLogoutExpected() + { + LogoutExpected = true; + } + protected bool ExitBot = false; protected Timer AutoRestartLoginTimer; @@ -78,6 +84,15 @@ namespace SecondBotEvents.Services protected void BotDisconnected(object o, DisconnectedEventArgs e) { LogFormater.Info("Client service ~ Network disconnected: " + e.Message); + if (LogoutExpected == false) + { + AutoRestartLoginTimer = new Timer(); + AutoRestartLoginTimer.Interval = 75 * 1000; + AutoRestartLoginTimer.AutoReset = false; + AutoRestartLoginTimer.Elapsed += RestartTimer; + LogFormater.Info("Client service ~ Unexpected disconnect (starting reconnect timer for 75s)"); + return; + } } protected void BotLoginStatus(object o, LoginProgressEventArgs e) From 5b12106301ab60e4d78e257677c6050e4362afc7 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Wed, 3 Jul 2024 23:33:14 +0100 Subject: [PATCH 11/17] Update BotClientService.cs --- SecondBotEvents/Services/BotClientService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SecondBotEvents/Services/BotClientService.cs b/SecondBotEvents/Services/BotClientService.cs index d06df79..c3809ce 100644 --- a/SecondBotEvents/Services/BotClientService.cs +++ b/SecondBotEvents/Services/BotClientService.cs @@ -178,7 +178,10 @@ namespace SecondBotEvents.Services bool isRestart = false; if (client != null) { - client.Network.Logout(); + if (client.Network != null) + { + client.Network.Logout(); + } isRestart = true; } client = null; From 5071431f26e89fb22a7e16428887cc7cbdf70632 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Thu, 4 Jul 2024 13:29:52 +0100 Subject: [PATCH 12/17] add extra checks on guest event triggers --- SecondBotEvents/Services/TriggerOnEventService.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/SecondBotEvents/Services/TriggerOnEventService.cs b/SecondBotEvents/Services/TriggerOnEventService.cs index 6295c16..cf27a9e 100644 --- a/SecondBotEvents/Services/TriggerOnEventService.cs +++ b/SecondBotEvents/Services/TriggerOnEventService.cs @@ -700,10 +700,17 @@ namespace SecondBotEvents.Services } if ((tracked.Count > 0) || (joined.Count > 0)) { + List seen = new List(); if (tracked.Count > 0) { + foreach (UUID a in tracked) { + if(seen.Contains(a) == true) + { + continue; + } + seen.Add(a); TriggerEvent("GuestLeaves", new Dictionary() { { "avataruuid", a.ToString() } }); } } @@ -711,6 +718,11 @@ namespace SecondBotEvents.Services { foreach (UUID a in joined) { + if (seen.Contains(a) == true) + { + continue; + } + seen.Add(a); TriggerEvent("GuestJoins", new Dictionary() { { "avataruuid", a.ToString() } }); } } From 68681629a84fbbf2b6bfd4c78dd014265316be24 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Thu, 4 Jul 2024 13:30:09 +0100 Subject: [PATCH 13/17] adjust command logging so it should only log the results --- SecondBotEvents/Services/CommandsService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/SecondBotEvents/Services/CommandsService.cs b/SecondBotEvents/Services/CommandsService.cs index e08bafa..d429f1c 100644 --- a/SecondBotEvents/Services/CommandsService.cs +++ b/SecondBotEvents/Services/CommandsService.cs @@ -416,11 +416,9 @@ namespace SecondBotEvents.Services if (requireSigning == false) { accepted = true; // just accept the command - master.CommandNotice(command, source, String.Join("@@@", args), accepted); return; } Vaildate(requireTimewindow, windowSize, secret); - master.CommandNotice(command, source, String.Join("@@@", args), accepted); } public SignedCommand(CommandsService setMaster, string source, string setCommand, string setSigningCode, string[] setArgs, From 73239fc40825584447482d55f2862a2b1c422ee2 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:06:02 +0100 Subject: [PATCH 14/17] patch json decode to return null if something goes wrong --- LibreMetaverse.StructuredData/JSON/OSDJson.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/LibreMetaverse.StructuredData/JSON/OSDJson.cs b/LibreMetaverse.StructuredData/JSON/OSDJson.cs index d3ec21a..0ddef3a 100644 --- a/LibreMetaverse.StructuredData/JSON/OSDJson.cs +++ b/LibreMetaverse.StructuredData/JSON/OSDJson.cs @@ -20,7 +20,16 @@ namespace OpenMetaverse.StructuredData public static OSD DeserializeJson(string json) { - return DeserializeJson(JsonMapper.ToObject(json)); + try + { + JsonData A = JsonMapper.ToObject(json); + return DeserializeJson(A); + } + catch + { + return null; // something fucky happened to the input + } + } public static OSD DeserializeJson(JsonData json) From 5853a807bb55acd9dc10094ad232b9f5a2308e23 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:18:40 +0100 Subject: [PATCH 15/17] stop error messages if the json decode fails --- LibreMetaverse/InventoryManager.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/LibreMetaverse/InventoryManager.cs b/LibreMetaverse/InventoryManager.cs index 5bc8b49..65c116a 100644 --- a/LibreMetaverse/InventoryManager.cs +++ b/LibreMetaverse/InventoryManager.cs @@ -607,14 +607,17 @@ namespace OpenMetaverse try { OSD result = OSDParser.Deserialize(data); - OSDMap res = (OSDMap)result; - OSDArray itemsOSD = (OSDArray)res["items"]; - - foreach (var it in itemsOSD) + if (result != null) { - InventoryItem item = InventoryItem.FromOSD(it); - _Store[item.UUID] = item; - OnItemReceived(new ItemReceivedEventArgs(item)); + OSDMap res = (OSDMap)result; + OSDArray itemsOSD = (OSDArray)res["items"]; + + foreach (var it in itemsOSD) + { + InventoryItem item = InventoryItem.FromOSD(it); + _Store[item.UUID] = item; + OnItemReceived(new ItemReceivedEventArgs(item)); + } } } catch (Exception ex) From 173f62b390c2561e373041060311ebb235b59076 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Thu, 4 Jul 2024 20:05:16 +0100 Subject: [PATCH 16/17] extra checks when caps system fails us --- LibreMetaverse/AppearanceManager.cs | 51 ++++++++++++++++------------- LibreMetaverse/GroupManager.cs | 7 +++- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/LibreMetaverse/AppearanceManager.cs b/LibreMetaverse/AppearanceManager.cs index c660af5..54c950d 100644 --- a/LibreMetaverse/AppearanceManager.cs +++ b/LibreMetaverse/AppearanceManager.cs @@ -2091,30 +2091,37 @@ namespace OpenMetaverse // TODO: create Current Outfit Folder } - OSDMap request = new OSDMap(1) { ["cof_version"] = currentoutfitfolder.Version }; - - string msg = "Server side baking failed"; - - OSD res = null; - - await Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, request, cancellationToken, - (response, data, error) => res = OSDParser.Deserialize(data)); - - if (res is OSDMap result) + try { - if (result["success"]) - { - Logger.Log("Successfully set appearance", Helpers.LogLevel.Info, Client); - // TODO: Set local visual params and baked textures based on the result here - return true; - } - if (result.ContainsKey("error")) - { - msg += ": " + result["error"].AsString(); - } - } + OSDMap request = new OSDMap(1) { ["cof_version"] = currentoutfitfolder.Version }; - Logger.Log(msg, Helpers.LogLevel.Error, Client); + string msg = "Server side baking failed"; + + OSD res = null; + + await Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, request, cancellationToken, + (response, data, error) => res = OSDParser.Deserialize(data)); + + if (res is OSDMap result) + { + if (result["success"]) + { + Logger.Log("Successfully set appearance", Helpers.LogLevel.Info, Client); + // TODO: Set local visual params and baked textures based on the result here + return true; + } + if (result.ContainsKey("error")) + { + msg += ": " + result["error"].AsString(); + } + } + + Logger.Log(msg, Helpers.LogLevel.Error, Client); + } + catch (Exception e) + { + Logger.Log("UpdateAvatarAppearanceAsync has failed to unpack data: "+e.Message, Helpers.LogLevel.Error, Client); + } return false; } diff --git a/LibreMetaverse/GroupManager.cs b/LibreMetaverse/GroupManager.cs index ad72bfb..ea38895 100644 --- a/LibreMetaverse/GroupManager.cs +++ b/LibreMetaverse/GroupManager.cs @@ -1056,7 +1056,12 @@ namespace OpenMetaverse if (error != null) { return; } OSD result = OSDParser.Deserialize(data); - GroupMembersHandlerCaps(requestID, result); + if (result != null) + { + GroupMembersHandlerCaps(requestID, result); + return; + } + Logger.Log("Failed to json decode data from uri "+cap.AbsoluteUri+": ", Helpers.LogLevel.Error, Client); }); } else From 5e4f32b82d4c7e73bd93ec4bef74fbba0c24244b Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Thu, 4 Jul 2024 20:25:26 +0100 Subject: [PATCH 17/17] remove debug flag ready for merge --- LibreMetaverse/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibreMetaverse/Settings.cs b/LibreMetaverse/Settings.cs index 9962794..1732227 100644 --- a/LibreMetaverse/Settings.cs +++ b/LibreMetaverse/Settings.cs @@ -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.Debug; + public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.None; /// Attach avatar names to log messages public bool LOG_NAMES = true;