new OnEvents system (see wiki)

this is WIP
This commit is contained in:
Madpeterz 2021-05-19 21:42:41 +01:00
parent 1f407785b8
commit 1cd0a45063
7 changed files with 836 additions and 26 deletions

View file

@ -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<UUID, KeyValuePair<long, int>> group_membership_update_q = new Dictionary<UUID, KeyValuePair<long, int>>();
protected List<OnEvent> Events = new List<OnEvent>();
protected Dictionary<UUID, List<UUID>> GroupMembership = new Dictionary<UUID, List<UUID>>();
protected void TriggerEvent(string trigger, Dictionary<string, string> 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<string, string> 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<string, string> args, bool enableCronArgs = false)
{
bool WherePassed = true;
Dictionary<string, string> updateArgs = new Dictionary<string, string>();
string[] keys = args.Keys.ToArray();
foreach(string K in keys)
{
args[K] = args[K].Trim();
}
List<string> WhereFilters = new List<string>()
{
"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<string> bits = new List<string>();
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<string,string> args)
{
foreach(KeyValuePair<string,string> 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<long, int>(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<string> wherefields = new List<string>();
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<string> actionfields = new List<string>();
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<OnEventBlob>(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<UUID> repop = new List<UUID>();
foreach (KeyValuePair<UUID, KeyValuePair<long, int>> 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<long, int>(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<long, int>(helpers.UnixTimeNow(), 25);
}
protected void updateGroupPolling(UUID group)
{
if(group_membership_update_q.ContainsKey(group) == false)
{
return;
}
group_membership_update_q[group] = new KeyValuePair<long, int>(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<UUID> members = new List<UUID>();
foreach(KeyValuePair<UUID,GroupMember> entry in e.Members)
{
members.Add(entry.Key);
}
if(enableChanges == true)
{
List<UUID> newEntrys = new List<UUID>();
List<UUID> 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<string, string> args = new Dictionary<string, string>();
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<string, string>(), 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<string, string> args = new Dictionary<string, string>();
args.Add("connected", e.connected.ToString());
args.Add("sim", e.sim);
TriggerEvent("StatusMessage", args);
}
}
}
protected void alertMessage(object o, AlertMessageEventArgs e)
{
Dictionary<string, string> args = new Dictionary<string, string>();
args.Add("message ", e.Message);
TriggerEvent("SimAlertMessage", args);
}
protected void changeSim(object o, SimChangedEventArgs e)
{
Dictionary<string, string> args = new Dictionary<string, string>();
args.Add("oldSim", e.PreviousSimulator.Name);
TriggerEvent("ChangeSim", args);
}
protected void trackerEvent(object o, TrackerEventArgs e)
{
Dictionary<string, string> args = new Dictionary<string, string>();
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);
}
}
}
}

View file

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

View file

@ -32,6 +32,7 @@ namespace BetterSecondBot.bottypes
group_members_storage.Remove(e.GroupID);
}
group_members_storage.Add(e.GroupID, new KeyValuePair<long, List<UUID>>(helpers.UnixTimeNow(), e.Members.Keys.ToList()));
}
}

View file

@ -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> _StatusMessageEvent;
private EventHandler<GroupEventArgs> _GroupsEvent;
private EventHandler<ImSendArgs> _SendImEvent;
private EventHandler<TrackerEventArgs> _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<SimChangedEventArgs> ChangeSimEvent
{
@ -165,6 +188,7 @@ namespace BetterSecondBot.bottypes
add { lock (_MessageEventLock) { _MessageEvent += value; } }
remove { lock (_MessageEventLock) { _MessageEvent -= value; } }
}
public event EventHandler<StatusMessageEvent> 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<TrackerEventArgs> TrackerEvent
{
add { lock (_TrackerUpdateEventLock) { _TrackerEvent += value; } }
remove { lock (_TrackerUpdateEventLock) { _TrackerEvent -= value; } }
}
protected void On_TrackerUpdateEvent(TrackerEventArgs e)
{
EventHandler<TrackerEventArgs> handler = _TrackerEvent;
handler?.Invoke(this, e);
}
protected void On_SendImEvent(ImSendArgs e)
{

View file

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

View file

@ -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
{

View file

@ -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<br/>or a URL<b/r/>or \"Event\" for events only";
}
return "";
}