Add bot source

This commit is contained in:
Zontreck 2019-12-19 03:33:30 -07:00
parent 020d43b81c
commit 437cc0e0e1
14 changed files with 1788 additions and 0 deletions

View file

@ -0,0 +1,19 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Bot.Assemble
{
public class ASMInfo
{
public static string BotName = "ZBotCore";
public static double BotVer = 5.0;
public static string GitPassword = "**REMOVED**";
}
}

49
Source/BotSession.cs Normal file
View file

@ -0,0 +1,49 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenMetaverse;
using System.Threading.Tasks;
namespace Bot
{
public sealed class BotSession
{
private static BotSession _inst = null;
private static readonly object lockHandle = new object();
static BotSession()
{
}
public static BotSession Instance
{
get
{
lock (lockHandle)
{
if (_inst == null)
{
_inst = new BotSession();
}
return _inst;
}
}
}
public GridClient grid { get; set; }
public SysOut Logger { get; set; }
public MessageHandler.MessageHandleEvent MHE;
public MessageHandler MH;
public MainConfiguration ConfigurationHandle;
}
}

View file

@ -0,0 +1,45 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Reflection;
namespace Bot.CommandSystem
{
[System.AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class CommandGroup : Attribute
{
public string Command;
public int minLevel;
public MethodInfo AssignedMethod;
public int arguments = 0;
public CommandHelp cmdUsage;
public MessageHandler.Destinations CommandSource;
public CommandGroup(string Command, int minLevel, int argCount, string HelpText, MessageHandler.Destinations SourceType)
{
this.Command = Command;
this.minLevel = minLevel;
arguments = argCount;
CommandSource = SourceType;
cmdUsage = new CommandHelp(Command, minLevel, argCount, HelpText, SourceType);
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class CommandGroupMaster : Attribute
{
public string CommandGroupName;
public CommandGroupMaster(string CmdGroupName)
{
CommandGroupName = CmdGroupName;
}
}
}

View file

@ -0,0 +1,69 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.IO;
using OpenMetaverse;
namespace Bot.CommandSystem
{
public class CommandHelp
{
Help h;
public bool hasGroupFlag()
{
if ((h.dests_allowed & MessageHandler.Destinations.DEST_GROUP) == MessageHandler.Destinations.DEST_GROUP) return true;
else return false;
}
public static readonly string NoAdditionalArguments = "This command does not take any arguments";
public struct Help
{
public string Name;
public int minLevel;
public int args;
public string Text;
public string sources;
public MessageHandler.Destinations dests_allowed;
}
public string GetUsage()
{
return "_\nCommand [" + h.Name + "]\n" + h.sources + "\nMinimum Level Required [" + h.minLevel.ToString() + "]\nTotal Arguments [" + h.args.ToString() + "]\nUsage: " + h.Text;
}
public string RawUsage()
{
return "Usage: " + h.Text;
}
public CommandHelp(string CmdName, int minLevel, int argCount, string HelpText, MessageHandler.Destinations DESTS)
{
h = new Help();
string Applicable = "Command can be used in [";
if ((DESTS & MessageHandler.Destinations.DEST_LOCAL) == MessageHandler.Destinations.DEST_LOCAL) Applicable += "Local, ";
if ((DESTS & MessageHandler.Destinations.DEST_AGENT) == MessageHandler.Destinations.DEST_AGENT) Applicable += "IM, ";
if ((DESTS & MessageHandler.Destinations.DEST_GROUP) == MessageHandler.Destinations.DEST_GROUP) Applicable += "Group, ";
if ((DESTS & MessageHandler.Destinations.DEST_DISCORD) == MessageHandler.Destinations.DEST_DISCORD) Applicable += "Discord, ";
if (Applicable.Substring(Applicable.Length - 1, 1) == " ") Applicable = Applicable.Substring(0, Applicable.Length - 2) + "]";
h.dests_allowed = DESTS;
h.args = argCount;
h.Name = CmdName;
h.minLevel = minLevel;
if (HelpText == "") HelpText = NoAdditionalArguments;
h.Text = HelpText;
h.sources = Applicable;
}
}
}

View file

@ -0,0 +1,260 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using OpenMetaverse;
using Newtonsoft.Json;
using System.Reflection;
using System.Threading;
namespace Bot.CommandSystem
{
public sealed class CommandRegistry
{
/*
* ===============================
* START SINGLETON PATTERN
* ===============================
*/
private static CommandRegistry _instance = null;
private static readonly object lockhandle = new object();
static CommandRegistry()
{
}
public static CommandRegistry Instance
{
get
{
lock (lockhandle)
{
if (_instance == null)
{
BotSession bs = BotSession.Instance;
_instance = new CommandRegistry();
_instance.client = bs.grid;
_instance.config = bs.ConfigurationHandle;
_instance.Log = bs.Logger;
_instance.MHEx = bs.MHE;
_instance.LocateCommands();
}
return _instance;
}
}
}
/*
* ==============================
* SINGLETON PATTERN END
* Usage: CommandRegistry reg = CommandRegistry.Instance
* ==============================
*/
// Define the registry
public Dictionary<string, CommandGroup> Cmds = new Dictionary<string, CommandGroup>();
public GridClient client;
public SysOut Log;
public IConfig config;
public MessageHandler.MessageHandleEvent MHEx;
public void LocateCommands()
{
try
{
int i = 0;
// Locate all commands--
for (i = 0; i < AppDomain.CurrentDomain.GetAssemblies().Length; i++)
{
Assembly A = null;
try
{
A = AppDomain.CurrentDomain.GetAssemblies()[i];
}
catch (Exception e)
{
// MHEx(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "")
}
if (A != null)
{
int ii = 0;
for (ii = 0; ii < A.GetTypes().Length; ii++)
{
Type T = null;
try
{
T = A.GetTypes()[ii];
}
catch (Exception e)
{
}
if (T != null)
{
if (T.IsClass)
{
foreach (MethodInfo MI in T.GetMethods())
{
CommandGroup[] Command = (CommandGroup[])MI.GetCustomAttributes(typeof(CommandGroup), false);
//var CommandO = MI.GetCustomAttributes(typeof(CommandGroup), false);
if (Command.Length > 0)
{
for (int ix = 0; ix < Command.Length; ix++)
{
CommandGroup CG = Command[ix];
CG.AssignedMethod = MI;
if (Cmds.ContainsKey(CG.Command) == false)
{
Console.WriteLine("DISCOVER: " + CG.Command);
Cmds.Add(CG.Command, CG);
}
}
}
}
}
}
}
}
}
Console.WriteLine("Discovered " + Cmds.Count.ToString() + " total commands");
}
catch (ReflectionTypeLoadException e)
{
MHEx(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "FAILURE!!!\n \n[Assembly load failure]");
foreach (Exception X in e.LoaderExceptions)
{
MHEx(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, X.Message + "\n \nSTACK: " + X.StackTrace);
}
}
}
public void PrintHelpAll(MessageHandler.Destinations dest, UUID uid)
{
for (int i = 0; i < Cmds.Count; i++)
{
KeyValuePair<string, CommandGroup> kvp = Cmds.ElementAt(i);
CommandHelp HE = kvp.Value.cmdUsage;
if (dest == MessageHandler.Destinations.DEST_GROUP)
{
if (!HE.hasGroupFlag())
{
//return;
}
else
{
MHEx(dest, uid, HE.GetUsage());
}
}
else
{
MHEx(dest, uid, HE.GetUsage());
}
// MHEx(dest, uid, kvp.Value.cmdUsage.GetUsage());
}
}
public void PrintHelp(MessageHandler.Destinations dest, string cmd, UUID uid)
{
try
{
CommandHelp HE = Cmds[cmd].cmdUsage;
if (dest == MessageHandler.Destinations.DEST_GROUP)
{
if (!HE.hasGroupFlag())
{
//return; // DO NOT SCHEDULE THIS HELP INFO FOR GROUP!!!
}
}
MHEx(dest, uid, Cmds[cmd].cmdUsage.GetUsage());
}
catch (Exception e)
{
MHEx(dest, uid, "Error: Unrecognized command");
}
}
public void RunCommand(string cmdString, UUID user, int level, MessageHandler.MessageHandleEvent MHE, MessageHandler.Destinations source, UUID agentKey, string agentName)
{
MHEx = MHE;
int pos = 0;
string[] cmdStruct = cmdString.Split(' ');
int IgnoreCount = 0;
foreach (string S in cmdStruct)
{
if (IgnoreCount > 0) { IgnoreCount--; }
else
{
// Search for Command
if (Cmds.ContainsKey(S))
{
// this must be a command
// argument types will ALWAYS be structured like this:
// UUID, int, GridClient, [args up to argCount], optional:{SysOut}
CommandGroup cgX = Cmds[S];
if (level >= cgX.minLevel)
{
// Check that the destination is allowed.
// If not then skip this command entirely
MessageHandler.Destinations dests = cgX.CommandSource;
bool Allowed = false;
if ((dests & MessageHandler.Destinations.DEST_AGENT) == source) Allowed = true;
if ((dests & MessageHandler.Destinations.DEST_GROUP) == source) Allowed = true;
if ((dests & MessageHandler.Destinations.DEST_LOCAL) == source) Allowed = true;
if (!Allowed)
{
IgnoreCount = cgX.arguments;
}
else
{
var ovj = Activator.CreateInstance(cgX.AssignedMethod.DeclaringType);
string[] additionalArgs = new string[cgX.arguments];
IgnoreCount = cgX.arguments;
for (int i = 1; i <= cgX.arguments; i++)
{
additionalArgs[i - 1] = cmdStruct[pos + i];
}
pos++;
//(UUID client, int level, GridClient grid, string[] additionalArgs,
//SysOut log, MessageHandler.MessageHandleEvent MHE, MessageHandler.Destinations source,
//CommandRegistry registry, UUID agentKey, string agentName)
Thread CommandThread = new Thread(() => cgX.AssignedMethod.Invoke(ovj, new object[] { user, level, client, additionalArgs, Log, MHE, source, this, agentKey, agentName }));
CommandThread.Start();
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,20 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Bot
{
class BaseConfig : IConfig
{
public float ConfigVersion { get; set; }
public string ConfigFor { get; set; }
public List<string> Data { get; set; }
}
}

View file

@ -0,0 +1,23 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Bot
{
public interface IConfig
{
float ConfigVersion { get; set; }
string ConfigFor { get; set; }
List<string> Data { get; set; }
}
}

View file

@ -0,0 +1,57 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Bot
{
[Serializable()]
public class MainConfiguration : IConfig
{
public float ConfigVersion
{
get; set;
}
public string ConfigFor { get; set; }
public List<string> Data
{
get; set;
}
public string MainProgramDLL;
public string first { get; set; }
public string last { get; set; }
public string password { get; set; }
//public License LicenseKey { get; set; }
public string ActivationCode { get; set; }
public MainConfiguration()
{
}
public static MainConfiguration Load()
{
MainConfiguration X = new MainConfiguration();
SerialManager sm = new SerialManager();
try
{
X = sm.Read<MainConfiguration>("Main");
return X;
}
catch (FileNotFoundException e)
{
Console.WriteLine("Main.json was not found");
return new MainConfiguration();
}
}
}
}

30
Source/IProgram.cs Normal file
View file

@ -0,0 +1,30 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenMetaverse;
namespace Bot
{
public interface IProgram
{
void run(GridClient client, MessageHandler MH, CommandSystem.CommandRegistry registry); // Define the run command since a thread needs a entry point
string getTick(); // Run every second to check for queued data. If queue exists, then it will be returned as a JSON string.
// getTick can reply with data for the serializer for instance.
void passArguments(string data); // json!!
string ProgramName { get; }
float ProgramVersion { get; }
void LoadConfiguration();
void onIMEvent(object sender, InstantMessageEventArgs e);
}
}

171
Source/MessageHandler.cs Normal file
View file

@ -0,0 +1,171 @@

/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenMetaverse;
using Newtonsoft.Json;
using System.IO;
using System.Threading;
namespace Bot
{
public class MessageHandler
{
private List<MessageQueuePacket> MSGQueue = new List<MessageQueuePacket>();
private List<ActionPacket> ActionQueue = new List<ActionPacket>();
private List<DiscordAction> DiscordQueue = new List<DiscordAction>();
public ManualResetEvent GroupJoinWaiter = new ManualResetEvent(false);
private SysOut Log = SysOut.Instance;
[Flags]
public enum Destinations
{
DEST_AGENT = 1,
DEST_GROUP = 2,
DEST_LOCAL = 4,
DEST_CONSOLE_DEBUG = 8,
DEST_CONSOLE_INFO = 16,
DEST_ACTION = 32,
DEST_DISCORD = 64
};
public struct MessageQueuePacket
{
public Destinations Dest;
public UUID DestID;
public string Msg;
public int channel;
}
public struct ActionPacket
{
public Destinations Dest;
public string ActionStr;
}
public struct DiscordAction
{
public string Action;
}
public delegate void MessageHandleEvent(MessageHandler.Destinations DType, UUID AgentOrSession, string MSG, int channel = 0);
public volatile MessageHandleEvent callbacks;
public void MessageHandle(Destinations DType, UUID AgentOrSession, string MSG, int channel = 0)
{
if (DType == Destinations.DEST_ACTION)
{
if (MSG == "RESET_QUEUE")
{
ClearQueues();
return;
}
ActionPacket PKT = new ActionPacket();
PKT.Dest = DType;
PKT.ActionStr = MSG;
ActionQueue.Add(PKT);
return;
}
else if (DType == Destinations.DEST_DISCORD)
{
DiscordAction DA = new DiscordAction();
DA.Action = MSG;
DiscordQueue.Add(DA);
return; // Do nothing
}
MessageQueuePacket pkt = new MessageQueuePacket();
pkt.channel = channel;
pkt.Dest = DType;
pkt.DestID = AgentOrSession;
pkt.Msg = MSG;
if (MSGQueue != null)
MSGQueue.Add(pkt);
}
public void ClearQueues()
{
MSGQueue = new List<MessageQueuePacket>();
DiscordQueue = new List<DiscordAction>();
}
public void run(GridClient client)
{
// Execute one queue item
if (MSGQueue.Count == 0) return;
MessageQueuePacket pkt = MSGQueue.First();
MSGQueue.RemoveAt(MSGQueue.IndexOf(pkt));
if (pkt.Dest == Destinations.DEST_AGENT)
{
client.Self.InstantMessage(pkt.DestID, "[" + MSGQueue.Count.ToString() + "] " + pkt.Msg);
}
else if (pkt.Dest == Destinations.DEST_CONSOLE_DEBUG)
{
Log.debug("[" + MSGQueue.Count.ToString() + "] " + pkt.Msg);
}
else if (pkt.Dest == Destinations.DEST_CONSOLE_INFO)
{
Log.info("[" + MSGQueue.Count.ToString() + "] " + pkt.Msg);
}
else if (pkt.Dest == Destinations.DEST_GROUP)
{
if (client.Self.GroupChatSessions.ContainsKey(pkt.DestID))
client.Self.InstantMessageGroup(pkt.DestID, "[" + MSGQueue.Count.ToString() + "] " + pkt.Msg);
else
{
GroupJoinWaiter.Reset();
client.Groups.ActivateGroup(pkt.DestID);
client.Self.RequestJoinGroupChat(pkt.DestID);
//callbacks(Destinations.DEST_LOCAL, UUID.Zero, "Attempting to join group chat for secondlife:///app/group/" + pkt.DestID.ToString() + "/about");
if (GroupJoinWaiter.WaitOne(TimeSpan.FromSeconds(20), false))
{
client.Self.InstantMessageGroup(pkt.DestID, "[" + MSGQueue.Count.ToString() + "] " + pkt.Msg);
}
else
{
MSGQueue.Add(pkt); // Because we failed to join the group chat we'll tack this onto the end of the queue and try again
}
}
}
else if (pkt.Dest == Destinations.DEST_LOCAL)
{
client.Self.Chat("[" + MSGQueue.Count.ToString() + "] " + pkt.Msg, pkt.channel, ChatType.Normal);
}
}
public string CheckActions()
{
string RETURNStr = "";
if (ActionQueue.Count == 0) return "NONE";
else
{
RETURNStr = ActionQueue.First().ActionStr;
ActionQueue.Remove(ActionQueue.First());
return RETURNStr;
}
}
public string CheckDiscordActions()
{
if (DiscordQueue.Count == 0) return "NONE";
else
{
string RET = DiscordQueue.First().Action;
DiscordQueue.Remove(DiscordQueue.First());
return RET;
}
}
}
}

44
Source/PluginActivator.cs Normal file
View file

@ -0,0 +1,44 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Bot
{
public class PluginActivator
{
public Assembly LoadedASM = null;
public void LoadLibrary(string DLL)
{
LoadedASM = Assembly.LoadFrom(DLL);
}
public List<IProgram> Activate(Assembly asm)
{
List<IProgram> Plugins = new List<IProgram>();
foreach (Type A in asm.GetTypes())
{
Type check = A.GetInterface("IProgram");
if (check == null)
{
//return null;
}
else
{
IProgram plugin = Activator.CreateInstance(A) as IProgram;
Plugins.Add(plugin);
}
}
return Plugins;
}
}
}

743
Source/Program.cs Normal file
View file

@ -0,0 +1,743 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using Bot.CommandSystem;
using Newtonsoft.Json;
using OpenMetaverse;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using OpenMetaverse.Packets;
using Bot.Assemble;
using OpenMetaverse.Interfaces;
using System.Security.Cryptography;
namespace Bot
{
public class Program
{
public static SysOut Log = SysOut.Instance;
public static double BotVer = ASMInfo.BotVer;
public static string BotStr = ASMInfo.BotName; // internal identifier for linden
public static MainConfiguration conf;
public static string Flavor = "Bot"; // inworld identification - must be customized
public static SerialManager SM = new SerialManager();
public static string DefaultProgram = "BlankBot.dll"; // default bot - blank will only contain the commands to switch programs. It is a complete blank!
public static GridClient client = new GridClient();
public static bool g_iIsRunning = true;
public static MessageHandler MH;
public static CommandRegistry registry;
public static List<IProgram> g_ZPrograms = new List<IProgram>();
static readonly object _CacheLock = new object();
//public static License LicenseKey; // Not to be used yet
public static void msg(MessageHandler.Destinations D, UUID x, string m)
{
MH.callbacks(D, x, m);
}
public static unsafe void Main(string[] args)
{
Console.WriteLine("Setting up Main Configuration");
conf = MainConfiguration.Load();
//MasterObjectCaches = ObjectCaches.Instance;
Log.debugf(true, "main", args);
if (args.Length == 2)
{
// Check if this is activation command
if (args[0] == "-a")
{
conf.ActivationCode = args[1];
SM.Write<MainConfiguration>("Main", conf);
return;
}
else if (args[0] == "-m")
{
conf.MainProgramDLL = args[1];
SM.Write<MainConfiguration>("Main", conf);
return;
}
}
else if (args.Length == 4)
{
if (args[0] == "-l")
{
conf.first = args[1];
conf.last = args[2];
conf.password = args[3];
SM.Write<MainConfiguration>("Main", conf);
return;
}
}
// Initiate bot login
// Main thread must be caught in the bot loop so it does not terminate early.
// Other programs may hook into the bot to control it
/*
if (conf.ActivationCode != "")
{
License L = new License();
L.NewKey();
L.InitUniqueMachine();
L.Key = conf.ActivationCode;
License def = new License();
def.NewKey();
def.InitUniqueMachine();
string Reply;
HttpWebRequest _request = (HttpWebRequest)WebRequest.Create("http://bak.cloud.xsinode.net/act_handle.php?r=verify&act=" + conf.ActivationCode + "&LIC=" + L.Key + "&mac="+def.Key);
using (HttpWebResponse response = (HttpWebResponse)_request.GetResponse())
using (Stream str = response.GetResponseStream())
using (StreamReader sr = new StreamReader(str))
{
Reply = sr.ReadToEnd();
}
string[] ReplyData = Reply.Split('|');
if(ReplyData[0] == "deny")
{
WebClient wc = new WebClient();
if (File.Exists("Activator.exe")) File.Delete("Activator.exe");
wc.DownloadFile("http://bak.cloud.xsinode.net/znibot/Activator.exe", "Activator.exe");
int E_CODE = -1;
if (ReplyData[1] == "TOO_MANY") E_CODE = 90;
else if (ReplyData[1] == "EXPIRED") E_CODE = 32;
else if (ReplyData[1] == "INVALID") E_CODE = 100;
else E_CODE = 55;
string batchContents = "@echo off" +
"\ntimeout 5\n" +
"cd " + Directory.GetCurrentDirectory()+"\n" +
"Activator.exe -d -m " + E_CODE.ToString();
File.WriteAllText("denyAct.bat", batchContents);
Process p = Process.Start("denyAct.bat");
return;
} else if(ReplyData[0] == "allow")
{
// Handle expiry on server!
// Activate now
}
else
{
WebClient wc = new WebClient();
if (File.Exists("Activator.exe")) File.Delete("Activator.exe");
wc.DownloadFile("http://bak.cloud.xsinode.net/znibot/Activator.exe", "Activator.exe");
int E_CODE = 55; // Unknown reply. Activator will not permit logging in until the server can be reached safely.
string batchContents = "@echo off" +
"\ntimeout 5\n" +
"cd " + Directory.GetCurrentDirectory() + "\n" +
"Activator.exe -d -m " + E_CODE.ToString();
File.WriteAllText("denyAct.bat", batchContents);
Process p = Process.Start("denyAct.bat");
return;
}
}
else
{
Console.WriteLine("ERROR: You must have an activation code set prior to running Bot.exe!!\n \n[Please run Activator with the Confirmation Number]");
Console.ReadKey();
return;
}
*/
MH = new MessageHandler();
MH.callbacks += MH.MessageHandle;
string fna = null;
string lna = null;
string pwd = null;
if (conf.first == null)
{
if (args.Length == 0)
{
Log.info("Please enter your avatar's first name: ");
fna = Console.ReadLine();
Log.info("Please enter the last name: ");
lna = Console.ReadLine();
Log.info("Now enter your password: ");
pwd = Console.ReadLine();
conf.MainProgramDLL = DefaultProgram;
conf.ConfigFor = "ZBotCore";
conf.ConfigVersion = 1.0f;
}
else
{
Log.info("Loading...");
Log.info("FirstName: " + args[0]);
fna = args[0];
lna = args[1];
pwd = args[2];
// Continue boot
}
conf.first = fna;
conf.last = lna;
conf.password = pwd;
SM.Write<MainConfiguration>("Main", conf);
Log.debug("FirstName in Config: " + conf.first);
}
else
{
fna = conf.first;
lna = conf.last;
pwd = conf.password;
}
bool startupSeq = true;
if (File.Exists("ObjectCache.bdf")) File.Delete("ObjectCache.bdf");
client.Self.ChatFromSimulator += onChatRecv;
client.Self.GroupChatJoined += onJoinGroupChat;
//client.Objects.ObjectUpdate += onObjectUpdate;
//client.Objects.ObjectProperties += onObjectProperties;
//client.Network.SimChanged += onSimChange; // Recache prims for this sim
//client.Objects.TerseObjectUpdate += onObjectTerseUpdate;
client.Settings.OBJECT_TRACKING = true;
client.Settings.ALWAYS_DECODE_OBJECTS = true;
client.Settings.USE_ASSET_CACHE = true;
client.Throttle.Asset = 100000;
client.Throttle.Land = 100000;
client.Throttle.Task = 100000;
client.Throttle.Total = 100000;
client.Settings.ALWAYS_REQUEST_OBJECTS = true;
Console.WriteLine("Logging in...");
bool LoggedIn = client.Network.Login(fna, lna, pwd, BotStr, BotVer.ToString());
Console.WriteLine("Logged In: " + LoggedIn.ToString());
if (!LoggedIn)
{
Console.WriteLine("Check Creds:\n \nFirst Name: '" + fna + "'\nLast Name: '" + lna + "'\nPWD: '" + pwd + "'\nBotStr: '" + BotStr + "'\nBotVer: " + BotVer.ToString()+"\n \nLogin Message: "+client.Network.LoginMessage);
if(args[0] == "-x") // debug launch
Console.ReadKey();
}
if (LoggedIn)
{
if (File.Exists("XUP"))
{
File.Delete("XUP");
MH.callbacks(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Updated to version " + BotStr + " - "+BotVer.ToString());
}
Log.debugf(true, "SL_NET", new[] { "logged_in" });
// Setup BotSession Singleton!
BotSession.Instance.grid = client;
BotSession.Instance.Logger = Log;
BotSession.Instance.MHE = MH.callbacks;
BotSession.Instance.MH = MH;
BotSession.Instance.ConfigurationHandle = conf;
while (g_iIsRunning)
{
client.Self.RetrieveInstantMessages();
if (client.Network.Connected == false) g_iIsRunning = false; // Quit the program and restart immediately!
Thread.Sleep(2000);
DirectoryInfo lp = new DirectoryInfo("update");
if (lp.Exists) g_iIsRunning = false;
if (conf.ConfigFor == "Main")
{
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Alert: Main.json is not fully initialized. Setting default values");
conf.ConfigFor = "BOT";
conf.ConfigVersion = 1.0f;
// data contains nothing at the moment.
SM.Write<MainConfiguration>("Main", conf);
conf = null;
conf = SM.Read<MainConfiguration>("Main");
if (conf.ConfigFor == "BOT")
{
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Main.json has been created");
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Continuing with startup");
}
else
{
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Main.json does not contain all memory. FAILURE.");
g_iIsRunning = false;
}
}
else
{
Flavor = conf.ConfigFor;
}
// Check MainConfiguration for a mainProgram handle
if (conf.MainProgramDLL == null)
{
Log.info("Setting main program library");
conf.MainProgramDLL = DefaultProgram;
SM.Write<MainConfiguration>("Main", conf);
}
if (File.Exists(conf.MainProgramDLL) == false)
{
Log.info("MainProgram Library: " + conf.MainProgramDLL + " does not exist");
if (conf.MainProgramDLL == DefaultProgram)
{
Log.info("FATAL: BlankBot.dll must exist to proceed");
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "BlankBot.dll does not exist. Please place the blank bot program into the same folder as 'Bot.dll'. Load cannot proceed any further Terminating");
}
g_iIsRunning = false;
}
else
{
if (startupSeq)
{
registry = CommandRegistry.Instance;
//ReloadGroupsCache();
Log.info("MainProgram exists");
try
{
int programCount = 0;
PluginActivator PA = new PluginActivator();
PA.LoadLibrary(conf.MainProgramDLL);
List<IProgram> plugins = PA.Activate(PA.LoadedASM);
foreach (IProgram plugin in plugins)
{
plugin.run(client, MH, registry); // simulate constructor and set up other things
g_ZPrograms.Add(plugin);
client.Self.IM += plugin.onIMEvent;
programCount++;
Log.debug("Plugin: " + plugin.ProgramName + " [" + PA.LoadedASM.FullName + "] added to g_ZPrograms");
if (File.Exists(plugin.ProgramName + ".bdf"))
plugin.LoadConfiguration(); // will throw an error if BlankBot tries to load config
}
Log.debug(g_ZPrograms.Count.ToString() + " programs linked");
if (g_ZPrograms.Count > 0) msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Default Program [" + conf.MainProgramDLL + "] has been loaded, " + programCount.ToString() + " plugin(s) loaded");
registry.LocateCommands();
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Commands found: " + registry.Cmds.Count.ToString());
}
catch (Exception E)
{
string Msg = E.Message;
string STACK = E.StackTrace.Replace("ZNI", "");
Msg = Msg.Replace("ZNI", "");
Log.debug("Generic Exception Caught: " + Msg + " [0x0A]");
int i;
int* ptr = &i;
IntPtr addr = (IntPtr)ptr;
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Generic Exception Caught: " + Msg + " [0x0A, 0x" + addr.ToString("x") + "]\nSTACK: " + STACK);
}
}
}
foreach (IProgram plugin in g_ZPrograms)
{
plugin.getTick(); // Trigger a tick event!!!
}
string jsonReply = MH.CheckActions();
if (jsonReply == "NONE") jsonReply = "";
if (jsonReply == "" || jsonReply == null)
{
//Log.debug("TICK NULL");
}
else
{
Log.debug("TICK REPLY: " + jsonReply);
dynamic jsonObj = JsonConvert.DeserializeObject(jsonReply);
Log.debug("TYPE: " + jsonObj.type);
string tp = jsonObj.type;
switch (tp)
{
case "assignProgram":
{
client.Self.Chat("Stand by", 0, ChatType.Normal);
string newProg = jsonObj.newProgram;
if (File.Exists(newProg + ".dll"))
{
conf.MainProgramDLL = jsonObj.newProgram + ".dll";
SM.Write<MainConfiguration>("Main", conf);
client.Self.Chat("Restarting bot using new main program", 0, ChatType.Normal);
g_iIsRunning = false;
}
else
{
client.Self.Chat("Error: Program '" + newProg + ".dll' does not exist.", 0, ChatType.Normal);
}
break;
}
case "exit":
{
Log.info("Logging off!");
g_iIsRunning = false;
break;
}
case "reload_groups":
{
ReloadGroupsCache();
break;
}
case "load_program":
{
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Stand by.. loading secondary libraries");
string newProg = jsonObj.newProgram;
if (File.Exists(newProg + ".dll"))
{
newProg += ".dll";
PluginActivator Plugs = new PluginActivator();
Plugs.LoadLibrary(newProg);
List<IProgram> libs = Plugs.Activate(Plugs.LoadedASM);
int programCount = 0;
foreach (IProgram plugin in libs)
{
plugin.run(client, MH, registry); // simulate constructor and set up other things
g_ZPrograms.Add(plugin);
client.Self.IM += plugin.onIMEvent;
programCount++;
Log.debug("Plugin: " + plugin.ProgramName + " [" + Plugs.LoadedASM.FullName + "] added to g_ZPrograms");
if (File.Exists(plugin.ProgramName + ".bdf"))
plugin.LoadConfiguration(); // will throw an error if BlankBot tries to load config
}
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Loaded plugin " + newProg + " with " + programCount.ToString() + " entry points");
registry.LocateCommands();
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Commands found: " + registry.Cmds.Count.ToString());
}
else
{
msg(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "ERROR: " + newProg + " could not be located!");
}
break;
}
default:
{
Log.debug("Unknown response code");
break;
}
}
}
MH.run(client);
//MasterObjectCaches.Save();
if (startupSeq) startupSeq = false;
//if (MasterObjectCaches.RegionPrims.Count == 0 && client.Network.Connected)
//{
// onSimChange(null, new SimChangedEventArgs(client.Network.CurrentSim));
//}
}
Log.debugf(false, "SL_NET", new[] { "" });
client.Network.Logout();
}
Log.debugf(false, "main", args);
//System.Console.WriteLine("PAUSING. PRESS ANY KEY TO EXIT");
//System.Console.ReadKey();
}
private static void onJoinGroupChat(object sender, GroupChatJoinedEventArgs e)
{
if (e.Success)
MH.GroupJoinWaiter.Set();
}
private static AutoResetEvent ReqObjProperties = new AutoResetEvent(false);
private static Dictionary<UUID, Primitive.ObjectProperties> ReqObjPropertiesData = new Dictionary<UUID, Primitive.ObjectProperties>();
[STAThread()]
private static void onObjectUpdate(object sender, PrimEventArgs e)
{
//Console.WriteLine("ObjectUpdate @ " + DateTime.Now);
/*
* Disabled until Libremetaverse is fully tested
*
while (Monitor.IsEntered(_CacheLock)) { }
lock (_CacheLock)
{
if (MasterObjectCaches == null)
{
MasterObjectCaches = ObjectCaches.Instance;
Console.WriteLine("\n=> Recv: ObjectUpdate; Set: new MasterObjectCache(" + e.Simulator.Name + ")");
}
if (MasterObjectCaches.RegionPrims == null) MasterObjectCaches.RegionPrims = new Dictionary<string, Dictionary<UUID, Primitive2>>();
Dictionary<UUID, Primitive2> NewDictionary = new Dictionary<UUID, Primitive2>();
if (!MasterObjectCaches.RegionPrims.ContainsKey(e.Simulator.Name))
{
NewDictionary = new Dictionary<UUID, Primitive2>();
try
{
MasterObjectCaches.RegionPrims.Add(e.Simulator.Name, NewDictionary);
MasterObjectCaches.MarkDirty();
}
catch (Exception E)
{
Console.WriteLine("FAILED TO INITIALIZE MASTER OBJECT CACHE FOR REGION");
Console.WriteLine(E.StackTrace);
}
}
else
{
NewDictionary = MasterObjectCaches.RegionPrims[e.Simulator.Name];
}
Primitive p = e.Prim;
if (!NewDictionary.ContainsKey(e.Prim.ID))
{
NewDictionary.Add(p.ID, new Primitive2(p));
MasterObjectCaches.RegionPrims[e.Simulator.Name] = NewDictionary;
MasterObjectCaches.MarkDirty();
// Check properties val
if (p.Properties == null)
{
client.Objects.SelectObject(client.Network.CurrentSim, p.LocalID);
client.Objects.DeselectObject(client.Network.CurrentSim, p.LocalID);
}
if (p.OwnerID == client.Self.AgentID)
{
Console.WriteLine("[!] Discovered a prim that i created\n\n");
}
}
else
{
// Prim is already in list.
// Verify that the properties are still the same
if (p.Properties == null)
{
client.Objects.SelectObject(client.Network.CurrentSim, p.LocalID);
client.Objects.DeselectObject(client.Network.CurrentSim, p.LocalID);
}
}
}
*/
}
[STAThread()]
private static void onObjectTerseUpdate(object sender, TerseObjectUpdateEventArgs e)
{
//Console.WriteLine("TerseObjectUpdate @ " + DateTime.Now);
PrimEventArgs ex = new PrimEventArgs(e.Simulator, e.Prim, e.TimeDilation, false, false);
onObjectUpdate(sender, ex);
}
[STAThread()]
private static void onObjectProperties(object sender, ObjectPropertiesEventArgs e)
{
//Console.WriteLine("ObjectProperties @ " + DateTime.Now);
//Console.WriteLine("\n=> Got prim properties <=\n");
/*
Dictionary<UUID, Primitive2> PrimList = MasterObjectCaches.RegionPrims[e.Simulator.Name];
UUID id = e.Properties.ObjectID;
if (PrimList.ContainsKey(id))
{
Primitive2 prim = PrimList[id];
if (prim.Properties != new Primitive2Properties(e.Properties))
{
prim.Properties = new Primitive2Properties(e.Properties);
PrimList[id] = prim;
MasterObjectCaches.RegionPrims[e.Simulator.Name] = PrimList;
MasterObjectCaches.MarkDirty();
}
}
else
{
// Skip. There is nothing we can do
}*/
//ReqObjPropertiesData.Add(e.Properties.ObjectID, e.Properties);
// This function is disabled until LibreMetaverse is fully tested
//ReqObjProperties.Set();
}
private static void onSimChange(object sender, SimChangedEventArgs e)
{
// Request object data for all prims on sim!
//Dictionary<uint, Primitive> simPrims = client.Network.CurrentSim.ObjectsPrimitives.Copy();
//ManualResetEvent mreWaiter = new ManualResetEvent(false);
//mreWaiter.Reset();
//foreach(KeyValuePair<uint, Primitive> kvp in simPrims)
//{
// onObjectUpdate(null, new PrimEventArgs(client.Network.CurrentSim, kvp.Value, 0, false, false));
// mreWaiter.WaitOne(TimeSpan.FromMilliseconds(500));
//}
}
private static void onChatRecv(object sender, ChatEventArgs e)
{
if (e.Message == "" || e.Message == "typing") return;
if (e.SourceID == client.Self.AgentID) return;
string eMe = e.Message;
Dictionary<string, string> dstuf = new Dictionary<string, string>();
Log.debugf(true, "onChatRecv", new[] { e.Message });
dstuf.Add("type", "chat");
string SRC = "";
if (e.SourceType == ChatSourceType.Agent) SRC = "agent";
else if (e.SourceType == ChatSourceType.Object) SRC = "obj";
else if (e.SourceType == ChatSourceType.System) SRC = "sys";
dstuf.Add("source", SRC);
dstuf.Add("request", eMe);
dstuf.Add("from", e.SourceID.ToString());
dstuf.Add("from_sess", "");
dstuf.Add("fromName", e.FromName);
foreach (IProgram P in g_ZPrograms)
{
Log.debug(JsonConvert.SerializeObject(dstuf));
Thread X = new Thread(() => P.passArguments(JsonConvert.SerializeObject(dstuf)));
X.Name = "T_" + eMe;
X.Start();
}
Log.debugf(false, "onChatRecv", new[] { "" });
}
private static Dictionary<UUID, Group> GroupsCache = null;
private static ManualResetEvent GroupsEvent = new ManualResetEvent(false);
private static void Groups_CurrentGroups(object sender, CurrentGroupsEventArgs e)
{
if (null == GroupsCache)
GroupsCache = e.Groups;
else
lock (GroupsCache) { GroupsCache = e.Groups; }
GroupsEvent.Set();
}
private static void ReloadGroupsCache()
{
client.Groups.CurrentGroups += Groups_CurrentGroups;
client.Groups.RequestCurrentGroups();
GroupsEvent.WaitOne(10000, false);
client.Groups.CurrentGroups -= Groups_CurrentGroups;
GroupsEvent.Reset();
}
private static UUID GroupName2UUID(String groupName)
{
UUID tryUUID;
if (UUID.TryParse(groupName, out tryUUID))
return tryUUID;
if (null == GroupsCache)
{
ReloadGroupsCache();
if (null == GroupsCache)
return UUID.Zero;
}
lock (GroupsCache)
{
if (GroupsCache.Count > 0)
{
foreach (Group currentGroup in GroupsCache.Values)
if (currentGroup.Name.ToLower() == groupName.ToLower())
return currentGroup.ID;
}
}
return UUID.Zero;
}
}
public class Tools
{
public static Int32 getTimestamp()
{
return int.Parse(DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString());
}
public static string Hash2String(byte[] Hash)
{
StringBuilder sb = new StringBuilder();
foreach(byte b in Hash)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
public static string MD5Hash(string ToHash)
{
byte[] Source = UTF8Encoding.UTF8.GetBytes(ToHash);
byte[] Hash = new MD5CryptoServiceProvider().ComputeHash(Source);
return Tools.Hash2String(Hash);
}
public static string MD5Hash(byte[] ToHash)
{
return Tools.Hash2String(new MD5CryptoServiceProvider().ComputeHash(ToHash));
}
public static string SHA256Hash(string ToHash)
{
SHA256 hasher = SHA256.Create();
return Tools.Hash2String(hasher.ComputeHash(UTF8Encoding.UTF8.GetBytes(ToHash)));
}
public static string SHA256Hash(byte[] ToHash)
{
SHA256 Hasher = SHA256.Create();
return Tools.Hash2String(Hasher.ComputeHash(ToHash));
}
}
}

114
Source/SerialManager.cs Normal file
View file

@ -0,0 +1,114 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Newtonsoft.Json;
namespace Bot
{
public class SerialManager // Handles saving a large amount of data to a binary file or vise-versa
{
/*
public void Write<T>(string Name, T ObjectData)
{
Stream F = null;
BinaryFormatter BinaryFormat = new BinaryFormatter();
try
{
if (File.Exists(Name + ".bdf")) File.Copy(Name + ".bdf", Name + ".bdf.bak", true);
F = new FileStream(Name + ".bdf", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
BinaryFormat.Serialize(F, ObjectData);
}
catch (SerializationException e)
{
Console.WriteLine(e.Message);
}
F.Close();
}
public T Read<T>(string Name)
{
if (File.Exists(Name + ".bdf") == false) throw new FileNotFoundException();
Stream F = new FileStream(Name + ".bdf", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
BinaryFormatter BinaryFormat = new BinaryFormatter();
T deserial = default(T);
try
{
deserial = (T)BinaryFormat.Deserialize(F);
}
catch (SerializationException e)
{
Console.WriteLine(e.Message);
}
catch (Exception e)
{
//
Console.WriteLine(e.Message);
}
F.Close();
if (deserial == null) deserial = default(T);
Console.WriteLine("Returning deserialized class");
return deserial;
}
*/
private static readonly object _fileAccess = new object();
public void Write<T>(string Name, T ObjectData)
{
string Json = JsonConvert.SerializeObject(ObjectData, Formatting.Indented);
lock (_fileAccess)
{
try
{
File.WriteAllText(Name + ".json", Json);
} catch(Exception E)
{
Console.WriteLine(E.Message);
}
}
}
public T Read<T> (string Name)
{
lock(_fileAccess){
try
{
T obj = default(T);
string serial = File.ReadAllText(Name + ".json");
obj = (T)JsonConvert.DeserializeObject<T>(serial);
Console.WriteLine("Returning class object");
if (obj == null) obj = default(T);
return obj;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw new FileNotFoundException();
}
}
}
}
}

144
Source/SysOut.cs Normal file
View file

@ -0,0 +1,144 @@
/*
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
Licensed under the AGPL-3.0
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Bot
{
public sealed class SysOut
{
private static SysOut _Inst = null;
private static readonly object instloc = new object();
static SysOut() { }
public static SysOut Instance
{
get
{
lock (instloc)
{
if(_Inst == null)
{
_Inst = new SysOut();
_Inst.FLAVOR = "Bot";
}
return _Inst;
}
}
}
public int tabs = 0;
string FLAVOR;
private static readonly object Locks = new object();
public void info(string msg)
{
lock (Locks)
{
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("[");
Console.ForegroundColor = ConsoleColor.Green;
System.Console.Write("INFO");
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("] [");
Console.ForegroundColor = ConsoleColor.Red;
System.Console.Write(FLAVOR);
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("] ");
Console.ForegroundColor = ConsoleColor.Cyan;
for (int i = 0; i < tabs; i++) { Console.Write("\t|"); }
System.Console.Write(msg);
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("\n");
}
}
public void debugf(bool enter, string label, string[] debugParams)
{
lock (Locks)
{
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("[");
Console.ForegroundColor = ConsoleColor.DarkRed;
System.Console.Write("DEBUG");
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("] [");
Console.ForegroundColor = ConsoleColor.Green;
System.Console.Write(FLAVOR);
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("] ");
Console.ForegroundColor = ConsoleColor.Magenta;
if (enter)
{
for (int i = 0; i < tabs; i++) { System.Console.Write("\t"); }
System.Console.Write("ENTER ");
tabs++;
Console.BackgroundColor = ConsoleColor.Cyan;
System.Console.Write(label);
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(" ");
}
else
{
tabs--;
for (int i = 0; i < tabs; i++) { System.Console.Write("\t"); }
System.Console.Write("LEAVE ");
Console.BackgroundColor = ConsoleColor.Cyan;
System.Console.Write(label);
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(" ");
}
Console.Write("[");
for (int i = 0; i < debugParams.Length; i++)
{
Console.Write(debugParams[i] + ", ");
}
Console.Write("]");
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("\n");
Console.ResetColor();
}
}
public void debug(string m)
{
lock (Locks)
{
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("[");
Console.ForegroundColor = ConsoleColor.DarkRed;
System.Console.Write("DEBUG");
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("] [");
Console.ForegroundColor = ConsoleColor.Green;
System.Console.Write(FLAVOR);
Console.ForegroundColor = ConsoleColor.White;
System.Console.Write("] ");
Console.ForegroundColor = ConsoleColor.Magenta;
for (int i = 0; i < tabs; i++)
{
Console.Write("\t|");
}
Console.Write(" " + m);
Console.Write("\n");
}
}
}
}