new OnEvents system (see wiki)
this is WIP
This commit is contained in:
parent
1f407785b8
commit
1cd0a45063
7 changed files with 836 additions and 26 deletions
751
BetterSecondbot/OnEvents/onevent.cs
Normal file
751
BetterSecondbot/OnEvents/onevent.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -42,16 +42,23 @@ namespace BetterSecondbot.Tracking
|
||||||
if(int.TryParse(controler.getBot().getMyConfig.Setting_Tracker,out output_channel) == true)
|
if(int.TryParse(controler.getBot().getMyConfig.Setting_Tracker,out output_channel) == true)
|
||||||
{
|
{
|
||||||
output_to_channel = true;
|
output_to_channel = true;
|
||||||
|
LogFormater.Info("Tracker - Running as EventDriver + Channel output");
|
||||||
attachEvents();
|
attachEvents();
|
||||||
}
|
}
|
||||||
else if (controler.getBot().getMyConfig.Setting_Tracker.StartsWith("http") == true)
|
else if (controler.getBot().getMyConfig.Setting_Tracker.StartsWith("http") == true)
|
||||||
{
|
{
|
||||||
output_to_url = true;
|
output_to_url = true;
|
||||||
|
LogFormater.Info("Tracker - Running as EventDriver + HTTP output");
|
||||||
attachEvents();
|
attachEvents();
|
||||||
}
|
}
|
||||||
|
else if(controler.getBot().getMyConfig.Setting_Tracker != "Event")
|
||||||
|
{
|
||||||
|
LogFormater.Info("Tracker - Disabled not a vaild channel,http address or EventDriver");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogFormater.Info("Tracker - Disabled not a vaild channel or http");
|
LogFormater.Info("Tracker - Running as EventDriver");
|
||||||
|
attachEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected void attachEvents()
|
protected void attachEvents()
|
||||||
|
|
@ -64,7 +71,7 @@ namespace BetterSecondbot.Tracking
|
||||||
{
|
{
|
||||||
if(e.Status == LoginStatus.ConnectingToSim)
|
if(e.Status == LoginStatus.ConnectingToSim)
|
||||||
{
|
{
|
||||||
LogFormater.Info("Tracker - disconnected from login process event");
|
LogFormater.Info("Tracker - warming up");
|
||||||
controler.getBot().LoginProgess -= LoginProcess;
|
controler.getBot().LoginProgess -= LoginProcess;
|
||||||
if (AfterLogin == false)
|
if (AfterLogin == false)
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +85,6 @@ namespace BetterSecondbot.Tracking
|
||||||
LogFormater.Info("Tracker - Enabled HTTP: " + controler.getBot().getMyConfig.Setting_Tracker);
|
LogFormater.Info("Tracker - Enabled HTTP: " + controler.getBot().getMyConfig.Setting_Tracker);
|
||||||
}
|
}
|
||||||
controler.getBot().StatusMessageEvent += StatusPing;
|
controler.getBot().StatusMessageEvent += StatusPing;
|
||||||
//controler.getBot().GetClient.Grid.CoarseLocationUpdate += LocationUpdate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -189,6 +195,21 @@ namespace BetterSecondbot.Tracking
|
||||||
loop++;
|
loop++;
|
||||||
}
|
}
|
||||||
output(avuuid, "entry###" + name);
|
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);
|
addToSeen(avuuid);
|
||||||
}
|
}
|
||||||
|
|
@ -235,31 +256,10 @@ namespace BetterSecondbot.Tracking
|
||||||
{
|
{
|
||||||
output(avuuid, "exit###" + name + "~#~" + AvatarSeen[avuuid].ToString());
|
output(avuuid, "exit###" + name + "~#~" + AvatarSeen[avuuid].ToString());
|
||||||
removeFromSeen(avuuid);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ namespace BetterSecondBot.bottypes
|
||||||
group_members_storage.Remove(e.GroupID);
|
group_members_storage.Remove(e.GroupID);
|
||||||
}
|
}
|
||||||
group_members_storage.Add(e.GroupID, new KeyValuePair<long, List<UUID>>(helpers.UnixTimeNow(), e.Members.Keys.ToList()));
|
group_members_storage.Add(e.GroupID, new KeyValuePair<long, List<UUID>>(helpers.UnixTimeNow(), e.Members.Keys.ToList()));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 class ImSendArgs : EventArgs
|
||||||
{
|
{
|
||||||
public UUID avataruuid { get; }
|
public UUID avataruuid { get; }
|
||||||
|
|
@ -127,6 +144,7 @@ namespace BetterSecondBot.bottypes
|
||||||
private EventHandler<StatusMessageEvent> _StatusMessageEvent;
|
private EventHandler<StatusMessageEvent> _StatusMessageEvent;
|
||||||
private EventHandler<GroupEventArgs> _GroupsEvent;
|
private EventHandler<GroupEventArgs> _GroupsEvent;
|
||||||
private EventHandler<ImSendArgs> _SendImEvent;
|
private EventHandler<ImSendArgs> _SendImEvent;
|
||||||
|
private EventHandler<TrackerEventArgs> _TrackerEvent;
|
||||||
|
|
||||||
private readonly object _ChangeSimLock = new object();
|
private readonly object _ChangeSimLock = new object();
|
||||||
private readonly object _AlertMessageLock = new object();
|
private readonly object _AlertMessageLock = new object();
|
||||||
|
|
@ -136,7 +154,12 @@ namespace BetterSecondBot.bottypes
|
||||||
private readonly object _StatusMessageEventlock = new object();
|
private readonly object _StatusMessageEventlock = new object();
|
||||||
private readonly object _GroupsEventLock = new object();
|
private readonly object _GroupsEventLock = new object();
|
||||||
private readonly object _SendImEventLock = 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
|
public event EventHandler<SimChangedEventArgs> ChangeSimEvent
|
||||||
{
|
{
|
||||||
|
|
@ -165,6 +188,7 @@ namespace BetterSecondBot.bottypes
|
||||||
add { lock (_MessageEventLock) { _MessageEvent += value; } }
|
add { lock (_MessageEventLock) { _MessageEvent += value; } }
|
||||||
remove { lock (_MessageEventLock) { _MessageEvent -= value; } }
|
remove { lock (_MessageEventLock) { _MessageEvent -= value; } }
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<StatusMessageEvent> StatusMessageEvent
|
public event EventHandler<StatusMessageEvent> StatusMessageEvent
|
||||||
{
|
{
|
||||||
add { lock (_StatusMessageEventlock) { _StatusMessageEvent += value; } }
|
add { lock (_StatusMessageEventlock) { _StatusMessageEvent += value; } }
|
||||||
|
|
@ -180,6 +204,17 @@ namespace BetterSecondBot.bottypes
|
||||||
add { lock (_SendImEventLock) { _SendImEvent += value; } }
|
add { lock (_SendImEventLock) { _SendImEvent += value; } }
|
||||||
remove { 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)
|
protected void On_SendImEvent(ImSendArgs e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,14 @@ namespace BetterSecondBotShared.IO
|
||||||
serializer.Serialize(writer, adverts);
|
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)
|
public void MarkOld(string targetfile)
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,21 @@ namespace BetterSecondBotShared.Json
|
||||||
public advertConfig[] adverts = new advertConfig[] { };
|
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
|
public class JsonConfig
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ namespace BetterSecondBotShared.Json
|
||||||
}
|
}
|
||||||
else if(cmd == "Setting_Tracker")
|
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 "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue