diff --git a/BetterSecondbot/OnEvents/onevent.cs b/BetterSecondbot/OnEvents/onevent.cs new file mode 100644 index 0000000..8d51a3d --- /dev/null +++ b/BetterSecondbot/OnEvents/onevent.cs @@ -0,0 +1,751 @@ +using BetterSecondBot; +using BetterSecondBot.bottypes; +using BetterSecondBotShared.IO; +using BetterSecondBotShared.Json; +using BetterSecondBotShared.logs; +using BetterSecondBotShared.Static; +using Newtonsoft.Json; +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace BetterSecondbot.OnEvents +{ + public class onevent + { + protected Cli controler = null; + protected StatusMessageEvent LastStatus = null; + protected int lastMinTick = 0; + protected int lastSecTick = 0; + protected bool DisableGroupEvents = true; + + protected Dictionary> group_membership_update_q = new Dictionary>(); + protected List Events = new List(); + protected Dictionary> GroupMembership = new Dictionary>(); + + protected void TriggerEvent(string trigger, Dictionary args, bool enableCronArgs = false) + { + if (controler.BotReady() == true) + { + args.Add("BotSim", controler.getBot().GetClient.Network.CurrentSim.Name); + int localp = controler.getBot().GetClient.Parcels.GetParcelLocalID(controler.getBot().GetClient.Network.CurrentSim, controler.getBot().GetClient.Self.SimPosition); + if (controler.getBot().GetClient.Network.CurrentSim.Parcels.ContainsKey(localp) == true) + { + Parcel P = controler.getBot().GetClient.Network.CurrentSim.Parcels[localp]; + args.Add("BotParcel", P.Name); + } + else + { + args.Add("BotParcel", "Unknown"); + } + foreach (OnEvent E in Events) + { + if (E.Enabled != true) + { + continue; + } + if (E.On != trigger) + { + continue; + } + if (whereChecks(E, args, enableCronArgs) == false) + { + continue; + } + actionEvents(E, args); + } + } + } + + protected void actionEvents(OnEvent E, Dictionary args) + { + foreach(string a in E.Actions) + { + string wip = UpdateBits(a, args); + string[] bits = wip.Split("|||",StringSplitOptions.None); + if(bits.Length == 2) + { + controler.getBot().CallAPI(bits[0],bits[1].Split("~#~")); + } + } + } + + protected int dayOfWeek(DayOfWeek e) + { + if (e == DayOfWeek.Monday) return 1; + else if (e == DayOfWeek.Tuesday) return 2; + else if(e == DayOfWeek.Wednesday) return 3; + else if(e == DayOfWeek.Thursday) return 4; + else if(e == DayOfWeek.Friday) return 5; + else if(e == DayOfWeek.Saturday) return 6; + return 7; + } + + public string WhyCronFailed = ""; + protected bool cronMagic(string checkString,string requestedResult) + { + string[] cronbits = checkString.Split(" "); + if (cronbits.Length != 5) + { + WhyCronFailed = checkString + " is not formated correctly"; + return false; + } + DateTime now = DateTime.Now; + int[] checkingCron = new int[] { now.Minute, now.Hour, now.Day, now.Month, dayOfWeek(now.DayOfWeek) }; + int[] lastCronValue = new int[] { 59, 23, DateTime.DaysInMonth(now.Year, now.Month), 12, 7 }; + int loop = 0; + bool cronStatus = true; + while (loop < checkingCron.Length) + { + int index = loop; + loop++; + if (cronbits[index] == "*") + { + continue; + } + else if (cronbits[index] == "L") + { + if (checkingCron[index] != lastCronValue[index]) + { + WhyCronFailed = checkString + " failed on index: " + index.ToString() + " ruleset: L check: ="; + cronStatus = false; + break; + } + } + else if (cronbits[index] == "E") + { + if ((checkingCron[index] % 2) != 0) + { + WhyCronFailed = checkString + " failed on index: " + index.ToString() + " ruleset: E check: mod2=0"; + cronStatus = false; + break; + } + } + else if (cronbits[index] == "O") + { + if ((checkingCron[index] % 2) == 0) + { + WhyCronFailed = checkString + " failed on index: " + index.ToString() + " ruleset: O check: mod2!=0"; + cronStatus = false; + break; + } + } + else if (cronbits[index].StartsWith("/") == true) + { + if (int.TryParse(cronbits[index].Replace("/", ""), out int B) == false) + { + WhyCronFailed = checkString + " failed on index: " + index.ToString() + " convert /X to int"; + cronStatus = false; + break; + } + int returnValue = (checkingCron[index] % B); + if (returnValue != 0) + { + WhyCronFailed = checkString + " failed on index: " + index.ToString() + " ruleset: / check: mod"+ B.ToString() +"= 0"; + cronStatus = false; + break; + } + } + else + { + if (int.TryParse(cronbits[index], out int B) == false) + { + WhyCronFailed = checkString + " failed on index: " + index.ToString() + " ruleset: = Failure on convert"; + cronStatus = false; + break; + } + if (B != checkingCron[index]) + { + WhyCronFailed = checkString + " failed on index: " + index.ToString() + " ruleset: = check: "+ B.ToString() + "="+ checkingCron[index].ToString(); + cronStatus = false; + break; + } + } + } + if (bool.TryParse(requestedResult, out bool expected) == false) + { + WhyCronFailed = checkString + " Unable to convert expected value "+ requestedResult; + return false; + } + if (cronStatus != expected) + { + WhyCronFailed = checkString + " is not vaild for this time" + requestedResult; + return false; + } + WhyCronFailed = checkString + " has passed ok"; + return true; + } + + protected bool whereChecks(OnEvent E, Dictionary args, bool enableCronArgs = false) + { + bool WherePassed = true; + Dictionary updateArgs = new Dictionary(); + string[] keys = args.Keys.ToArray(); + foreach(string K in keys) + { + args[K] = args[K].Trim(); + } + List WhereFilters = new List() + { + "CRON", "IN_GROUP", "NOT_IN_GROUP", + "IS", "NOT", "IS_EMPTY", "HAS", "MISSING", + "IS_UUID", "CRON" + }; + foreach (string A in E.Where) + { + if((A.Contains(" {CRON} ") == true) && (enableCronArgs == false)) + { + WherePassed = false; + break; + } + List bits = new List(); + string filter = ""; + foreach(string F in WhereFilters) + { + if (A.Contains(" {"+F+"} ") == true) + { + filter = F; + bits = A.Split(" {" + F + "} ", StringSplitOptions.None).ToList(); + break; + } + } + if(filter == "") + { + WherePassed = false; + break; + } + if(bits.Count != 2) + { + WherePassed = false; + break; + } + bits[0] = bits[0].Trim(); + bits[1] = bits[1].Trim(); + bits[0] = UpdateBits(bits[0], args); + bits[1] = UpdateBits(bits[1], args); + if (filter == "CRON") + { + if(cronMagic(bits[0], bits[1]) == false) + { + //LogFormater.Info(WhyCronFailed, true); + WherePassed = false; + break; + } + } + else if (filter == "IS") + { + if(bits[0] != bits[1]) + { + WherePassed = false; + break; + } + } + else if (filter == "NOT") + { + if (bits[0] == bits[1]) + { + WherePassed = false; + break; + } + } + else if (filter == "IS_EMPTY") + { + if(bool.TryParse(bits[1],out bool status) == false) + { + WherePassed = false; + break; + } + bool check = false; + if(bits[0].Length == 0) + { + check = true; + } + if(check != status) + { + WherePassed = false; + break; + } + } + else if (filter == "HAS") + { + if (bits[0].Contains(bits[1]) == false) + { + WherePassed = false; + break; + } + } + else if (filter == "MISSING") + { + if (bits[0].Contains(bits[1]) == true) + { + WherePassed = false; + break; + } + } + else if (filter == "IS_UUID") + { + if (bool.TryParse(bits[1], out bool resultCheck) == false) + { + WherePassed = false; + break; + } + bool isUUID = UUID.TryParse(bits[0], out UUID _); + if(resultCheck != isUUID) + { + WherePassed = false; + break; + } + } + else if((filter == "IN_GROUP") || (filter == "NOT_IN_GROUP")) + { + bool expectedStatus = true; + if (filter == "NOT_IN_GROUP") + { + expectedStatus = false; + } + if (UUID.TryParse(bits[0], out UUID avatar) == false) + { + WherePassed = false; + break; + } + if (UUID.TryParse(bits[1],out UUID group) == false) + { + WherePassed = false; + break; + } + if(GroupMembership.ContainsKey(group) == false) + { + WherePassed = false; + break; + } + bool status = GroupMembership[group].Contains(avatar); + if(status != expectedStatus) + { + WherePassed = false; + break; + } + } + } + + return WherePassed; + } + + public string UpdateBits(string bit,Dictionary args) + { + foreach(KeyValuePair A in args) + { + bit = bit.Replace("[" + A.Key + "]", A.Value); + } + return bit; + } + + + public onevent(Cli master, bool LoadFromDocker) + { + controler = master; + if (LoadFromDocker == true) + { + loadFromDockerEnv(); + } + else + { + loadFromDisk(); + } + SetupMonitor(); + attachEvents(); +#if DEBUG + testCron(); +#endif + + } + + protected void testCron() + { + string[] crontests = new string[] + { + "* * * * *", + "* * * * "+dayOfWeek(DateTime.Now.DayOfWeek).ToString(), + "* * * "+DateTime.Now.Month.ToString()+" *", + "* * "+DateTime.Now.Day.ToString()+" * *", + "* "+DateTime.Now.Hour.ToString()+" * * *", + ""+DateTime.Now.Minute.ToString()+" * * * *", + "* * * * /"+dayOfWeek(DateTime.Now.DayOfWeek).ToString(), + "* * * /"+DateTime.Now.Month.ToString()+" *", + "* * /"+DateTime.Now.Day.ToString()+" * *", + "* /"+DateTime.Now.Hour.ToString()+" * * *", + "/"+DateTime.Now.Minute.ToString()+" * * * *", + "61 25 77 44 8", + "E O E O E", + }; + bool[] expected = new bool[] + { + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + }; + int loop = 1; + foreach(string a in crontests) + { + bool result = cronMagic(a, "true"); + if (result != expected[loop - 1]) + { + LogFormater.Info("failed test \"" + a + "\" " + loop.ToString() + " " + result.ToString(), true); + } + loop++; + } + + + } + + protected void SetupMonitor() + { + string[] skipped = new string[] { "None", "" }; + foreach(OnEvent E in Events) + { + if ((E.Monitor == "None") || (E.Monitor == "")) + { + continue; + } + UUID checking = UUID.Zero; + if(UUID.TryParse(E.Monitor,out checking) == false) + { + continue; + } + if(checking == UUID.Zero) + { + continue; + } + if(group_membership_update_q.ContainsKey(checking) == true) + { + continue; + } + group_membership_update_q.Add(checking, new KeyValuePair(helpers.UnixTimeNow(), 60)); + } + } + + protected string getEnv(string name) + { + return Environment.GetEnvironmentVariable(name); + } + + protected void loadFromDockerEnv() + { + LogFormater.Info("Loading onEvents from ENV", true); + int loop = 1; + bool found = true; + while (found == true) + { + string title = getEnv("event_" + loop.ToString() + "_title"); + if (helpers.notempty(title) == true) + { + OnEvent config = new OnEvent(); + bool.TryParse(getEnv("event_" + loop.ToString() + "_enabled"), out bool enabled); + config.Enabled = enabled; + if (enabled == true) + { + config.title = title; + config.Monitor = getEnv("event_" + loop.ToString() + "_monitor"); + config.On = getEnv("event_" + loop.ToString() + "_on"); + + int loop2 = 1; + bool found2 = true; + List wherefields = new List(); + while (found2 == true) + { + found2 = false; + string wherefield = getEnv("event_" + loop.ToString() + "_where_" + loop2.ToString()); + if (helpers.notempty(wherefield) == true) + { + found2 = true; + wherefields.Add(wherefield); + } + loop2++; + } + config.Where = wherefields.ToArray(); + loop2 = 1; + found2 = true; + List actionfields = new List(); + while (found2 == true) + { + found2 = false; + string actionfield = getEnv("event_" + loop.ToString() + "_action_" + loop2.ToString()); + if (helpers.notempty(actionfield) == true) + { + found2 = true; + actionfields.Add(actionfield); + } + loop2++; + } + config.Actions = actionfields.ToArray(); + Events.Add(config); + } + } + else + { + found = false; + } + loop++; + } + } + + + protected void loadFromDisk() + { + LogFormater.Info("Loading onEvents from Disk", true); + OnEventBlob DemoloadedEvents = new OnEventBlob(); + OnEvent demoEvent = new OnEvent(); + demoEvent.Enabled = false; + demoEvent.Actions = new string[] { "Say|||0~#~hi mom im on TV!"}; + demoEvent.title = "demo"; + demoEvent.On = "Clock"; + demoEvent.Where = new string[] { "59 23 * * 7 {CRON} true"}; + demoEvent.Monitor = "None"; + DemoloadedEvents.listEvents = new OnEvent[] { demoEvent }; + + string targetfile = "events.json"; + SimpleIO io = new SimpleIO(); + io.ChangeRoot(controler.getFolderUsed()); + if (io.Exists(targetfile) == false) + { + LogFormater.Status("Creating new events file", true); + io.WriteJsonEvents(DemoloadedEvents, targetfile); + return; + } + string json = io.ReadFile(targetfile); + if (json.Length > 0) + { + try + { + OnEventBlob loadedEvents = JsonConvert.DeserializeObject(json); + foreach (OnEvent loaded in loadedEvents.listEvents) + { + Events.Add(loaded); + } + } + catch + { + io.MarkOld(targetfile); + io.WriteJsonEvents(DemoloadedEvents, targetfile); + } + return; + } + } + + protected void attachEvents() + { + controler.getBot().ChangeSimEvent += changeSim; + controler.getBot().TrackerEvent += trackerEvent; + controler.getBot().AlertMessage += alertMessage; + controler.getBot().StatusMessageEvent += statusMessage; + controler.getBot().GetClient.Groups.GroupMembersReply += groupMembershipUpdate; + controler.getBot().GetClient.Groups.GroupMemberEjected += groupMembershipUpdateEject; + } + + protected void groupMembershipChecks() + { + long now = helpers.UnixTimeNow(); + List repop = new List(); + foreach (KeyValuePair> entry in group_membership_update_q) + { + long dif = now - entry.Value.Key; + if (dif >= entry.Value.Value) + { + repop.Add(entry.Key); + } + } + foreach (UUID entry in repop) + { + group_membership_update_q[entry] = new KeyValuePair(now + 120, 60); + controler.getBot().GetClient.Groups.RequestGroupMembers(entry); + } + } + protected void markFastCheck(UUID group, bool fastPoll) + { + if (group_membership_update_q.ContainsKey(group) == false) + { + return; + } + group_membership_update_q[group] = new KeyValuePair(helpers.UnixTimeNow(), 25); + } + protected void updateGroupPolling(UUID group) + { + if(group_membership_update_q.ContainsKey(group) == false) + { + return; + } + group_membership_update_q[group] = new KeyValuePair(helpers.UnixTimeNow(), 60); + } + + protected void groupMembershipUpdateEject(object o, GroupOperationEventArgs e) + { + if (e.Success == true) + { + markFastCheck(e.GroupID,true); + } + } + + protected void groupMembershipUpdate(object o, GroupMembersReplyEventArgs e) + { + DisableGroupEvents = false; + updateGroupPolling(e.GroupID); + bool enableChanges = GroupMembership.ContainsKey(e.GroupID); + List members = new List(); + foreach(KeyValuePair entry in e.Members) + { + members.Add(entry.Key); + } + if(enableChanges == true) + { + List newEntrys = new List(); + List missingEntrys = GroupMembership[e.GroupID]; + foreach (UUID updated in members) + { + if(missingEntrys.Contains(updated) == false) + { + newEntrys.Add(updated); + } + else + { + missingEntrys.Remove(updated); + } + } + int lookups = 0; + foreach (UUID newMember in newEntrys) + { + string name = controler.getBot().FindAvatarKey2Name(newMember); + if(name == "lookup") + { + lookups++; + } + } + foreach (UUID missingMember in missingEntrys) + { + string name = controler.getBot().FindAvatarKey2Name(missingMember); + if (name == "lookup") + { + lookups++; + } + } + if (lookups > 0) + { + Thread.Sleep(500); + } + Dictionary args = new Dictionary(); + args.Add("avataruuid", "notset"); + args.Add("avatarname", "notset"); + args.Add("groupuuid", e.GroupID.ToString()); + + foreach (UUID newMember in newEntrys) + { + string name = controler.getBot().FindAvatarKey2Name(newMember); + args["avataruuid"] = newMember.ToString(); + args["avatarname"] = name; + TriggerEvent("GroupMemberJoins", args, false); + } + + foreach (UUID missingMember in missingEntrys) + { + string name = controler.getBot().FindAvatarKey2Name(missingMember); + args["avataruuid"] = missingMember.ToString(); + args["avatarname"] = name; + TriggerEvent("GroupMemberLeaves", args, false); + } + + } + } + + protected void ClockEvent() + { + TriggerEvent("Clock", new Dictionary(), true); + } + + protected void statusMessage(object o, StatusMessageEvent e) + { + if (controler.BotReady() == true) + { + bool send = false; + DateTime Dt = DateTime.Now; + if (Dt.Minute != lastMinTick) + { + lastMinTick = Dt.Minute; + ClockEvent(); + } + if (Dt.Second != lastSecTick) + { + lastSecTick = Dt.Second; + if (DisableGroupEvents == false) + { + groupMembershipChecks(); + } + } + if (LastStatus == null) + { + send = true; + } + else if (e.connected != LastStatus.connected) + { + send = true; + } + else if (e.sim != LastStatus.sim) + { + send = true; + } + if (send == true) + { + LastStatus = e; + Dictionary args = new Dictionary(); + args.Add("connected", e.connected.ToString()); + args.Add("sim", e.sim); + TriggerEvent("StatusMessage", args); + } + } + } + + protected void alertMessage(object o, AlertMessageEventArgs e) + { + Dictionary args = new Dictionary(); + args.Add("message ", e.Message); + TriggerEvent("SimAlertMessage", args); + } + + protected void changeSim(object o, SimChangedEventArgs e) + { + Dictionary args = new Dictionary(); + args.Add("oldSim", e.PreviousSimulator.Name); + TriggerEvent("ChangeSim", args); + } + + protected void trackerEvent(object o, TrackerEventArgs e) + { + Dictionary args = new Dictionary(); + args.Add("avataruuid", e.avatarUUID.ToString()); + args.Add("avatarname", e.avatarName); + if(e.Leaving == true) + { + TriggerEvent("GuestLeavesArea", args); + } + else + { + args.Add("AvatarSim", e.simName); + args.Add("AvatarParcel", e.parcelName); + TriggerEvent("GuestEntersArea", args); + } + } + + } + + +} diff --git a/BetterSecondbot/Tracking/BetterTracking.cs b/BetterSecondbot/Tracking/BetterTracking.cs index a1cfbe0..d5cdf75 100644 --- a/BetterSecondbot/Tracking/BetterTracking.cs +++ b/BetterSecondbot/Tracking/BetterTracking.cs @@ -42,16 +42,23 @@ namespace BetterSecondbot.Tracking if(int.TryParse(controler.getBot().getMyConfig.Setting_Tracker,out output_channel) == true) { output_to_channel = true; + LogFormater.Info("Tracker - Running as EventDriver + Channel output"); attachEvents(); } else if (controler.getBot().getMyConfig.Setting_Tracker.StartsWith("http") == true) { output_to_url = true; + LogFormater.Info("Tracker - Running as EventDriver + HTTP output"); attachEvents(); } + else if(controler.getBot().getMyConfig.Setting_Tracker != "Event") + { + LogFormater.Info("Tracker - Disabled not a vaild channel,http address or EventDriver"); + } else { - LogFormater.Info("Tracker - Disabled not a vaild channel or http"); + LogFormater.Info("Tracker - Running as EventDriver"); + attachEvents(); } } protected void attachEvents() @@ -64,7 +71,7 @@ namespace BetterSecondbot.Tracking { if(e.Status == LoginStatus.ConnectingToSim) { - LogFormater.Info("Tracker - disconnected from login process event"); + LogFormater.Info("Tracker - warming up"); controler.getBot().LoginProgess -= LoginProcess; if (AfterLogin == false) { @@ -78,7 +85,6 @@ namespace BetterSecondbot.Tracking LogFormater.Info("Tracker - Enabled HTTP: " + controler.getBot().getMyConfig.Setting_Tracker); } controler.getBot().StatusMessageEvent += StatusPing; - //controler.getBot().GetClient.Grid.CoarseLocationUpdate += LocationUpdate; } } } @@ -189,6 +195,21 @@ namespace BetterSecondbot.Tracking loop++; } output(avuuid, "entry###" + name); + string parcelname = ""; + string simname = ""; + if (controler.getBot().GetClient.Network.CurrentSim.AvatarPositions.ContainsKey(avuuid)) + { + Vector3 pos = controler.getBot().GetClient.Network.CurrentSim.AvatarPositions[avuuid]; + simname = controler.getBot().GetClient.Network.CurrentSim.Name; + int localp = controler.getBot().GetClient.Parcels.GetParcelLocalID(controler.getBot().GetClient.Network.CurrentSim, pos); + parcelname = "?"; + if (controler.getBot().GetClient.Network.CurrentSim.Parcels.ContainsKey(localp) == true) + { + Parcel P = controler.getBot().GetClient.Network.CurrentSim.Parcels[localp]; + parcelname = P.Name; + } + } + controler.getBot().TriggerTrackingEvent(avuuid, name,parcelname, simname, false); } addToSeen(avuuid); } @@ -235,31 +256,10 @@ namespace BetterSecondbot.Tracking { output(avuuid, "exit###" + name + "~#~" + AvatarSeen[avuuid].ToString()); removeFromSeen(avuuid); + controler.getBot().TriggerTrackingEvent(avuuid, name,"","",true); } } } } - - - - protected void LocationUpdate(object o, CoarseLocationUpdateEventArgs e) - { - if (e.NewEntries.Count() > 0) - { - foreach (UUID av in e.NewEntries) - { - Thread newThread = new Thread(this.TrackerEventAdd); - newThread.Start(av); - } - } - if (e.RemovedEntries.Count() > 0) - { - foreach (UUID av in e.RemovedEntries) - { - TrackerEventRemove(av); - } - } - - } } } diff --git a/Core/bottypes/AwaitReplyEventBot.cs b/Core/bottypes/AwaitReplyEventBot.cs index 7546ebf..33a0cc5 100644 --- a/Core/bottypes/AwaitReplyEventBot.cs +++ b/Core/bottypes/AwaitReplyEventBot.cs @@ -32,6 +32,7 @@ namespace BetterSecondBot.bottypes group_members_storage.Remove(e.GroupID); } group_members_storage.Add(e.GroupID, new KeyValuePair>(helpers.UnixTimeNow(), e.Members.Keys.ToList())); + } } diff --git a/Core/bottypes/EventsBot.cs b/Core/bottypes/EventsBot.cs index 30ae0dd..0d222d8 100644 --- a/Core/bottypes/EventsBot.cs +++ b/Core/bottypes/EventsBot.cs @@ -81,6 +81,23 @@ namespace BetterSecondBot.bottypes } } + public class TrackerEventArgs: EventArgs + { + public UUID avatarUUID { get; } + public string avatarName { get; } + public string parcelName { get; } + public string simName { get; } + public bool Leaving { get; } + public TrackerEventArgs(UUID avataruuid, string name, string parcelname, string simname, bool leaving) + { + this.avatarUUID = avataruuid; + this.avatarName = name; + this.parcelName = parcelname; + this.simName = simname; + this.Leaving = leaving; + } + } + public class ImSendArgs : EventArgs { public UUID avataruuid { get; } @@ -127,6 +144,7 @@ namespace BetterSecondBot.bottypes private EventHandler _StatusMessageEvent; private EventHandler _GroupsEvent; private EventHandler _SendImEvent; + private EventHandler _TrackerEvent; private readonly object _ChangeSimLock = new object(); private readonly object _AlertMessageLock = new object(); @@ -136,7 +154,12 @@ namespace BetterSecondBot.bottypes private readonly object _StatusMessageEventlock = new object(); private readonly object _GroupsEventLock = new object(); private readonly object _SendImEventLock = new object(); + private readonly object _TrackerUpdateEventLock = new object(); + public void TriggerTrackingEvent(UUID avatar,string name,string parcelname,string simname, bool exit) + { + On_TrackerUpdateEvent(new TrackerEventArgs(avatar, name,parcelname,simname,exit)); + } public event EventHandler ChangeSimEvent { @@ -165,6 +188,7 @@ namespace BetterSecondBot.bottypes add { lock (_MessageEventLock) { _MessageEvent += value; } } remove { lock (_MessageEventLock) { _MessageEvent -= value; } } } + public event EventHandler StatusMessageEvent { add { lock (_StatusMessageEventlock) { _StatusMessageEvent += value; } } @@ -180,6 +204,17 @@ namespace BetterSecondBot.bottypes add { lock (_SendImEventLock) { _SendImEvent += value; } } remove { lock (_SendImEventLock) { _SendImEvent -= value; } } } + public event EventHandler TrackerEvent + { + add { lock (_TrackerUpdateEventLock) { _TrackerEvent += value; } } + remove { lock (_TrackerUpdateEventLock) { _TrackerEvent -= value; } } + } + + protected void On_TrackerUpdateEvent(TrackerEventArgs e) + { + EventHandler handler = _TrackerEvent; + handler?.Invoke(this, e); + } protected void On_SendImEvent(ImSendArgs e) { diff --git a/Shared/IO/SimpleIO.cs b/Shared/IO/SimpleIO.cs index 6ce6b12..ef1763d 100644 --- a/Shared/IO/SimpleIO.cs +++ b/Shared/IO/SimpleIO.cs @@ -75,6 +75,14 @@ namespace BetterSecondBotShared.IO serializer.Serialize(writer, adverts); } + public void WriteJsonEvents(OnEventBlob events, string targetfile) + { + JsonSerializer serializer = new JsonSerializer(); + using StreamWriter sw = new StreamWriter(@"" + root_folder + "/" + targetfile); + using JsonWriter writer = new JsonTextWriter(sw) { Formatting = Formatting.Indented }; + serializer.Serialize(writer, events); + } + public void MarkOld(string targetfile) diff --git a/Shared/Json/JsonConfig.cs b/Shared/Json/JsonConfig.cs index 7e9b497..68f951b 100644 --- a/Shared/Json/JsonConfig.cs +++ b/Shared/Json/JsonConfig.cs @@ -47,6 +47,21 @@ namespace BetterSecondBotShared.Json public advertConfig[] adverts = new advertConfig[] { }; } + public class OnEvent + { + public string title; + public bool Enabled; + public string On; + public string Monitor; + public string[] Where; + public string[] Actions; + } + + public class OnEventBlob + { + public OnEvent[] listEvents = new OnEvent[] { }; + } + public class JsonConfig { diff --git a/Shared/Json/JsonConfigApi.cs b/Shared/Json/JsonConfigApi.cs index 501ac20..5345238 100644 --- a/Shared/Json/JsonConfigApi.cs +++ b/Shared/Json/JsonConfigApi.cs @@ -86,7 +86,7 @@ namespace BetterSecondBotShared.Json } else if(cmd == "Setting_Tracker") { - return "should the avatar tracker be enabled (anything but \"false\") and if so where should it go: (Channel number or a url)"; + return "Enable avatar tracking (and supported events) by setting this value to a channel number
or a URLor \"Event\" for events only"; } return ""; }