Skip to content
This repository has been archived by the owner on Feb 8, 2021. It is now read-only.

Commit

Permalink
Implemented Plugins + Improvements
Browse files Browse the repository at this point in the history
No TextDBAdapter yet though.
  • Loading branch information
squeeglii committed Mar 26, 2019
1 parent b54ea08 commit bab9879
Show file tree
Hide file tree
Showing 24 changed files with 579 additions and 297 deletions.
480 changes: 231 additions & 249 deletions .idea/workspace.xml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions archt5.iml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/Resources" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/LATEST" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
Expand Down
8 changes: 7 additions & 1 deletion src/net/cloudsbots/archseriest/archt5/Bot.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import net.cloudsbots.archseriest.archt5.components.UtilityFunctions;
import net.cloudsbots.archseriest.archt5.events.EventManager;
import net.cloudsbots.archseriest.archt5.exceptions.PermissionDeniedException;
import net.cloudsbots.archseriest.archt5.plugin.DisableReason;
import net.cloudsbots.archseriest.archt5.plugin.PluginManager;
import net.cloudsbots.archseriest.archt5.plugin.PluginPackaging;
import net.dv8tion.jda.core.JDA;

import java.util.HashMap;
Expand Down Expand Up @@ -36,7 +38,7 @@ public Bot(String syspass){

public static final String BRANCH_NAME = "DEV5";
public static final String MILESTONE_VERSION = "0.1.0";
public static final String BUILD_VERSION = "ADP190901"; //Example - Alpha Version, Development Build, Private Beta, 2018, Week 52, Build 01 of that week = ADP185201
public static final String BUILD_VERSION = "ADP191201"; //Example - Alpha Version, Development Build, Private Beta, 2018, Week 52, Build 01 of that week = ADP185201
public static final int BUILD_STRUCTURE = 1; // If there's a major code change which is breaking of old features, increment this.
public static final String BUILD_DATE = "27/12/18"; // dd/mm/yy

Expand Down Expand Up @@ -100,6 +102,10 @@ public static void shutdown(int code){

//Shutdown

for(PluginPackaging p:Bot.getBot().getPluginManager().getPlugins().values()){
p.getPlugin().disablePlugin(DisableReason.SHUTDOWN);
}

String id = (code==0) ? "LOG": "CRASH";

getBot().getLogger().dumpLog(id, UtilityFunctions.dateString());
Expand Down
12 changes: 12 additions & 0 deletions src/net/cloudsbots/archseriest/archt5/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static void main(String[] args){
plugin.getPlugin().setPackaging(plugin);

PluginManager plgManager = new PluginManager(plugin);

Bot.getBot().setPluginManager(plgManager);

plugin.getPlugin().enablePlugin();
Expand Down Expand Up @@ -80,6 +81,17 @@ public static void main(String[] args){

new CallableEvent(plugin, "bot.ready", new Pair<>("VERIF", Bot.getBot().getSession().toString())).call(EventChannel.SYSTEM, false);

try {
if(!new File("./plugins/").exists()){ new File("./plugins/").mkdir(); }
File plugindir = new File("./plugins/");
for(File file: plugindir.listFiles()){
if(file.getName().endsWith(".jar")){
Bot.getBot().getPluginManager().loadPlugin(file.getPath());
}
}
} catch (NullPointerException err){
Logger.getLogger().logRuntimeError("Bootloader/LoadPlugins", err.getMessage());
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
import javafx.util.Pair;
import net.cloudsbots.archseriest.archt5.Bot;
import net.cloudsbots.archseriest.archt5.Main;
import net.cloudsbots.archseriest.archt5.behaviorchunks.CoreBehaviors.BehaviorCommandProcess;
import net.cloudsbots.archseriest.archt5.behaviorchunks.CoreBehaviors.BehaviorNotFound;
import net.cloudsbots.archseriest.archt5.components.Validator;
import net.cloudsbots.archseriest.archt5.events.CallableEvent;
import net.cloudsbots.archseriest.archt5.events.EventChannel;
import net.cloudsbots.archseriest.archt5.exceptions.BehaviorNotFoundException;
import net.cloudsbots.archseriest.archt5.exceptions.PermissionDeniedException;
import net.cloudsbots.archseriest.archt5.plugin.Plugin;
import net.cloudsbots.archseriest.archt5.plugin.PluginPackaging;
import net.cloudsbots.archseriest.archt5.plugin.PluginState;
import net.cloudsbots.archseriest.archt5.plugin.SystemPlugin;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class BehaviorManager {

Expand All @@ -23,6 +29,31 @@ public final class BehaviorManager {

public BehaviorManager(String pass){ this.pass = pass; }

public void defaultBehavior(Plugin plugin, String name, String pass){
if(name.toLowerCase().equals("cmd_pcs")){
behaviors.put(name.toLowerCase(), new BehaviorCommandProcess());
} else {
if(behaviors.containsKey(name.toLowerCase())){
Behavior b = behaviors.get(name.toLowerCase());
if(b.isProtected()){
if(plugin instanceof SystemPlugin){
behaviors.put(name.toLowerCase(), new BehaviorNotFound());
} else if(plugin == behaviorParents.get(name.toLowerCase()).getPlugin()) {
behaviors.put(name.toLowerCase(), new BehaviorNotFound());
} else {
if(b.unlock(pass)){
behaviors.put(name.toLowerCase(), new BehaviorNotFound());
} else {
throw new PermissionDeniedException("You cannot default a protected behavior.");
}
}
} else {
behaviors.put(name.toLowerCase(), new BehaviorNotFound());
}
}
}
}

public void registerBehavior(String name, Behavior behavior, PluginPackaging plugin){ registerBehavior(name, behavior, plugin, ""); }

public boolean registerBehavior(String name, Behavior behavior, PluginPackaging plugin, String password){
Expand Down Expand Up @@ -65,6 +96,16 @@ public Behavior runBehavior(String name, Object... params){
}
}

public List<String> getPluginBehaviors(Plugin plugin){
List<String> list = new ArrayList<>();
for(Map.Entry<String, PluginPackaging> entry:behaviorParents.entrySet()){
if(entry.getValue().getPlugin() == plugin){
list.add(entry.getKey());
}
}
return list;
}

public static BehaviorManager getBehaviorManager(){
return Bot.getBot().getBehaviorManager();
}
Expand Down
20 changes: 17 additions & 3 deletions src/net/cloudsbots/archseriest/archt5/commands/CommandManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
import net.cloudsbots.archseriest.archt5.plugin.PluginPackaging;
import net.dv8tion.jda.core.entities.Message;

import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.*;

public class CommandManager {

Expand Down Expand Up @@ -53,6 +51,22 @@ public void unregisterCommand(String name){
}
}

public void unregisterAll(Plugin plugin){
Iterator<Map.Entry<String, PluginPackaging>> i = commandOwnership.entrySet().iterator();
List<String> keys = new ArrayList<>();
while(i.hasNext()) {
Map.Entry<String, PluginPackaging> pair = i.next();
if (pair.getValue().getPlugin() == plugin) {
keys.add(pair.getKey());
}
}
for(String key:keys){
cmdmap.remove(key.toLowerCase());
commandOwnership.remove(key);
}

}

//TODO: Add a plugin based unregister which can unregister if you supply the plugin (Protects System)
//Do not remove #unregisterCommand(String name); as that's useful for deeper plugins and isn't too harmful due to hardcodeds

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class Logger implements Thread.UncaughtExceptionHandler{

@Override
public void uncaughtException(Thread t, Throwable e) {
logRuntimeError("Exception", e.getMessage());
logRuntimeError("Exception/"+e.getClass().getTypeName(), e.getMessage());
for (StackTraceElement element: e.getStackTrace()) {
logAppend(element.getClassName()+"."+element.getMethodName()+":Line "+element.getLineNumber(), " >> ");
}
Expand Down
119 changes: 85 additions & 34 deletions src/net/cloudsbots/archseriest/archt5/config/ConfigurationFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.io.*;
import java.util.*;
import java.util.regex.Pattern;

public class ConfigurationFile {

Expand All @@ -29,28 +30,75 @@ public ConfigurationFile(File file) throws IOException, InvalidFormatException{
if(!cfgfile.getName().endsWith(".cfgp")){ throw new InvalidFormatException("Invalid file format. Please select a .cfgp file."); }
Reader reader = new FileReader(file);
BufferedReader read = new BufferedReader(reader);
readFile(read);
}

/**
* Reads a config under the ConfigPlus format, creating a map
* of keys and object values. These values can be converted by
* the specified format in the config.
*
* @param read Reader Object which points towards config
* @throws InvalidFormatException - Config Has a format error
*/
public ConfigurationFile(BufferedReader read) throws IOException, InvalidFormatException{
readFile(read);
}

/**
* Just like {@see #Constructer(File, String)} but
* it does a few checks to ensure that some fields are
* present in the config. Else it returns a InvalidConfigException
*
* @param file File Object which points towards config
* @param requiredfields List of fields which are required in the config. Throws an error if one or more aren't present
* @throws IOException
* @throws InvalidFormatException
* @throws InvalidConfigException Thrown if a required field is not present in the loaded config.
*/
public ConfigurationFile(File file, String ... requiredfields) throws IOException, InvalidFormatException, InvalidConfigException{
this(file);
for (String r:requiredfields) { if(!getConfig().containsKey(r)){ throw new InvalidConfigException("Missing Field Error - Required Field '"+r+"' was not found in config '"+getConfigFile().getName()+"' ("+getConfig().keySet().toString()+")"); } }
}

public ConfigurationFile(BufferedReader reader, String ... requiredfields) throws IOException, InvalidFormatException, InvalidConfigException{
this(reader);
for (String r:requiredfields) { if(!getConfig().containsKey(r)){ throw new InvalidConfigException("Missing Field Error - Required Field '"+r+"' was not found in config '"+getConfigFile().getName()+"' ("+getConfig().keySet().toString()+")"); } }
}

private void readFile(BufferedReader read) throws IOException, InvalidFormatException{
Iterator<String> cfglines = read.lines().iterator();
int linen = -1;
int linen = 0;
while (cfglines.hasNext()){
String line = cfglines.next();
linen++;
if(line.length() == 0){ continue; }
if(line.startsWith("//")){
comments.add(line);
} else {
if(line.contains("=")){
String[] components = line.split("=", 2);
if(components[0].length() == 0) {throw new InvalidFormatException("Syntax Violation Error - The pair key cannot be null. [Line "+String.valueOf(linen)+"]"); }
if(components[1].length() == 0) {throw new InvalidFormatException("Syntax Violation Error - The pair value cannot be null. [Line "+String.valueOf(linen)+"]"); }
String[] components = line.split(Pattern.quote("="), 2);
Bot.getBot().getLogger().logInfo("Debug/Config", "Whole = "+line, "Components = "+Arrays.asList(components).toString());

if(components[0].length() == 0) {
read.close();
throw new InvalidFormatException("Syntax Violation Error - The pair key cannot be null. [Line "+String.valueOf(linen)+"]");
}
if(components[1].length() == 0) {
read.close();
throw new InvalidFormatException("Syntax Violation Error - The pair value cannot be null. [Line "+String.valueOf(linen)+"]");
}
if(components[0].startsWith("[")){
if (!components[0].contains("]")) {throw new InvalidFormatException("Syntax Error - Expected ']' [Line "+String.valueOf(linen)+"]"); }
String type = components[0].substring(1).split("]")[0].toLowerCase();
if (!components[0].contains("]")) {
read.close();
throw new InvalidFormatException("Syntax Error - Expected ']' [Line "+String.valueOf(linen)+"]");
}
String type = components[0].substring(1).split(Pattern.quote("]"))[0].toLowerCase();
String prefix = "[" + type + "]";
if(components[0].substring(prefix.length()).length() == 0){ throw new InvalidFormatException("Syntax Violation Error - The pair value cannot be null. [Line "+String.valueOf(linen)+"]"); }
if(components[0].substring(prefix.length()).length() == 0){
read.close();
throw new InvalidFormatException("Syntax Violation Error - The pair value cannot be null. [Line "+String.valueOf(linen)+"]");
}
String content = components[0].substring(prefix.length());

Bot.getBot().getLogger().logInfo("Debug/Config", "Whole = "+line, "Components = "+components.toString(), "Type = "+type, "Key = "+content);

if (type.equals("string")){
config.put(content, components[1]);
} else if(type.equals("int")){
Expand All @@ -60,43 +108,46 @@ public ConfigurationFile(File file) throws IOException, InvalidFormatException{
} else if(type.equals("uint")){
config.put(content, Integer.parseUnsignedInt(components[1]));
} else if(type.equals("array")){
config.put(content, components[1].split(","));
config.put(content, components[1].split(Pattern.quote(",")));
} else if(type.equals("map")){
String[] pairs = components[1].split(",");
String[] pairs = components[1].split(Pattern.quote(","));
Map<String, String> map = new HashMap<>();
for(String pair: pairs){
if(!pair.contains(":")){ throw new InvalidFormatException("Syntax Error - Expected ':' (Map Type requires the format 'key1:value1,key2:value2,key3:value3' [Line "+String.valueOf(linen)+"]"); }
String[] keyval = pair.split(pair, 2);
if(keyval[0].length() == 0){throw new InvalidFormatException("Syntax Violation Error - A map key cannot be null. [Line "+String.valueOf(linen)+"]"); }
if(keyval[1].length() == 0){throw new InvalidFormatException("Syntax Violation Error - A map value cannot be null. [Line "+String.valueOf(linen)+"]"); }
if(!pair.contains(":")){
read.close();
throw new InvalidFormatException("Syntax Error - Expected ':' (Map Type requires the format 'key1:value1,key2:value2,key3:value3' [Line "+String.valueOf(linen)+"]");
}
String[] keyval = pair.split(Pattern.quote(":"), 2);
if(keyval[0].length() == 0){
read.close();
throw new InvalidFormatException("Syntax Violation Error - A map key cannot be null. [Line "+String.valueOf(linen)+"]");
}
if(keyval[1].length() == 0){
read.close();
throw new InvalidFormatException("Syntax Violation Error - A map value cannot be null. [Line "+String.valueOf(linen)+"]");
}
map.put(keyval[0], keyval[1]);
}
config.put(components[0], map);
} else if(type.equals("json")){
read.close();
throw new InvalidFormatException("Type Error - The JSON format is not yet supported in version "+ Bot.MILESTONE_VERSION+" (Build "+ Bot.BUILD_VERSION+") [Line "+String.valueOf(linen)+"]");
} else { throw new InvalidFormatException("Type Error - '"+type+"' is not a supported config entry conversion type. [Line "+String.valueOf(linen)+"]"); }
} else {
read.close();
throw new InvalidFormatException("Type Error - '"+type+"' is not a supported config entry conversion type. [Line "+String.valueOf(linen)+"]");
}
} else { config.put(components[0], components[1]); }
} else { throw new InvalidFormatException("Syntax Error - Expected '=' [Line "+String.valueOf(linen)+"]" ); }
} else {
continue;
}
}
}
}

/**
* Just like {@see #Constructer(File, String)} but
* it does a few checks to ensure that some fields are
* present in the config. Else it returns a InvalidConfigException
*
* @param file File Object which points towards config
* @param requiredfields List of fields which are required in the config. Throws an error if one or more aren't present
* @throws IOException
* @throws InvalidFormatException
* @throws InvalidConfigException Thrown if a required field is not present in the loaded config.
*/
public ConfigurationFile(File file, String ... requiredfields) throws IOException, InvalidFormatException, InvalidConfigException{
this(file);
for (String r:requiredfields) { if(!getConfig().containsKey(r)){ throw new InvalidConfigException("Missing Field Error - Required Field '"+r+"' was not found in config '"+getConfigFile().getName()+"' ("+getConfig().keySet().toString()+")"); } }
read.close();

}


public HashMap<String, Object> getConfig() { return config; }
public List<String> getConfigComments() { return comments; }
public File getConfigFile() { return cfgfile; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.cloudsbots.archseriest.archt5.exceptions;

public class BehaviorNotFoundException extends RuntimeException {

public BehaviorNotFoundException(String message){
super(message);
}

}
18 changes: 17 additions & 1 deletion src/net/cloudsbots/archseriest/archt5/plugin/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

import net.cloudsbots.archseriest.archt5.Bot;

import java.util.List;

public class Plugin {

private static Plugin plugin = new Plugin();

private PluginPackaging packaging;
private boolean hasPackagingSet = false;

private Bot bot;
private boolean hasBotSet = false;

protected void onEnable(){ }
protected void onDisable(DisableReason cause){ }

Expand All @@ -19,6 +24,12 @@ public final void enablePlugin(){

public final void disablePlugin(DisableReason cause){
//TODO: Unregistering commands + Behaviors
List<String> behaviorids = Bot.getBot().getBehaviorManager().getPluginBehaviors(this);
for(String id: behaviorids){
Bot.getBot().getBehaviorManager().defaultBehavior(this, id, "");
}
Bot.getBot().getCommandManager().unregisterAll(this);

Bot.getBot().getPluginManager().setPluginState(this, PluginState.DISABLED);
onDisable(cause);
}
Expand All @@ -33,6 +44,11 @@ public void setPackaging(PluginPackaging packaging){
}
}


public void setBot(Bot bot){
if(!hasBotSet) {
this.bot = bot;
hasBotSet = true;
}
}

}

0 comments on commit bab9879

Please sign in to comment.