diff --git a/.gitignore b/.gitignore
index b179efba..8d469572 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,6 @@
/bin/
.project
.classpath
-.metadata
\ No newline at end of file
+.metadata
+.idea/
+*.iml
diff --git a/README.md b/README.md
index 96171085..887f48c3 100644
--- a/README.md
+++ b/README.md
@@ -65,11 +65,12 @@ Similar to Game Fixes, but distinct in that the intent here is on hacks that _tu
or alter existing mechanics without fully disabling them or without fixing them.
Things like altering armor damage reduction or tool impact would be good fits.
-### HackBot
+### ~~HackBot~~
-An experimental module whose complexity is approaching divorce from SAH, this is
+(Removed in 1.2.4)
+~~An experimental module whose complexity is approaching divorce from SAH, this is
a bit of mid-work code that allows operators to define static Bots that show up
-like "real" players but aren't.
+like "real" players but aren't.~~
### Introbook
@@ -84,12 +85,13 @@ Host of the `/invsee` command, gives insight into active player inventory, armor
health and more. I hope / intend to add another portion to this that allows online
and offline inventory management via `/invmod` but this is as of now not started.
-### InvisibleFix and InvisibleFixTwo
+### ~~InvisibleFix and InvisibleFixTwo~~
-My hope is to remove these in time, but for 1.9 and 1.10 minecraft players
+(Removed in 1.3.0)
+~~My hope is to remove these in time, but for 1.9 and 1.10 minecraft players
go invisible all the time. Both of these hacks use different approaches to help
preserve the visiblity of players. The second hack is the more invasive, sending
-explicit location packets when the situation indicates its usefulness.
+explicit location packets when the situation indicates its usefulness.~~
### NewfriendAssist
@@ -107,6 +109,23 @@ are actively breaking reinforced containers.
This one is pretty Devoted iteration 3 specific. Allows tracking server wide of
all breaks or builds under a specific y level.
+### ToggleLamp
+
+A solid piece of contributed code, this hack lets redstone lamps be used as
+clickable-on, clickable-off light sources without additional redstone infrastructure.
+
+### HumbugBatchOne
+
+A new BasicHack (thanks Maxopoly) which encompasses a number of previously unincluded
+Humbug gameplay modifications. Specifically, sheep wool dying, anvil use, enchanting table use,
+cauldrons sourcing infinite water, disabling ender dragon, disabling iron farms,
+disabling ender crystal damage, disable mining fatigue, and equipping banners as hats.
+
+
+### PortalSpawnModifier
+
+Another new BasicHack which allows control of the spawn of creatures rate from nether portals
+
### TimingsHack
This is mature enough to be its own plugin now, but for the moment I'm leaving it in
diff --git a/pom.xml b/pom.xml
index 3a8d0adf..c5fff837 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.programmerdan.minecraft
SimpleAdminHacks
jar
- 1.2.4
+ 1.3.0
SimpleAdminHacks
https://github.com/DevotedMC/SimpleAdminHacks
@@ -89,10 +89,6 @@
spigot-repo
https://hub.spigotmc.org/nexus/content/groups/public/
-
- byteflux-repo
- http://repo.byteflux.net/repository/maven-snapshots/
-
dmulloy2-repo
http://repo.dmulloy2.net/content/groups/public/
@@ -107,7 +103,7 @@
org.spigotmc
spigot
- 1.12.2-R0.1-SNAPSHOT
+ 1.14.4-R0.1-SNAPSHOT
provided
@@ -137,24 +133,24 @@
com.comphenix.protocol
ProtocolLib-API
- 4.3.0
+ 4.4.0
vg.civcraft.mc.namelayer
NameLayer
- 2.11.0
+ 2.12.0
provided
vg.civcraft.mc.citadel
Citadel
- 3.9.0
+ 4.0.1
provided
vg.civcraft.mc.civmodcore
CivModCore
- 1.6.0
+ 1.7.8
provided
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/BasicHack.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/BasicHack.java
new file mode 100644
index 00000000..4324ad9e
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/BasicHack.java
@@ -0,0 +1,76 @@
+package com.programmerdan.minecraft.simpleadminhacks;
+
+import java.lang.reflect.Field;
+import java.util.logging.Level;
+
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+
+/**
+ * Utility automating a lot of the boiler plate required by SimpleHack and thus allowing easier creation
+ * of small hacks
+ *
+ */
+public abstract class BasicHack extends SimpleHack implements Listener {
+
+ public BasicHack(SimpleAdminHacks plugin, BasicHackConfig config) {
+ super(plugin, config);
+ }
+
+ @Override
+ public void registerListeners() {
+ SimpleAdminHacks.instance().registerListener(this);
+ }
+
+ @Override
+ public void registerCommands() {
+ //override in subclass if needed
+ }
+
+ @Override
+ public void dataBootstrap() {
+ //override in subclass if needed
+ }
+
+ @Override
+ public void unregisterListeners() {
+ HandlerList.unregisterAll(this);
+
+ }
+
+ @Override
+ public void unregisterCommands() {
+ //override in subclass if needed
+ }
+
+ @Override
+ public void dataCleanup() {
+ //override in subclass if needed
+
+ }
+
+ @Override
+ public String status() {
+ StringBuilder genStatus = new StringBuilder();
+ genStatus.append(this.getClass().getSimpleName());
+ genStatus.append(" is ");
+ if (config == null || !config.isEnabled()) {
+ genStatus.append("disabled");
+ return genStatus.toString();
+ }
+ genStatus.append("enabled\n");
+ for(Field field : this.getClass().getDeclaredFields()) {
+ genStatus.append(field.getName());
+ genStatus.append(" = ");
+ field.setAccessible(true);
+ try {
+ genStatus.append(field.get(this));
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ plugin().log(Level.WARNING, "Failed to read field", e);
+ }
+ genStatus.append('\n');
+ }
+ return genStatus.toString();
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/BasicHackConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/BasicHackConfig.java
new file mode 100644
index 00000000..ac5cf685
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/BasicHackConfig.java
@@ -0,0 +1,20 @@
+package com.programmerdan.minecraft.simpleadminhacks;
+
+import org.bukkit.configuration.ConfigurationSection;
+
+public class BasicHackConfig extends SimpleHackConfig {
+
+ public BasicHackConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
+ super(plugin, base);
+ }
+
+ @Override
+ protected void wireup(ConfigurationSection config) {
+ //not needed
+ }
+
+ public static BasicHackConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
+ return new BasicHackConfig(plugin, config);
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/CommandListener.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/CommandListener.java
index da78b707..da636738 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/CommandListener.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/CommandListener.java
@@ -67,7 +67,7 @@ private boolean showHacks(CommandSender sender) {
sb.append(ChatColor.WHITE).append("List of hacks:\n");
- for (SimpleHack> hack : plugin.getHacks()) {
+ for (SimpleHack> hack : plugin.getHackManager().getHacks()) {
sb.append(" ")
.append(ChatColor.AQUA).append(hack.getName())
.append(ChatColor.WHITE).append(": ");
@@ -87,7 +87,7 @@ private boolean showHacks(CommandSender sender) {
* Internal utility to get a hack from name.
*/
private SimpleHack> findHack(String hackName) {
- for (SimpleHack> candidate : plugin.getHacks()) {
+ for (SimpleHack> candidate : plugin.getHackManager().getHacks()) {
if (candidate.getName().equals(hackName)) {
return candidate;
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/HackManager.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/HackManager.java
new file mode 100644
index 00000000..0d1ab068
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/HackManager.java
@@ -0,0 +1,213 @@
+package com.programmerdan.minecraft.simpleadminhacks;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+
+import org.bukkit.configuration.ConfigurationSection;
+
+import com.google.common.reflect.ClassPath;
+import com.programmerdan.minecraft.simpleadminhacks.autoload.AutoLoad;
+
+public class HackManager {
+
+ private SimpleAdminHacks plugin;
+ private List> hacks;
+
+ public HackManager(SimpleAdminHacks plugin) {
+ this.plugin = plugin;
+ this.hacks = new LinkedList<>();
+ reloadHacks();
+ }
+
+ public void reloadHacks() {
+ // Now load all the Hacks and register.
+ ConfigurationSection hackConfigs = plugin.getConfig().getConfigurationSection("hacks");
+ try {
+ ClassPath getSamplersPath = ClassPath.from(plugin.exposeClassLoader());
+
+ for (ClassPath.ClassInfo clsInfo : getSamplersPath
+ .getTopLevelClassesRecursive("com.programmerdan.minecraft.simpleadminhacks.hacks")) {
+ try {
+ Class> clazz = clsInfo.load();
+ if (clazz != null && SimpleHack.class.isAssignableFrom(clazz)) {
+ plugin.log(Level.INFO,
+ "Found a hack class {0}, attempting to find a generating method and constructor",
+ clazz.getName());
+ ConfigurationSection hackConfig = hackConfigs.getConfigurationSection(clazz.getSimpleName());
+ SimpleHackConfig hackingConfig = null;
+ if (hackConfig != null) {
+ try {
+ Method genBasic = clazz.getMethod("generate", SimpleAdminHacks.class,
+ ConfigurationSection.class);
+ hackingConfig = (SimpleHackConfig) genBasic.invoke(null, plugin, hackConfig);
+ } catch (IllegalAccessException failure) {
+ plugin.log(Level.WARNING,
+ "Creating configuration for hack {0} failed, illegal access failure: {1}",
+ clazz.getName(), failure.toString());
+ } catch (IllegalArgumentException failure) {
+ plugin.log(Level.WARNING,
+ "Creating configuration for hack {0} failed, illegal argument failure: {1}",
+ clazz.getName(), failure.toString());
+ } catch (InvocationTargetException failure) {
+ plugin.log(Level.WARNING,
+ "Creating configuration for hack {0} failed, invocation target failure",
+ clazz.getName());
+ }
+ } else {
+ plugin.log(Level.INFO, "Hack for {0} found but no configuration, skipping.",
+ clazz.getSimpleName());
+ }
+
+ if (hackingConfig != null) {
+ plugin.log(Level.INFO, "Configuration for Hack {0} found, instance: {1}",
+ clazz.getSimpleName(), hackingConfig.toString());
+ SimpleHack> hack = null;
+ try {
+ Constructor> constructBasic = clazz.getConstructor(SimpleAdminHacks.class,
+ hackingConfig.getClass());
+ hack = (SimpleHack>) constructBasic.newInstance(plugin, hackingConfig);
+ plugin.log(Level.INFO, "Created a new Hack of type {0}", clazz.getSimpleName());
+ } catch (InvalidConfigException ice) {
+ plugin.log(Level.WARNING, "Failed to activate {0} hack, configuration failed",
+ clazz.getSimpleName());
+ } catch (Exception e) {
+ plugin.log(Level.WARNING, "Failed to activate {0} hack, configuration failed: {1}",
+ clazz.getSimpleName(), e.getMessage());
+ }
+
+ if (hack == null) {
+ plugin.log(Level.WARNING, "Failed to create a Hack of type {0}", clazz.getSimpleName());
+ } else {
+ register(hack);
+ plugin.log(Level.INFO, "Registered a new hack: {0}", clazz.getSimpleName());
+ }
+ } else {
+ plugin.log(Level.INFO, "Configuration generation for Hack {0} failed, skipping.",
+ clazz.getSimpleName());
+ }
+ }
+ } catch (NoClassDefFoundError e) {
+ plugin.log(Level.INFO, "Unable to load discovered class {0} due to dependency failure",
+ clsInfo.getName());
+ } catch (Exception e) {
+ plugin.log(Level.WARNING, "Failed to complete hack discovery of {0}: {1}", clsInfo.getName(), e.toString());
+ }
+ }
+ } catch (Exception e) {
+ plugin.log(Level.WARNING, "Failed to complete hack registration");
+ }
+ // Warning if no hacks.
+ if (hacks.isEmpty()) {
+ plugin.log(Level.WARNING, "No hacks enabled.");
+ return;
+ }
+ // Boot up the hacks.
+ List> iterList = new ArrayList<>(hacks);
+ for (SimpleHack> hack : iterList) {
+ try {
+ populateParameter(hack);
+ hack.enable();
+ } catch (NoClassDefFoundError err) {
+ plugin.log(Level.WARNING, "Unable to activate hack {0}, missing dependency: {1}", hack.getName(),
+ err.getMessage());
+ unregister(hack);
+ } catch (Exception e) {
+ plugin.log(Level.WARNING, "Unable to activate hack {0}, unrecognized error: {1}", hack.getName(),
+ e.getMessage());
+ plugin.log(Level.WARNING, "Full stack trace: ", e);
+ unregister(hack);
+ }
+ }
+ }
+
+ public void disableAllHacks() {
+ for (SimpleHack> hack : hacks) {
+ try {
+ hack.disable();
+ } catch (NoClassDefFoundError err) {
+ plugin.log(Level.WARNING, "Unable to cleanly disable hack {0}, missing dependency: {1}", hack.getName(),
+ err.getMessage());
+ } catch (Exception e) {
+ plugin.log(Level.WARNING, "Unable to cleanly disable hack {0}, unrecognized error: {1}", hack.getName(),
+ e.getMessage());
+ plugin.log(Level.WARNING, "Full stack trace: ", e);
+ }
+ }
+ hacks.clear();
+ }
+
+ private void populateParameter(SimpleHack extends SimpleHackConfig> hack) {
+ Class> hackClass = hack.getClass();
+ ConfigurationSection config = hack.config().getBase();
+ for (Field field : hackClass.getDeclaredFields()) {
+ AutoLoad autoLoad = field.getAnnotation(AutoLoad.class);
+ if (autoLoad == null) {
+ continue;
+ }
+ String identifier;
+ if (autoLoad.id().equals("")) {
+ identifier = field.getName();
+ } else {
+ identifier = autoLoad.id();
+ }
+ Class> clazz;
+ if (field.getType().getName().split("\\.").length == 1) {
+ //unwrap primitives
+ clazz = Array.get(Array.newInstance(field.getType(),1),0).getClass();
+ }
+ else {
+ clazz = field.getType();
+ }
+ Object value;
+ try {
+ value = config.getObject(identifier, clazz, null);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Hack " + hackClass.getSimpleName() + " failed to read parameter "
+ + identifier, e);
+ }
+ if (value == null) {
+ plugin.log(Level.WARNING, "Hack {0} had no value for option {1}", hackClass.getSimpleName(), identifier);
+ continue;
+ }
+ field.setAccessible(true);
+ try {
+ field.set(hack, value);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new IllegalStateException(field.getClass().getSimpleName() + " in " + hackClass.getSimpleName()
+ + " could not be set " + e.toString());
+ }
+ plugin.log(Level.INFO, "Loaded {0} = {1}", identifier, value);
+ }
+ }
+
+ /**
+ * Registers a new SimpleHack.
+ */
+ void register(SimpleHack> hack) {
+ hacks.add(hack);
+ }
+
+ /**
+ * Unregisters an existing SimpleHack.
+ */
+ void unregister(SimpleHack> hack) {
+ hacks.remove(hack);
+ }
+
+ /**
+ * Returns a wrapped version of hacks preventing external removal but allowing
+ * interaction with the hacks.
+ */
+ public List> getHacks() {
+ return Collections.unmodifiableList(hacks);
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/InvalidConfigException.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/InvalidConfigException.java
index e9a1d495..9faa086b 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/InvalidConfigException.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/InvalidConfigException.java
@@ -2,6 +2,8 @@
public class InvalidConfigException extends RuntimeException {
+ private static final long serialVersionUID = 7614429135140646756L;
+
public InvalidConfigException(String message) {
super(message);
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleAdminHacks.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleAdminHacks.java
index 3e98eab8..c2fa4101 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleAdminHacks.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleAdminHacks.java
@@ -1,13 +1,6 @@
package com.programmerdan.minecraft.simpleadminhacks;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
@@ -17,23 +10,21 @@
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.PluginCommand;
-import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
-import com.google.common.reflect.ClassPath;
-
/**
* Wrapper for simple admin hacks, each doing a thing and each configurable.
*
* @author ProgrammerDan
*/
public class SimpleAdminHacks extends JavaPlugin {
+
private static SimpleAdminHacks plugin;
private SimpleAdminHacksConfig config;
- private List> hacks;
+ private HackManager hackManager;
/**
* No-op constructor
@@ -47,7 +38,6 @@ public SimpleAdminHacks() {
*/
public void onEnable() {
SimpleAdminHacks.plugin = this;
- this.hacks = new LinkedList>();
// Config bootstrap
this.saveDefaultConfig();
@@ -60,139 +50,21 @@ public void onEnable() {
this.setEnabled(false);
return;
}
-
-
- // Now load all the Hacks and register.
- ConfigurationSection hackConfigs = this.getConfig().getConfigurationSection("hacks");
- try {
- ClassPath getSamplersPath = ClassPath.from(this.getClassLoader());
-
- for (ClassPath.ClassInfo clsInfo : getSamplersPath.getTopLevelClasses("com.programmerdan.minecraft.simpleadminhacks.hacks")) {
- try {
- Class> clazz = clsInfo.load();
- if (clazz != null && SimpleHack.class.isAssignableFrom(clazz)) {
- log(Level.INFO, "Found a hack class {0}, attempting to find a generating method and constructor", clazz.getName());
- ConfigurationSection hackConfig = hackConfigs.getConfigurationSection(clazz.getSimpleName());
- SimpleHackConfig hackingConfig = null;
- if (hackConfig != null) {
- try {
- Method genBasic = clazz.getMethod("generate", SimpleAdminHacks.class, ConfigurationSection.class);
- hackingConfig = (SimpleHackConfig) genBasic.invoke(null, this, hackConfig);
- } catch (IllegalAccessException failure) {
- log(Level.WARNING, "Creating configuration for hack {0} failed, illegal access failure", clazz.getName());
- } catch (IllegalArgumentException failure) {
- log(Level.WARNING, "Creating configuration for hack {0} failed, illegal argument failure", clazz.getName());
- } catch (InvocationTargetException failure) {
- log(Level.WARNING, "Creating configuration for hack {0} failed, invocation target failure", clazz.getName());
- }
- } else {
- log(Level.INFO, "Hack for {0} found but no configuration, skipping.", clazz.getSimpleName());
- }
-
- if (hackingConfig != null) {
- log(Level.INFO, "Configuration for Hack {0} found, instance: {1}", clazz.getSimpleName(), hackingConfig.toString());
- SimpleHack> hack = null;
- try {
- Constructor> constructBasic = clazz.getConstructor(SimpleAdminHacks.class, hackingConfig.getClass());
- hack = (SimpleHack>) constructBasic.newInstance(this, hackingConfig);
- log(Level.INFO, "Created a new Hack of type {0}", clazz.getSimpleName());
- } catch (InvalidConfigException ice) {
- log(Level.WARNING, "Failed to activate {0} hack, configuration failed", clazz.getSimpleName());
- } catch (Exception e) {
- log(Level.WARNING, "Failed to activate {0} hack, configuration failed: {1}", clazz.getSimpleName(), e.getMessage());
- }
-
- if (hack == null) {
- log(Level.WARNING, "Failed to create a Hack of type {0}", clazz.getSimpleName());
- } else {
- register(hack);
- log(Level.INFO, "Registered a new hack: {0}", clazz.getSimpleName());
- }
- } else {
- log(Level.INFO, "Configuration generation for Hack {0} failed, skipping.", clazz.getSimpleName());
- }
- }
- } catch (NoClassDefFoundError e) {
- log(Level.INFO, "Unable to load discovered class {0} due to dependency failure", clsInfo.getName());
- } catch (Exception e) {
- log(Level.WARNING, "Failed to complete hack discovery {0}", clsInfo.getName());
- }
- }
- } catch (Exception e) {
- log(Level.WARNING, "Failed to complete hack registration");
- }
-
-
- // Warning if no hacks.
- if (hacks == null || hacks.size() == 0) {
- log(Level.WARNING, "No hacks enabled.");
- return;
- }
-
- // Boot up the hacks.
- List> iterList = new ArrayList>(hacks);
- for (SimpleHack> hack : iterList) {
- try {
- hack.enable();
- } catch (NoClassDefFoundError err) {
- log(Level.WARNING, "Unable to activate hack {0}, missing dependency: {1}", hack.getName(), err.getMessage());
- unregister(hack);
- } catch (Exception e) {
- log(Level.WARNING, "Unable to activate hack {0}, unrecognized error: {1}", hack.getName(), e.getMessage());
- log(Level.WARNING, "Full stack trace: ", e);
- unregister(hack);
- }
- }
-
+ this.hackManager = new HackManager(this);
this.registerCommand("hacks", new CommandListener(this));
}
/**
* Forwards disable to hacks, clears instance and static variables
*/
+ @Override
public void onDisable() {
- if (hacks == null) return;
- for (SimpleHack> hack : hacks) {
- try {
- hack.disable();
- } catch (NoClassDefFoundError err) {
- log(Level.WARNING, "Unable to cleanly disable hack {0}, missing dependency: {1}", hack.getName(), err.getMessage());
- } catch (Exception e) {
- log(Level.WARNING, "Unable to cleanly disable hack {0}, unrecognized error: {1}", hack.getName(), e.getMessage());
- log(Level.WARNING, "Full stack trace: ", e);
- }
- }
- hacks.clear();
- hacks = null;
+ hackManager.disableAllHacks();
+ hackManager = null;
config = null;
SimpleAdminHacks.plugin = null;
}
- /**
- * Registers a new SimpleHack.
- */
- public void register(SimpleHack> hack) {
- if (hacks != null) {
- hacks.add(hack);
- }
- }
-
- /**
- * Unregisters an existing SimpleHack.
- */
- public void unregister(SimpleHack> hack) {
- if (hacks != null) {
- hacks.remove(hack);
- }
- }
-
- /**
- * Returns a wrapped version of hacks preventing external removal but allowing interaction with the hacks.
- */
- public List> getHacks() {
- return Collections.unmodifiableList(hacks);
- }
-
/**
* Returns the psuedo-singleton instance of this plugin.
*/
@@ -356,5 +228,12 @@ public void registerCommand(String command, CommandExecutor executor) {
public ClassLoader exposeClassLoader() {
return this.getClassLoader();
}
+
+ /**
+ * @return Manager holding hack instances
+ */
+ public HackManager getHackManager() {
+ return hackManager;
+ }
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleHack.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleHack.java
index a6c25347..74e42350 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleHack.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/SimpleHack.java
@@ -149,7 +149,7 @@ public SimpleHackConfig config() {
*/
@Override
public boolean equals(Object e) {
- if (e != null && e instanceof SimpleHack) {
+ if (e instanceof SimpleHack) {
SimpleHack> f = (SimpleHack>) e;
if (f.config != null && this.config != null && f.config.getName().equals(this.config.getName())) {
return true;
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/autoload/AutoLoad.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/autoload/AutoLoad.java
new file mode 100644
index 00000000..6f7acf09
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/autoload/AutoLoad.java
@@ -0,0 +1,31 @@
+package com.programmerdan.minecraft.simpleadminhacks.autoload;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface AutoLoad {
+
+ //Thanks Angelia
+
+ /**
+ * The identifier used for this option when reading it from the hacks config yaml section. If
+ * this is not set, the variable name will be used
+ *
+ * @return Identifier used for this option or an empty string if the variable
+ * name should be used
+ */
+ String id() default "";
+
+ /**
+ * Is the parameter required? If set to true, an exception will be thrown if no
+ * default is specified and the option is not specified in the config
+ *
+ * @return Whether this option is required
+ */
+ boolean isRequired() default true;
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/AutoRespawnConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/AutoRespawnConfig.java
new file mode 100644
index 00000000..07449104
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/AutoRespawnConfig.java
@@ -0,0 +1,64 @@
+package com.programmerdan.minecraft.simpleadminhacks.configs;
+
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
+import org.bukkit.configuration.ConfigurationSection;
+
+import java.util.logging.Level;
+
+public class AutoRespawnConfig extends SimpleHackConfig {
+
+ private static final long defaultRespawnDelay = 1000 * 60 * 5; // Five minutes
+ private static final long defaultLoginRespawnDelay = 0; // Instantly
+
+ private long respawnDelay;
+ private long loginRespawnDelay;
+ private String[] respawnQuotes;
+
+ public AutoRespawnConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
+ super(plugin, base);
+ }
+
+ @Override
+ protected void wireup(ConfigurationSection config) {
+ this.respawnDelay = config.getLong("respawnDelay", defaultRespawnDelay);
+ if (this.respawnDelay <= 0) {
+ plugin().log(Level.WARNING, "\tAuto Respawn delay has an invalid value, defaulting.");
+ this.respawnDelay = defaultRespawnDelay;
+ }
+ else {
+ plugin().log(Level.INFO, "\tAuto Respawn delay set to: " + this.respawnDelay);
+ }
+ this.loginRespawnDelay =config.getLong("loginRespawnDelay", defaultLoginRespawnDelay);
+ if (this.loginRespawnDelay < 0) {
+ plugin().log(Level.WARNING, "\tLogin Respawn delay has an invalid value, defaulting.");
+ this.loginRespawnDelay = defaultLoginRespawnDelay;
+ }
+ else {
+ plugin().log(Level.INFO, "\tLogin Respawn delay set to: " + this.loginRespawnDelay);
+ }
+ this.respawnQuotes = config.getStringList("respawnQuotes").toArray(new String[0]);
+ if (this.respawnQuotes.length < 1) {
+ plugin().log(Level.WARNING, "\tThere are no auto respawn quotes :'(");
+ }
+ else {
+ plugin().log(Level.INFO, "\tThe following auto respawn quotes were loaded:");
+ for (String quote : this.respawnQuotes) {
+ plugin().log(Level.INFO, "\t\t- " + quote);
+ }
+ }
+ }
+
+ public long getRespawnDelay() {
+ return this.respawnDelay;
+ }
+
+ public long getLoginRespawnDelay() {
+ return this.loginRespawnDelay;
+ }
+
+ public String[] getRespawnQuotes() {
+ return this.respawnQuotes;
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/BadBoyWatchConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/BadBoyWatchConfig.java
index 0dca6262..a3544e72 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/BadBoyWatchConfig.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/BadBoyWatchConfig.java
@@ -29,7 +29,7 @@ public class BadBoyWatchConfig extends SimpleHackConfig {
Material.JUKEBOX,
Material.NOTE_BLOCK,
Material.BEACON,
- Material.ENCHANTMENT_TABLE,
+ Material.ENCHANTING_TABLE,
Material.ENDER_CHEST,
Material.FURNACE,
Material.SPONGE);
@@ -48,7 +48,7 @@ protected void wireup(ConfigurationSection config) {
plugin().log(Level.INFO, " Minimum Breakpath Depth To Match: {0}", this.minDepthToMatch);
@SuppressWarnings("unchecked")
List watch = (List) config.getList("watchedMaterials");
- this.watchedMaterials = new HashSet();
+ this.watchedMaterials = new HashSet<>();
if (watch == null || watch.isEmpty()) {
this.watchedMaterials.addAll(defaultWatched);
plugin().log(Level.INFO, " Adding default watch set");
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFeaturesConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFeaturesConfig.java
index 6f8ad6f3..45f94d63 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFeaturesConfig.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFeaturesConfig.java
@@ -15,6 +15,8 @@ public class GameFeaturesConfig extends SimpleHackConfig {
private boolean potatoXPEnabled;
private boolean villagerTrading;
private boolean witherSpawning;
+ private boolean patrolSpawning;
+ private boolean isPhantomSpawning;
private boolean enderChestPlacement;
private boolean enderChestUse;
private boolean shulkerBoxUse;
@@ -47,6 +49,12 @@ protected void wireup(ConfigurationSection config) {
this.witherSpawning = config.getBoolean("witherSpawning", false);
if (!this.witherSpawning) plugin().log(" Wither Spawning is disabled");
+ this.patrolSpawning = config.getBoolean("patrolSpawning", false);
+ if (!this.patrolSpawning) plugin().log("Patrol Spawning is disabled");
+
+ this.isPhantomSpawning = config.getBoolean("phantomSpawning", false);
+ if (!this.isPhantomSpawning) plugin().log("Phantom Spawning is disabled");
+
this.enderChestPlacement = config.getBoolean("enderChestPlacement", true);
if (!this.enderChestPlacement) plugin().log(" Placing EnderChests is disabled");
@@ -63,7 +71,9 @@ protected void wireup(ConfigurationSection config) {
if (!this.elytraUse) plugin().log(" Elytra use is disabled");
this.chorusFruitUse = config.getBoolean("chorusFruitTeleportation", false);
- if (!this.chorusFruitUse) plugin().log(" Chorus Fruit Teleportation is disabled");
+ if (!this.chorusFruitUse) {
+ plugin().log(" Chorus Fruit Teleportation is disabled");
+ }
this.weepingAngel = config.getBoolean("weepingAngel.enabled", false);
if (this.weepingAngel) {
@@ -103,6 +113,14 @@ public boolean isWitherSpawning() {
return this.witherSpawning;
}
+ public boolean isPatrolSpawning() {
+ return this.patrolSpawning;
+ }
+
+ public boolean isPhantomSpawning() {
+ return this.isPhantomSpawning;
+ }
+
public boolean isEnderChestPlacement() {
return this.enderChestPlacement;
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFixesConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFixesConfig.java
index 1bcdf067..52c609de 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFixesConfig.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameFixesConfig.java
@@ -73,15 +73,30 @@ protected void wireup(ConfigurationSection config) {
}
private void wireUpArrays() {
- bfArray = new ArrayList();
- railArray = new ArrayList();
- pistonArray = new ArrayList();
+ bfArray = new ArrayList<>();
+ railArray = new ArrayList<>();
+ pistonArray = new ArrayList<>();
- railArray.add(Material.RAILS);
+ railArray.add(Material.RAIL);
railArray.add(Material.ACTIVATOR_RAIL);
railArray.add(Material.DETECTOR_RAIL);
railArray.add(Material.POWERED_RAIL);
- railArray.add(Material.CARPET);
+ railArray.add(Material.WHITE_CARPET);
+ railArray.add(Material.RED_CARPET);
+ railArray.add(Material.BLACK_CARPET);
+ railArray.add(Material.BLUE_CARPET);
+ railArray.add(Material.BROWN_CARPET);
+ railArray.add(Material.CYAN_CARPET);
+ railArray.add(Material.GRAY_CARPET);
+ railArray.add(Material.GREEN_CARPET);
+ railArray.add(Material.LIGHT_BLUE_CARPET);
+ railArray.add(Material.LIGHT_GRAY_CARPET);
+ railArray.add(Material.LIME_CARPET);
+ railArray.add(Material.YELLOW_CARPET);
+ railArray.add(Material.PURPLE_CARPET);
+ railArray.add(Material.PINK_CARPET);
+ railArray.add(Material.ORANGE_CARPET);
+ railArray.add(Material.MAGENTA_CARPET);
bfArray.add(BlockFace.NORTH);
bfArray.add(BlockFace.SOUTH);
@@ -90,10 +105,10 @@ private void wireUpArrays() {
bfArray.add(BlockFace.UP);
bfArray.add(BlockFace.DOWN);
- pistonArray.add(Material.PISTON_BASE);
- pistonArray.add(Material.PISTON_EXTENSION);
- pistonArray.add(Material.PISTON_MOVING_PIECE);
- pistonArray.add(Material.PISTON_STICKY_BASE);
+ pistonArray.add(Material.PISTON);
+ pistonArray.add(Material.PISTON_HEAD);
+ pistonArray.add(Material.MOVING_PISTON);
+ pistonArray.add(Material.STICKY_PISTON);
}
public boolean isBlockElytraBreakBug() {
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameTuningConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameTuningConfig.java
index 27f01bb1..27c9e683 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameTuningConfig.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/GameTuningConfig.java
@@ -49,9 +49,12 @@ public class GameTuningConfig extends SimpleHackConfig {
private boolean enderGrief;
private boolean witherGrief;
+ private boolean dragonGrief;
private boolean preventFallingThroughBedrock;
+ private boolean badOmen;
+
private Set noPlace;
public GameTuningConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
@@ -102,9 +105,15 @@ protected void wireup(ConfigurationSection config) {
this.witherGrief = config.getBoolean("witherGrief", false);
if (!witherGrief) plugin().log("Wither grief is disabled.");
+ this.dragonGrief = config.getBoolean("dragonGrief", true);
+ if (!dragonGrief) plugin().log("Dragon grief is disabled.");
+
this.preventFallingThroughBedrock = config.getBoolean("preventFallingThroughBedrock", true);
- noPlace = new HashSet();
+ this.badOmen = config.getBoolean("badOmen", false);
+ if (!badOmen) plugin().log("Bad Omen effect is disabled.");
+
+ noPlace = new HashSet<>();
if(config.isList("noplace")) {
for(String entry : config.getStringList("noplace")) {
try {
@@ -124,8 +133,8 @@ protected void wireup(ConfigurationSection config) {
* @author ProgrammerDan
*/
private void wireupChunkLimits(ConfigurationSection config) {
- this.blockEntityLimits = new HashMap();
- this.exemptFromLimits = new HashSet();
+ this.blockEntityLimits = new HashMap<>();
+ this.exemptFromLimits = new HashSet<>();
this.chunkLimitsEnabled = false;
if (config == null) return;
@@ -289,12 +298,20 @@ public boolean isWitherGrief() {
return witherGrief;
}
+ public boolean isDragonGrief() {
+ return dragonGrief;
+ }
+
public boolean isPreventFallingThroughBedrock() {
return preventFallingThroughBedrock;
}
+ public boolean isBadOmenEnabled() {
+ return badOmen;
+ }
+
public boolean canPlace(Material mat) {
return !noPlace.contains(mat);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/PhantomOfTheOperaConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/PhantomOfTheOperaConfig.java
new file mode 100644
index 00000000..7bee610e
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/PhantomOfTheOperaConfig.java
@@ -0,0 +1,67 @@
+package com.programmerdan.minecraft.simpleadminhacks.configs;
+
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
+import java.util.logging.Level;
+import org.bukkit.configuration.ConfigurationSection;
+
+public class PhantomOfTheOperaConfig extends SimpleHackConfig {
+
+ private int timeSinceRestCap;
+
+ private boolean nightSpawn;
+
+ private boolean stormSpawn;
+
+ public PhantomOfTheOperaConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
+ super(plugin, base);
+ }
+
+ @Override
+ protected void wireup(ConfigurationSection config) {
+ // Parse the cap for TIME_SINCE_REST
+ this.timeSinceRestCap = config.getInt("timeSinceRestCap", 80_000);
+ if (this.timeSinceRestCap == -1) {
+ plugin().log(Level.INFO, "[PhantomOfTheOpera] TIME_SINCE_REST will not be capped.");
+ }
+ else if (this.timeSinceRestCap < -1) {
+ plugin().log(Level.WARNING, "[PhantomOfTheOpera] TIME_SINCE_REST invalid value, defaulting.");
+ this.timeSinceRestCap = 80_000;
+ }
+ else if (this.timeSinceRestCap < 72_000) {
+ plugin().log(Level.WARNING, "[PhantomOfTheOpera] TIME_SINCE_REST capped below spawning value.");
+ }
+ else {
+ plugin().log(Level.INFO, "[PhantomOfTheOpera] TIME_SINCE_REST capped to: " + this.timeSinceRestCap);
+ }
+ // Parse phantom spawning at night
+ this.nightSpawn = config.getBoolean("nightSpawn", true);
+ if (this.nightSpawn) {
+ plugin().log(Level.INFO, "[PhantomOfTheOpera] Phantoms are now allowed to spawn during the night.");
+ }
+ else {
+ plugin().log(Level.INFO, "[PhantomOfTheOpera] Phantoms are no longer allowed to spawn during the night.");
+ }
+ // Parse phantom spawning during storms
+ this.stormSpawn = config.getBoolean("stormSpawn", true);
+ if (this.stormSpawn) {
+ plugin().log(Level.INFO, "[PhantomOfTheOpera] Phantoms are now allowed to spawn during storms.");
+ }
+ else {
+ plugin().log(Level.INFO, "[PhantomOfTheOpera] Phantoms are no longer allowed to spawn during storms.");
+ }
+ }
+
+ public int getTimeSinceRestCap() {
+ return timeSinceRestCap;
+ }
+
+ public boolean canNightSpawn() {
+ return nightSpawn;
+ }
+
+ public boolean canStormSpawn() {
+ return stormSpawn;
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/TimingsHackConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/TimingsHackConfig.java
index 7e2d994f..1f6f934b 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/TimingsHackConfig.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/TimingsHackConfig.java
@@ -11,9 +11,9 @@
public class TimingsHackConfig extends SimpleHackConfig {
- private Short timingsMap;
- private Map bindMaps;
- private Map reverseBindMaps;
+ private Integer timingsMap;
+ private Map bindMaps;
+ private Map reverseBindMaps;
public TimingsHackConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
super(plugin, base);
@@ -21,37 +21,37 @@ public TimingsHackConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
@Override
protected void wireup(ConfigurationSection config) {
- timingsMap = config.contains("timingMap") ? (short) config.getInt("timingMap") : null;
- bindMaps = new ConcurrentHashMap();
- reverseBindMaps = new ConcurrentHashMap();
+ timingsMap = config.contains("timingMap") ? config.getInt("timingMap") : null;
+ bindMaps = new ConcurrentHashMap<>();
+ reverseBindMaps = new ConcurrentHashMap<>();
if (config.contains("bindings")) {
ConfigurationSection bindings = config.getConfigurationSection("bindings");
Set keys = bindings.getKeys(false);
for (String key : keys) {
- bindMaps.put(key, (short) bindings.getInt(key));
- reverseBindMaps.put((short) bindings.getInt(key), key);
+ bindMaps.put(key, bindings.getInt(key));
+ reverseBindMaps.put(bindings.getInt(key), key);
}
}
}
- public Short getTimingsMap() {
+ public Integer getTimingsMap() {
return timingsMap;
}
- public void setTimingsMap(short mapId) {
+ public void setTimingsMap(int mapId) {
timingsMap = mapId;
getBase().set("timingMap", mapId);
}
- public Short getBindMap(String bind) {
+ public Integer getBindMap(String bind) {
if (bind == null) {
return null;
}
return bindMaps.get(bind);
}
- public void setBindMap(String bind, short mapId) {
- Short prior = bindMaps.replace(bind, mapId);
+ public void setBindMap(String bind, int mapId) {
+ Integer prior = bindMaps.replace(bind, mapId);
if (prior != null) {
reverseBindMaps.remove(prior);
}
@@ -59,7 +59,7 @@ public void setBindMap(String bind, short mapId) {
getBase().set("bindings." + bind, mapId);
}
- public String getBindFromId(short mapId) {
+ public String getBindFromId(int mapId) {
return reverseBindMaps.get(mapId);
}
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/ToggleLampConfig.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/ToggleLampConfig.java
new file mode 100644
index 00000000..d9a3c66d
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/ToggleLampConfig.java
@@ -0,0 +1,25 @@
+package com.programmerdan.minecraft.simpleadminhacks.configs;
+
+import org.bukkit.configuration.ConfigurationSection;
+
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
+
+public class ToggleLampConfig extends SimpleHackConfig {
+
+ private long cooldownTime;
+
+ public ToggleLampConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
+ super(plugin, base);
+ }
+
+ @Override
+ protected void wireup(ConfigurationSection config) {
+ this.cooldownTime = config.getLong("cooldownTime", 100);
+ }
+
+ public long getCooldownTime() {
+ return this.cooldownTime;
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/AutoRespawn.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/AutoRespawn.java
new file mode 100644
index 00000000..279797e1
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/AutoRespawn.java
@@ -0,0 +1,202 @@
+package com.programmerdan.minecraft.simpleadminhacks.hacks;
+
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
+import com.programmerdan.minecraft.simpleadminhacks.configs.AutoRespawnConfig;
+import org.bukkit.Bukkit;
+import org.bukkit.boss.BarColor;
+import org.bukkit.boss.BarStyle;
+import org.bukkit.boss.BossBar;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.PlayerDeathEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.player.PlayerRespawnEvent;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scheduler.BukkitTask;
+import vg.civcraft.mc.civmodcore.util.TextUtil;
+
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.logging.Level;
+
+public class AutoRespawn extends SimpleHack implements Listener {
+
+ private final Random random = new SecureRandom();
+ private final Map respawnTimers = new HashMap<>();
+
+ public AutoRespawn(SimpleAdminHacks plugin, AutoRespawnConfig config) {
+ super(plugin, config);
+ }
+
+ private void autoRespawnPlayer(Player player) {
+ player.spigot().respawn();
+ String[] quotes = config.getRespawnQuotes();
+ if (quotes.length > 0) {
+ player.sendMessage(TextUtil.parse(quotes[quotes.length == 1 ? 0 : random.nextInt(quotes.length)]));
+ }
+ }
+
+ @EventHandler
+ public void onPlayerLogin(PlayerJoinEvent event) {
+ if (event.getPlayer().isDead()) {
+ plugin().log(Level.INFO, "Player [" + event.getPlayer().getName() + "] logged in while dead, respawning.");
+ if (config.getLoginRespawnDelay() == 0) {
+ autoRespawnPlayer(event.getPlayer());
+ }
+ else {
+ this.respawnTimers.compute(event.getPlayer(), (player, timer) -> {
+ if (timer != null) {
+ timer.stop();
+ }
+ return new RespawnTimer(player, config.getLoginRespawnDelay());
+ });
+ }
+ }
+ }
+
+ @EventHandler
+ public void onPlayerDeath(PlayerDeathEvent event) {
+ plugin().log(Level.INFO, "Player [" + event.getEntity().getName() + "] died, setting respawn timer.");
+ this.respawnTimers.compute(event.getEntity(), (player, timer) -> {
+ if (timer != null) {
+ timer.stop();
+ }
+ return new RespawnTimer(player, config.getRespawnDelay());
+ });
+ }
+
+ @EventHandler
+ public void onPlayerLogout(PlayerQuitEvent event) {
+ if (event.getPlayer().isDead()) {
+ plugin().log(Level.INFO, "Player [" + event.getPlayer().getName() + "] logged out while dead.");
+ this.respawnTimers.computeIfPresent(event.getPlayer(), (player, timer) -> timer.stop());
+ }
+ }
+
+ @EventHandler
+ public void onPlayerRespawn(PlayerRespawnEvent event) {
+ this.respawnTimers.computeIfPresent(event.getPlayer(), (player, timer) -> timer.stop());
+ }
+
+ @Override
+ public void dataCleanup() {
+ this.respawnTimers.forEach((player, timer) -> timer.stop());
+ this.respawnTimers.clear();
+ }
+
+ @Override
+ public void registerListeners() {
+ if (config.isEnabled()) {
+ plugin().log("Registering AutoRespawn listener");
+ plugin().registerListener(this);
+ }
+ }
+
+ @Override
+ public void unregisterListeners() {
+ HandlerList.unregisterAll(this);
+ }
+
+ @Override
+ public String status() {
+ if (!config.isEnabled()) {
+ return "Auto Respawner disabled.";
+ }
+ return "Auto Respawner enabled (" + this.respawnTimers.size() + " players are waiting to respawn)";
+ }
+
+ @Override
+ public void dataBootstrap() {}
+
+ @Override
+ public void registerCommands() {}
+
+ @Override
+ public void unregisterCommands() {}
+
+ public class RespawnTimer {
+
+ private BossBar bar;
+ private long previousTime;
+ private final long setTime;
+ private long timeRemaining;
+ private long secondTimer;
+ private BukkitTask processor;
+
+ public RespawnTimer(Player player, long delay) {
+ this.previousTime = System.currentTimeMillis();
+ this.setTime = this.timeRemaining = delay;
+ this.secondTimer = 1000L;
+ this.bar = Bukkit.createBossBar(generateBarTitle(), BarColor.WHITE, BarStyle.SOLID);
+ this.bar.setVisible(true);
+ this.bar.setProgress(1.0d);
+ this.bar.addPlayer(player);
+ this.processor = new BukkitRunnable() {
+ @Override
+ public void run() {
+ tick();
+ }
+ }.runTaskTimer(plugin(), 1L, 1L);
+ }
+
+ private String generateBarTitle() {
+ if (this.timeRemaining <= 1000L) {
+ return "Respawning now.";
+ }
+ if (this.timeRemaining < 60000L) {
+ return "Respawning in " + (this.timeRemaining / 1000L) + " seconds.";
+ }
+ if (this.timeRemaining < 120000L) {
+ return "Respawning in 1 minute.";
+ }
+ if (this.timeRemaining < 3600000L) {
+ return "Respawning in " + (this.timeRemaining / 60000L) + " minutes.";
+ }
+ return "Respawning in " + (this.timeRemaining / 3600000L) + " hours.";
+ }
+
+ private void tick() {
+ long currentTime = System.currentTimeMillis();
+ long timeDifference = currentTime - this.previousTime;
+ this.previousTime = currentTime;
+ this.timeRemaining -= timeDifference;
+ this.secondTimer -= timeDifference;
+ if (this.secondTimer > 0) {
+ return;
+ }
+ this.secondTimer = 1000L;
+ this.bar.setTitle(generateBarTitle());
+ this.bar.setProgress(Math.max((double) (this.timeRemaining - 1000L) / (double) this.setTime, 0));
+ if (this.timeRemaining > 0) {
+ return;
+ }
+ this.bar.getPlayers().forEach(AutoRespawn.this::autoRespawnPlayer);
+ }
+
+ public RespawnTimer stop() {
+ if (this.bar != null) {
+ this.bar.setVisible(false);
+ this.bar.removeAll();
+ this.bar = null;
+ }
+ if (this.processor != null) {
+ this.processor.cancel();
+ this.processor = null;
+ }
+ return null;
+ }
+
+ }
+
+ public static AutoRespawnConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
+ return new AutoRespawnConfig(plugin, config);
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/BadBoyWatch.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/BadBoyWatch.java
index 4572b71e..848cab34 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/BadBoyWatch.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/BadBoyWatch.java
@@ -112,8 +112,8 @@ public void registerListeners() {
@Override
public void dataBootstrap() {
- boys = new ConcurrentHashMap();
- lowBoys = new ConcurrentHashMap();
+ boys = new ConcurrentHashMap<>();
+ lowBoys = new ConcurrentHashMap<>();
}
@Override
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/CTAnnounce.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/CTAnnounce.java
index dec8f6ed..b5894014 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/CTAnnounce.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/CTAnnounce.java
@@ -43,7 +43,7 @@ public CTAnnounce(SimpleAdminHacks plugin, CTAnnounceConfig config) {
* @param event
*/
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled = true)
- public void CTEvent(PlayerCombatTagEvent event) {
+ public void ctEvent(PlayerCombatTagEvent event) {
if (!config.isEnabled()) return; // ignore if off
if (event.getVictim() == null || event.getAttacker() == null) return; // ignore non-pvp and admin-pvp
plugin().debug(" Victim: {0} Attacker: {1}", event.getVictim().getName(), event.getAttacker().getName());
@@ -99,7 +99,7 @@ public void registerCommands() {
@Override
public void dataBootstrap() {
- lastCTAnnounce = new ConcurrentHashMap();
+ lastCTAnnounce = new ConcurrentHashMap<>();
}
@Override
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Experimental.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Experimental.java
index 303811ff..4993bcb3 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Experimental.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Experimental.java
@@ -92,11 +92,13 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
Player player = (Player) sender;
ItemStack item = player.getInventory().getItemInMainHand();
- if (item != null) {
+ if (item != null && item.getType().isItem()) { // spigot claims @Notnull but unclear how well enforced
YamlConfiguration yml = new YamlConfiguration();
yml.set("template", item);
plugin().log(yml.saveToString());
sender.sendMessage(yml.saveToString());
+ } else {
+ sender.sendMessage("No valid item in main hand");
}
return true;
}
@@ -105,7 +107,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
private void monitorTeleportLow(PlayerTeleportEvent event) {
if (!config.isEnabled()) return;
if (!config.isTeleportSpy()) return;
- StringBuffer sb = new StringBuffer("[LO] ");
+ StringBuilder sb = new StringBuilder("[LO] ");
logTeleport(event, sb);
}
@@ -113,7 +115,7 @@ private void monitorTeleportLow(PlayerTeleportEvent event) {
private void monitorTeleportHigh(PlayerTeleportEvent event) {
if (!config.isEnabled()) return;
if (!config.isTeleportSpy()) return;
- StringBuffer sb = new StringBuffer("[HI] ");
+ StringBuilder sb = new StringBuilder("[HI] ");
logTeleport(event, sb);
}
@@ -133,15 +135,17 @@ public void run() {
this.cancel();
return;
}
+ // I recall running into situation where this UUID nulled out, don't remember how
+ // so, I check.
if (playerUUID != null) {
Player player = plugin().getServer().getPlayer(playerUUID);
if (player != null) {
- StringBuffer sb = new StringBuffer("Tracking: ");
+ StringBuilder sb = new StringBuilder("Tracking: ");
sb.append(playerUUID);
logPlayer(player, sb);
plugin().log(sb.toString());
} else {
- StringBuffer sb = new StringBuffer("Lost: ");
+ StringBuilder sb = new StringBuilder("Lost: ");
sb.append(playerUUID);
plugin().log(sb.toString());
this.cancel();
@@ -153,12 +157,16 @@ public void run() {
}.runTaskTimer(plugin(), 2l, 4l);
}
- private void logTeleport(PlayerTeleportEvent event, StringBuffer sb) {
+ private void logTeleport(PlayerTeleportEvent event, StringBuilder sb) {
sb.append(event.isCancelled() ? "C " : "A ");
sb.append(event.getCause().name());
Player player = event.getPlayer();
Location from = event.getFrom();
Location to = event.getTo();
+ // Most of these nullchecks will gen warnings with compile time contracts.
+ // Experience tells me these can be violated at runtime due to spigot failures,
+ // esp moving between worlds with corresponding state desync. Leaving them in
+ // consequentially.
sb.append(String.format(" %16s", player != null ? player.getName() : "--unknown--"));
if (from != null) {
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", from.getWorld().getName(), from.getX(), from.getY(), from.getZ()));
@@ -177,10 +185,12 @@ private void logTeleport(PlayerTeleportEvent event, StringBuffer sb) {
plugin().log(sb.toString());
}
- private void logPlayer(final Player player, StringBuffer sb) {
+ private void logPlayer(final Player player, StringBuilder sb) {
sb.append(player.getWorld().getName());
Location feet = player.getLocation();
Location eyes = player.getEyeLocation();
+ // Similar comment here, most/all these nullchecks are from observed failures.
+ // I truly hope Spigot has eliminated all sources of these but I'm not the trusting type.
if (feet != null) {
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", feet.getWorld().getName(), feet.getX(), feet.getY(), feet.getZ()));
} else {
@@ -197,17 +207,19 @@ private void logPlayer(final Player player, StringBuffer sb) {
private void monitorCombatLow(EntityDamageByEntityEvent event) {
if (!config.isEnabled()) return;
if (!config.isCombatSpy()) return;
- StringBuffer sb = new StringBuffer("[LO] ");
+ StringBuilder sb = new StringBuilder("[LO] ");
logCombat(event, sb);
}
- private void logCombat(EntityDamageByEntityEvent event, StringBuffer sb) {
+ private void logCombat(EntityDamageByEntityEvent event, StringBuilder sb) {
sb.append(event.isCancelled() ? "C " : "A ");
sb.append(event.getCause().name());
+ // These null checks defend against specific kinds of malformed damage events, which can occur
+ // at runtime or while running with older plugins.
sb.append(String.format(", %5.2f->%5.2f", event.getDamage(), event.getFinalDamage()));
- sb.append(String.format(", %16s v %16s",
- event.getDamager() != null ? event.getDamager().getName() : "--unknown--",
- event.getEntity() != null ? event.getEntity().getName() : "--unknown--" ));
+ sb.append(String.format(", %16s v %16s",
+ event.getDamager() != null ? event.getDamager().getName() : "--unknown--",
+ event.getEntity() != null ? event.getEntity().getName() : "--unknown--"));
for (EntityDamageEvent.DamageModifier mod : EntityDamageEvent.DamageModifier.values()) {
sb.append(", ").append(mod.name());
try {
@@ -223,7 +235,7 @@ private void logCombat(EntityDamageByEntityEvent event, StringBuffer sb) {
private void monitorCombatHigh(EntityDamageByEntityEvent event) {
if (!config.isEnabled()) return;
if (!config.isCombatSpy()) return;
- StringBuffer sb = new StringBuffer("[HI]: ");
+ StringBuilder sb = new StringBuilder("[HI]: ");
logCombat(event, sb);
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFeatures.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFeatures.java
index d0bcf6a4..ee55b56a 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFeatures.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFeatures.java
@@ -12,6 +12,7 @@
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
+import org.bukkit.block.data.type.Dispenser;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@@ -43,7 +44,6 @@
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.material.Dispenser;
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
@@ -128,6 +128,20 @@ public String status() {
genStatus.append("disabled\n");
}
+ genStatus.append(" Patrol Spawning is ");
+ if (config.isPatrolSpawning()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Phantom Spawning is ");
+ if (config.isPhantomSpawning()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
genStatus.append(" Ender Chest placement is ");
if (config.isEnderChestPlacement()) {
genStatus.append("enabled\n");
@@ -225,7 +239,6 @@ public void potatoXP(FurnaceExtractEvent event) {
if (!config.isEnabled() || config.isPotatoXPEnabled()) return;
try {
Material mat = event.getItemType();
- if (mat == null) return;
if (Material.BAKED_POTATO.equals(mat)) {
event.setExpToDrop(0);
@@ -240,11 +253,11 @@ public void disableVillagerTrading(PlayerInteractEntityEvent event) {
if (!config.isEnabled()) return;
if (!config.isVillagerTrading()) {
Entity npc = event.getRightClicked();
-
- if (npc != null) {
- if (npc.getType().equals(EntityType.VILLAGER)) {
- event.setCancelled(true);
- }
+ // Don't recall specifically but considering I had this null check
+ // alone... I probably had an NPE here at some point. Probably plugin
+ // with plugin interactions.
+ if (npc != null && EntityType.VILLAGER.equals(npc.getType())) {
+ event.setCancelled(true);
}
}
}
@@ -253,7 +266,28 @@ public void disableVillagerTrading(PlayerInteractEntityEvent event) {
public void disableWitherSpawning(CreatureSpawnEvent event) {
if (!config.isEnabled()) return;
if (!config.isWitherSpawning()) {
- if (event.getEntityType().equals(EntityType.WITHER)) {
+ if (EntityType.WITHER.equals(event.getEntityType())) {
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void disablePatrols(CreatureSpawnEvent event) {
+ if (!config.isEnabled()) return;
+ if (!config.isPatrolSpawning()) {
+ if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.PATROL) {
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void disablePhantomSpawning(CreatureSpawnEvent event) {
+ if (!config.isEnabled()) return;
+ if (!config.isPhantomSpawning()) {
+ if (EntityType.PHANTOM.equals(event.getEntityType())
+ && event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.NATURAL) {
event.setCancelled(true);
}
}
@@ -263,7 +297,7 @@ public void disableWitherSpawning(CreatureSpawnEvent event) {
public void disableEnderChestPlacement(BlockPlaceEvent event) {
if (!config.isEnabled()) return;
if (!config.isEnderChestPlacement()) {
- if (event.getBlock().getType().equals(Material.ENDER_CHEST)) {
+ if (Material.ENDER_CHEST.equals(event.getBlock().getType())) {
event.setCancelled(true);
}
}
@@ -275,9 +309,9 @@ public void disableEnderChestUse(PlayerInteractEvent event) {
if (!config.isEnderChestUse()) {
Action action = event.getAction();
Material material = event.getClickedBlock().getType();
- boolean ender_chest = action == Action.RIGHT_CLICK_BLOCK &&
- material.equals(Material.ENDER_CHEST);
- if (ender_chest) {
+ boolean enderChest = action == Action.RIGHT_CLICK_BLOCK &&
+ Material.ENDER_CHEST.equals(material);
+ if (enderChest) {
event.setCancelled(true);
}
}
@@ -292,9 +326,9 @@ public void disableShulkerBoxUse(InventoryOpenEvent event){
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void disabledShulkerBoxHoppering(InventoryMoveItemEvent event) {
- if (!config.isEnabled() || config.isShulkerBoxUse()) return;
-
- if ((event.getDestination() == null) || (event.getSource() == null)) return;
+ if (!config.isEnabled() || config.isShulkerBoxUse()) {
+ return;
+ }
if (InventoryType.SHULKER_BOX.equals(event.getDestination().getType()) ||
InventoryType.SHULKER_BOX.equals(event.getSource().getType())) {
event.setCancelled(true);
@@ -315,7 +349,7 @@ public void disableTotemPowers(EntityResurrectEvent event) {
public void disableChorusFruitTeleportation(PlayerTeleportEvent event) {
if (!config.isEnabled() || config.isChorusFruitTeleportation()) return;
- if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT)) {
+ if (PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT.equals(event.getCause())) {
event.setCancelled(true);
}
}
@@ -379,7 +413,7 @@ public void run() {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerBucketEmptyEvent(PlayerBucketEmptyEvent e) {
if (config.isEnabled() && config.isBlockWaterInHell()) {
- if ((e.getBlockClicked().getBiome() == Biome.HELL) && (e.getBucket() == Material.WATER_BUCKET)) {
+ if (Biome.NETHER.equals(e.getBlockClicked().getBiome()) && Material.WATER_BUCKET.equals(e.getBucket())) {
e.setCancelled(true);
e.getItemStack().setType(Material.BUCKET);
}
@@ -388,16 +422,15 @@ public void onPlayerBucketEmptyEvent(PlayerBucketEmptyEvent e) {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onDispenseEvent(BlockDispenseEvent event) {
- if (config.isEnabled() && config.isBlockWaterInHell()) {
- if (event.getBlock().getType() == Material.DISPENSER) {
- Dispenser disp = (Dispenser) event.getBlock().getState().getData();
- Biome biome = event.getBlock().getRelative(disp.getFacing()).getBiome();
-
- if (Biome.HELL.equals(biome) && event.getItem() != null && event.getItem().getType().equals(Material.WATER_BUCKET)) {
- event.setItem(new ItemStack(Material.BUCKET, event.getItem().getAmount()));
- event.setCancelled(true);
- }
-
+ if (!config.isEnabled() || !config.isBlockWaterInHell()) {
+ return;
+ }
+ if (Material.DISPENSER.equals(event.getBlock().getType())) {
+ Dispenser disp = (Dispenser) event.getBlock().getBlockData();
+ Biome biome = event.getBlock().getRelative(disp.getFacing()).getBiome();
+ if (Biome.NETHER.equals(biome) && Material.WATER_BUCKET.equals(event.getItem().getType())) {
+ event.setItem(new ItemStack(Material.BUCKET, event.getItem().getAmount()));
+ event.setCancelled(true);
}
}
}
@@ -423,11 +456,8 @@ public void onPlayerQuit(PlayerQuitEvent event) {
public void onVehicleExit(VehicleExitEvent event) {
if (config.isEnabled() && config.isMinecartTeleport()) {
final Vehicle vehicle = event.getVehicle();
- if (vehicle == null) {
- return;
- }
final Entity passenger = event.getExited();
- if (passenger == null || !(passenger instanceof Player)) {
+ if (!(passenger instanceof Player)) {
return;
}
final Player player = (Player) passenger;
@@ -445,11 +475,8 @@ public void onVehicleExit(VehicleExitEvent event) {
public void onVehicleDestroy(VehicleDestroyEvent event) {
if (config.isEnabled() && config.isMinecartTeleport()) {
final Vehicle vehicle = event.getVehicle();
- if (vehicle == null) {
- return;
- }
final List passengers = vehicle.getPassengers();
- if (passengers == null) {
+ if (passengers.isEmpty()) {
return;
}
final Location vehicleLocation = vehicle.getLocation();
@@ -469,20 +496,15 @@ public void onVehicleDestroy(VehicleDestroyEvent event) {
@EventHandler
public void onBlockFromTo(BlockFromToEvent event) {
if (config.isEnabled() && config.isObsidianGenerators()) {
- if (event.getBlock().getType() == Material.STATIONARY_LAVA ||
- event.getBlock().getType() == Material.LAVA) {
+ if (Material.LAVA.equals(event.getBlock().getType())) {
Block to = event.getToBlock();
- if (to.getType() == Material.REDSTONE || to.getType() == Material.TRIPWIRE) {
- if (to.getRelative(BlockFace.NORTH).getType() == Material.STATIONARY_WATER
- || to.getRelative(BlockFace.SOUTH).getType() == Material.STATIONARY_WATER
- || to.getRelative(BlockFace.WEST).getType() == Material.STATIONARY_WATER
- || to.getRelative(BlockFace.EAST).getType() == Material.STATIONARY_WATER
- || to.getRelative(BlockFace.NORTH).getType() == Material.WATER
- || to.getRelative(BlockFace.SOUTH).getType() == Material.WATER
- || to.getRelative(BlockFace.WEST).getType() == Material.WATER
- || to.getRelative(BlockFace.EAST).getType() == Material.WATER) {
+ if (Material.REDSTONE.equals(to.getType()) || Material.TRIPWIRE.equals(to.getType())) {
+ if (Material.WATER.equals(to.getRelative(BlockFace.NORTH).getType())
+ || Material.WATER.equals(to.getRelative(BlockFace.SOUTH).getType())
+ || Material.WATER.equals(to.getRelative(BlockFace.WEST).getType())
+ || Material.WATER.equals(to.getRelative(BlockFace.EAST).getType())) {
to.setType(Material.OBSIDIAN);
- }
+ }
}
}
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFixes.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFixes.java
index 7a3cdfff..97279341 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFixes.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameFixes.java
@@ -12,6 +12,8 @@
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
+import org.bukkit.block.data.type.Dispenser;
+import org.bukkit.block.data.type.Hopper;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -33,8 +35,6 @@
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.InventoryHolder;
-import org.bukkit.material.Dispenser;
-import org.bukkit.material.Hopper;
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
@@ -162,7 +162,6 @@ public void onBlockBreak(BlockBreakEvent event) {
if (!config.isEnabled() || !config.isBlockElytraBreakBug()) return;
Block block = event.getBlock();
Player player = event.getPlayer();
- if (block == null || player == null) return;
if (!player.getLocation().equals(block.getLocation())
&& player.getEyeLocation().getBlock().getType() != Material.AIR) {
@@ -173,7 +172,9 @@ public void onBlockBreak(BlockBreakEvent event) {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onEntityTeleport(EntityTeleportEvent event) {
- if (!config.isEnabled() || config.canStorageTeleport()) return;
+ if (!config.isEnabled() || config.canStorageTeleport()) {
+ return;
+ }
if (event.getEntity() instanceof InventoryHolder) {
event.setCancelled(true);
}
@@ -181,7 +182,9 @@ public void onEntityTeleport(EntityTeleportEvent event) {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onEntityPortal(EntityPortalEvent event) {
- if (!config.isEnabled() || config.canStorageTeleport()) return;
+ if (!config.isEnabled() || config.canStorageTeleport()) {
+ return;
+ }
if (event.getEntity() instanceof InventoryHolder) {
event.setCancelled(true);
}
@@ -190,13 +193,19 @@ public void onEntityPortal(EntityPortalEvent event) {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
if (!config.isEnabled() || !config.isStopHopperDupe()) return;
+ // I recollect inventory handling to be the single biggest source of NPEs, so I'll add
+ // back in the nullcheck, although I do hope Spigot has addressed the sources with the
+ // addition of their annotations.
+ //
if ((event.getDestination() == null) || (event.getSource() == null) ||
!(InventoryType.HOPPER.equals(event.getDestination().getType())) ||
!(InventoryType.HOPPER.equals(event.getSource().getType())) ||
!(Material.HOPPER.equals(event.getDestination().getLocation().getBlock().getType())) ||
- !(Material.HOPPER.equals(event.getSource().getLocation().getBlock().getType()))) return;
- Hopper source = (Hopper) event.getSource().getLocation().getBlock().getState().getData();
- Hopper dest = (Hopper) event.getDestination().getLocation().getBlock().getState().getData();
+ !(Material.HOPPER.equals(event.getSource().getLocation().getBlock().getType()))) {
+ return;
+ }
+ Hopper source = (Hopper) event.getSource().getLocation().getBlock().getBlockData();
+ Hopper dest = (Hopper) event.getDestination().getLocation().getBlock().getBlockData();
if (source.getFacing().getOppositeFace() == dest.getFacing()) {
//They're pointing into each other and will eventually dupe
event.setCancelled(true);
@@ -243,7 +252,7 @@ public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
if (config.isEnabled() && config.isStopEndPortalDeletion()) {
Block block = event.getBlockClicked().getRelative(event.getBlockFace());
- if (block.getType() == Material.ENDER_PORTAL) {
+ if (Material.END_PORTAL.equals(block.getType())) {
event.setCancelled(true);
}
}
@@ -252,11 +261,11 @@ public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onDispenseEvent(BlockDispenseEvent event) {
if (config.isEnabled() && config.isStopEndPortalDeletion()) {
- if (event.getBlock().getType() == Material.DISPENSER) {
- Dispenser disp = (Dispenser) event.getBlock().getState().getData();
+ if (Material.DISPENSER.equals(event.getBlock().getType())) {
+ Dispenser disp = (Dispenser) event.getBlock().getBlockData();
Material type = event.getBlock().getRelative(disp.getFacing()).getType();
- if (type == Material.ENDER_PORTAL) {
+ if (Material.END_PORTAL.equals(type)) {
event.setCancelled(true);
}
}
@@ -268,12 +277,33 @@ public void onPlayerEnterBed(BlockPlaceEvent event) {
if (!config.isEnabled() || !config.stopBedBombing()) return;
Block b = event.getBlock();
- if (!(b.getType() == Material.BED || b.getType() == Material.BED_BLOCK))
- return;
-
+ switch (b.getType()) {
+ case BLACK_BED:
+ case BLUE_BED:
+ case BROWN_BED:
+ case CYAN_BED:
+ case GRAY_BED:
+ case GREEN_BED:
+ case LIME_BED:
+ case MAGENTA_BED:
+ case LIGHT_GRAY_BED:
+ case PURPLE_BED:
+ case PINK_BED:
+ case YELLOW_BED:
+ case WHITE_BED:
+ case RED_BED:
+ case ORANGE_BED:
+ case LIGHT_BLUE_BED:
+ break;
+ default:
+ return;
+ }
Environment env = b.getLocation().getWorld().getEnvironment();
Biome biome = b.getLocation().getBlock().getBiome();
- if (env == Environment.NETHER || env == Environment.THE_END || Biome.HELL == biome || Biome.SKY == biome) {
+ if (Environment.NETHER.equals(env) || Environment.THE_END.equals(env) || Biome.NETHER.equals(biome)
+ || Biome.END_BARRENS.equals(biome) || Biome.END_HIGHLANDS.equals(biome)
+ || Biome.END_MIDLANDS.equals(biome) || Biome.SMALL_END_ISLANDS.equals(biome)
+ || Biome.THE_END.equals(biome)) {
event.setCancelled(true);
}
}
@@ -281,7 +311,8 @@ public void onPlayerEnterBed(BlockPlaceEvent event) {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true)
public void onStructureGrow(StructureGrowEvent event) {
if(config.isEnabled() && config.stopTreeWraparound()) {
- int maxY = 0, minY = 257;
+ int maxY = 0;
+ int minY = 257;
for(BlockState bs : event.getBlocks()) {
final int y = bs.getLocation().getBlockY();
maxY = Math.max(maxY, y);
@@ -322,35 +353,116 @@ public void onPearlTeleport(PlayerTeleportEvent event) {
case ENDER_CHEST:
height = 0.875;
break;
- case STEP:
+ case ACACIA_SLAB:
+ case ANDESITE_SLAB:
+ case BIRCH_SLAB:
+ case BRICK_SLAB:
+ case COBBLESTONE_SLAB:
+ case CUT_RED_SANDSTONE_SLAB:
+ case CUT_SANDSTONE_SLAB:
+ case DARK_OAK_SLAB:
+ case DARK_PRISMARINE_SLAB:
+ case DIORITE_SLAB:
+ case END_STONE_BRICK_SLAB:
+ case GRANITE_SLAB:
+ case JUNGLE_SLAB:
+ case MOSSY_COBBLESTONE_SLAB:
+ case STONE_SLAB:
+ case STONE_BRICK_SLAB:
+ case SPRUCE_SLAB:
+ case SMOOTH_STONE_SLAB:
+ case SMOOTH_SANDSTONE_SLAB:
+ case SMOOTH_RED_SANDSTONE_SLAB:
+ case SMOOTH_QUARTZ_SLAB:
+ case SANDSTONE_SLAB:
+ case RED_SANDSTONE_SLAB:
+ case RED_NETHER_BRICK_SLAB:
+ case QUARTZ_SLAB:
+ case PURPUR_SLAB:
+ case PRISMARINE_SLAB:
+ case PRISMARINE_BRICK_SLAB:
+ case POLISHED_GRANITE_SLAB:
+ case POLISHED_DIORITE_SLAB:
+ case POLISHED_ANDESITE_SLAB:
+ case PETRIFIED_OAK_SLAB:
+ case OAK_SLAB:
+ case NETHER_BRICK_SLAB:
+ case MOSSY_STONE_BRICK_SLAB:
lowerBlockBypass = true;
height = 0.5;
break;
- case WATER_LILY:
+ case LILY_PAD:
height = 0.016;
break;
- case ENCHANTMENT_TABLE:
+ case ENCHANTING_TABLE:
lowerBlockBypass = true;
height = 0.75;
break;
- case BED:
- case BED_BLOCK:
+ case BLACK_BED:
+ case BLUE_BED:
+ case BROWN_BED:
+ case CYAN_BED:
+ case GRAY_BED:
+ case GREEN_BED:
+ case LIME_BED:
+ case MAGENTA_BED:
+ case LIGHT_GRAY_BED:
+ case PURPLE_BED:
+ case PINK_BED:
+ case YELLOW_BED:
+ case WHITE_BED:
+ case RED_BED:
+ case ORANGE_BED:
+ case LIGHT_BLUE_BED:
break;
case FLOWER_POT:
- case FLOWER_POT_ITEM:
height = 0.375;
break;
- case SKULL:
+ case SKELETON_SKULL:
+ case WITHER_SKELETON_WALL_SKULL:
+ case WITHER_SKELETON_SKULL:
+ case SKELETON_WALL_SKULL:
+ case PLAYER_HEAD:
+ case PLAYER_WALL_HEAD:
+ case CREEPER_HEAD:
+ case CREEPER_WALL_HEAD:
+ case DRAGON_HEAD:
+ case DRAGON_WALL_HEAD:
+ case ZOMBIE_HEAD:
+ case ZOMBIE_WALL_HEAD:
height = 0.5;
break;
default:
break;
}
switch (below.getType()) {
- case FENCE:
- case FENCE_GATE:
- case NETHER_FENCE:
- case COBBLE_WALL:
+ case ACACIA_FENCE:
+ case ACACIA_FENCE_GATE:
+ case BIRCH_FENCE:
+ case BIRCH_FENCE_GATE:
+ case DARK_OAK_FENCE:
+ case DARK_OAK_FENCE_GATE:
+ case JUNGLE_FENCE:
+ case JUNGLE_FENCE_GATE:
+ case SPRUCE_FENCE_GATE:
+ case SPRUCE_FENCE:
+ case OAK_FENCE_GATE:
+ case OAK_FENCE:
+ case NETHER_BRICK_FENCE:
+ case ANDESITE_WALL:
+ case BRICK_WALL:
+ case STONE_BRICK_WALL:
+ case COBBLESTONE_WALL:
+ case DIORITE_WALL:
+ case END_STONE_BRICK_WALL:
+ case GRANITE_WALL:
+ case SANDSTONE_WALL:
+ case RED_SANDSTONE_WALL:
+ case MOSSY_COBBLESTONE_WALL:
+ case MOSSY_STONE_BRICK_WALL:
+ case PRISMARINE_WALL:
+ case RED_NETHER_BRICK_WALL:
+ case NETHER_BRICK_WALL:
height = 0.5;
break;
default:
@@ -426,4 +538,4 @@ public void onSignChange(SignChangeEvent event) {
public static GameFixesConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
return new GameFixesConfig(plugin, config);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameTuning.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameTuning.java
index 5203de04..53addac9 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameTuning.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/GameTuning.java
@@ -1,15 +1,13 @@
package com.programmerdan.minecraft.simpleadminhacks.hacks;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Random;
import java.util.logging.Level;
-import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.World;
+import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.configuration.ConfigurationSection;
@@ -18,7 +16,6 @@
import org.bukkit.entity.Player;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.SkeletonHorse;
-import org.bukkit.entity.WitherSkeleton;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
@@ -28,11 +25,7 @@
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
-import org.bukkit.event.entity.CreatureSpawnEvent;
-import org.bukkit.event.entity.EntityChangeBlockEvent;
-import org.bukkit.event.entity.EntityDeathEvent;
-import org.bukkit.event.entity.EntityPortalEvent;
-import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.event.entity.*;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
@@ -40,16 +33,17 @@
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
+import org.bukkit.event.player.PlayerBedEnterEvent.BedEnterResult;
import org.bukkit.event.world.PortalCreateEvent;
import org.bukkit.inventory.InventoryHolder;
-import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.SpawnEggMeta;
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
import com.programmerdan.minecraft.simpleadminhacks.configs.GameTuningConfig;
import com.programmerdan.minecraft.simpleadminhacks.util.TeleportUtil;
-
-import net.md_5.bungee.api.ChatColor;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
/**
* This is a grab-bag class to hold any _tuning_ related configurations that impact the
@@ -68,8 +62,6 @@
public class GameTuning extends SimpleHack implements Listener {
public static final String NAME = "GameTuning";
- private Random rng = new Random();
-
public GameTuning(SimpleAdminHacks plugin, GameTuningConfig config) {
super(plugin, config);
}
@@ -133,7 +125,63 @@ public String status() {
} else {
genStatus.append("disabled\n");
}
- // more?
+
+ genStatus.append(" Kill trap horses is ");
+ if (config.killTrapHorses()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Changing spawner type is ");
+ if (config.canChangeSpawnerType()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Villager trading is ");
+ if (config.allowVillagerTrading()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Ender grief is ");
+ if (config.isEnderGrief()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Wither grief is ");
+ if (config.isWitherGrief()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Dragon grief is ");
+ if (config.isDragonGrief()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Prevent falling through bedrock is ");
+ if (config.isPreventFallingThroughBedrock()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
+ genStatus.append(" Bad Omen is ");
+ if (config.isBadOmenEnabled()) {
+ genStatus.append("enabled\n");
+ } else {
+ genStatus.append("disabled\n");
+ }
+
} else {
genStatus.append("inactive");
}
@@ -159,21 +207,15 @@ public void chunkLimits(BlockPlaceEvent event) {
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
try {
Player player = event.getPlayer();
- if (player == null) return;
-
Block block = event.getBlock();
- if (block == null) return;
if (!config.applyChunkLimits(player.getUniqueId())) return;
Material mat = block.getType();
- if (mat == null) return;
Integer limit = config.getChunkLimit(mat);
if (limit == null) return;
- if (block.getChunk().getTileEntities() == null) return;
-
int current = 0;
for (BlockState state : block.getChunk().getTileEntities()) {
if (state != null && mat.equals(state.getType())) {
@@ -194,9 +236,9 @@ public void chunkLimits(BlockPlaceEvent event) {
public void chunkLimitsExploitExtend(BlockPistonExtendEvent event) {
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
List blocks = event.getBlocks();
- if (blocks != null && blocks.size() > 0) {
+ if (!blocks.isEmpty()) {
for (Block b : blocks) {
- if (b != null && b.getType() != null && config.getChunkLimit(b.getType()) != null) {
+ if (b != null && config.getChunkLimit(b.getType()) != null) {
event.setCancelled(true);
return; // TODO send message to nearby player warning of reason for stopping.
}
@@ -209,36 +251,25 @@ public void chunkLimitsExploitExtend(BlockPistonExtendEvent event) {
public void chunkLimitsExploitRetract(BlockPistonRetractEvent event) {
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
List blocks = event.getBlocks();
- if (blocks != null && blocks.size() > 0) {
+ if (!blocks.isEmpty()) {
for (Block b : blocks) {
- if (b != null && b.getType() != null && config.getChunkLimit(b.getType()) != null) {
+ if (b != null && config.getChunkLimit(b.getType()) != null) {
event.setCancelled(true);
return; // TODO send message to nearby player warning of reason for stopping.
}
}
}
}
-
- @SuppressWarnings("deprecation")
- @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
- public void bedRClickToSetSpawn(PlayerInteractEvent event) {
- if (!config.isEnabled() || !config.areDaytimeBedsEnabled() || event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getClickedBlock().getType() != Material.BED_BLOCK) {
+
+ @EventHandler
+ public void enterBed(PlayerBedEnterEvent e) {
+ if (!config.isEnabled() || !config.areDaytimeBedsEnabled()) {
return;
}
-
- if (event.getPlayer() == null) return;
- if (event.getClickedBlock() == null) return;
-
- // Let plugins that already watch for and cancel this event have a turn, like ExilePearl
- PlayerBedEnterEvent pbee = new PlayerBedEnterEvent(event.getPlayer(), event.getClickedBlock());
- Bukkit.getServer().getPluginManager().callEvent(pbee);
- if (pbee.isCancelled()) {
- return;
+ if (BedEnterResult.NOT_POSSIBLE_NOW.equals(e.getBedEnterResult()) || BedEnterResult.NOT_SAFE.equals(e.getBedEnterResult())) {
+ e.getPlayer().setBedSpawnLocation(e.getBed().getLocation(), false);
+ e.getPlayer().sendTitle("", config.getDaytimeBedSpawnSetMessage());
}
-
- event.getPlayer().setBedSpawnLocation(event.getClickedBlock().getLocation(), false);
- Location loc = event.getClickedBlock().getLocation();
- event.getPlayer().sendTitle("", config.getDaytimeBedSpawnSetMessage());
}
@EventHandler(priority = EventPriority.LOWEST)
@@ -252,7 +283,7 @@ public void onPortalTravel(EntityPortalEvent event) {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerPortalTravel(PlayerPortalEvent event) {
- if(config.isEnabled() && event.getCause() == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) {
+ if(config.isEnabled() && PlayerTeleportEvent.TeleportCause.NETHER_PORTAL.equals(event.getCause())) {
if(!config.allowNetherTravel()) {
event.setCancelled(true);
} else if (config.isOneToOneNether()) {
@@ -266,7 +297,7 @@ public void onPlayerPortalTravel(PlayerPortalEvent event) {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPortalCreate(PortalCreateEvent event) {
if (config.isEnabled() && !config.isReturnNetherPortal()) {
- if (event.getReason() == PortalCreateEvent.CreateReason.FIRE && event.getWorld().getName().equals("world_nether")) {
+ if (PortalCreateEvent.CreateReason.FIRE.equals(event.getReason()) && Environment.NETHER.equals(event.getWorld().getEnvironment())) {
event.setCancelled(true);
}
}
@@ -320,11 +351,13 @@ public void onEntityTarget(EntityTargetEvent event) {
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
- if(config.isEnabled() && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
- boolean cancel = !config.isEnderChestInventories() && event.getClickedBlock().getType() == Material.ENDER_CHEST;
- cancel = cancel || (!config.canChangeSpawnerType() && event.getClickedBlock().getType() == Material.MOB_SPAWNER
- && event.getItem() != null && event.getItem().getType() == Material.MONSTER_EGG);
- event.setCancelled(cancel);
+ if(!config.isEnabled() || !Action.RIGHT_CLICK_BLOCK.equals(event.getAction())) {
+ return;
+ }
+ boolean cancel = !config.canChangeSpawnerType() && Material.SPAWNER.equals(event.getClickedBlock().getType())
+ && event.getItem() != null && event.getItem().getItemMeta() instanceof SpawnEggMeta;
+ if (cancel) {
+ event.setCancelled(true);
}
}
@@ -340,26 +373,57 @@ public void onBlockPlace(BlockPlaceEvent event) {
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if(config.isEnabled() && !config.allowVillagerTrading()) {
Entity npc = event.getRightClicked();
- if(npc != null && npc.getType() == EntityType.VILLAGER) {
+ // consistency, preserving null check
+ if(npc != null && EntityType.VILLAGER.equals(npc.getType())) {
event.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
- public void onEntityChangeBLock(EntityChangeBlockEvent event) {
+ public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if(config.isEnabled() &&
- (!config.isEnderGrief() && event.getEntityType() == EntityType.ENDERMAN) ||
- (!config.isWitherGrief() && event.getEntityType() == EntityType.WITHER)) {
+ (!config.isEnderGrief() && EntityType.ENDERMAN.equals(event.getEntityType())) ||
+ (!config.isWitherGrief() && EntityType.WITHER.equals(event.getEntityType())) ||
+ (!config.isDragonGrief() && EntityType.ENDER_DRAGON.equals(event.getEntityType()))) {
event.setCancelled(true);
}
}
+ /**
+ * Speculative handler for dragon fireballs and exploding wither skulls
+ *
+ * Some examples online prefer event.getEntity() instanceof DragonFireball and WitherSkull, could try that
+ * if this does not work
+ */
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onEntityExplodeEvent(EntityExplodeEvent event) {
+ if (config.isEnabled() &&
+ (!config.isDragonGrief() && EntityType.DRAGON_FIREBALL.equals(event.getEntityType())) ||
+ (!config.isWitherGrief() && EntityType.WITHER_SKULL.equals(event.getEntityType()))) {
+ event.setCancelled(true);
+ // note this might not prevent block breaks, check on that (1.14)
+ }
+ }
+
+
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if(config.isEnabled() && config.isPreventFallingThroughBedrock() && event.getTo().getY() < 1
- && event.getPlayer().getGameMode() == GameMode.SURVIVAL) {
+ && GameMode.SURVIVAL.equals(event.getPlayer().getGameMode())) {
TeleportUtil.tryToTeleportVertically(event.getPlayer(), event.getTo(), "falling into the void");
}
}
+
+
+ @EventHandler
+ public void onBadOmenEffect(EntityPotionEffectEvent event) {
+ if (!config.isEnabled() || config.isBadOmenEnabled()) {
+ return;
+ }
+ PotionEffect effect = event.getNewEffect();
+ if (effect != null && effect.getType().equals(PotionEffectType.BAD_OMEN)) {
+ event.setCancelled(true);
+ }
+ }
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Insight.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Insight.java
index 456632b1..f2e14078 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Insight.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/Insight.java
@@ -77,11 +77,7 @@ public Insight(SimpleAdminHacks plugin, InsightConfig config) {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
- if (args.length < 1) { // show help
- return false;
- }
-
- return true;
+ return args.length >= 1;
}
@@ -185,9 +181,9 @@ private void reboundHandlers(Class clazz) {
Method method = clazz.getDeclaredMethod("getHandlerList");
HandlerList handler = (HandlerList) method.invoke(null);
RegisteredListener[] listeners = handler.getRegisteredListeners();
- ArrayList newOrdering = new ArrayList(listeners.length);
- ArrayList thisLow = new ArrayList();
- ArrayList thisHigh = new ArrayList();
+ ArrayList newOrdering = new ArrayList<>(listeners.length);
+ ArrayList thisLow = new ArrayList<>();
+ ArrayList thisHigh = new ArrayList<>();
for (RegisteredListener l : listeners) {
handler.unregister(l);
if (l.getPriority().equals(EventPriority.LOWEST)) {
@@ -236,8 +232,8 @@ public void registerCommands() {
@Override
public void dataBootstrap() {
if (config.isEnabled()) {
- this.tracking = new ConcurrentHashMap();
- this.rebounders = new ArrayList>();
+ this.tracking = new ConcurrentHashMap<>();
+ this.rebounders = new ArrayList<>();
}
}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvControl.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvControl.java
index 172e960b..dc90bcda 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvControl.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvControl.java
@@ -11,8 +11,8 @@
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
-import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftInventoryPlayer;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventoryPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
@@ -25,9 +25,9 @@
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
import com.programmerdan.minecraft.simpleadminhacks.configs.InvControlConfig;
-import net.minecraft.server.v1_12_R1.NBTTagCompound;
-import net.minecraft.server.v1_12_R1.NBTTagList;
-import net.minecraft.server.v1_12_R1.WorldNBTStorage;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.NBTTagList;
+import net.minecraft.server.v1_14_R1.WorldNBTStorage;
import vg.civcraft.mc.namelayer.NameAPI;
public class InvControl extends SimpleHack implements CommandExecutor, Listener {
@@ -70,7 +70,8 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
}
}
if (player == null && playerUID != null) { // Go deep into NBT.
- WorldNBTStorage storage = (WorldNBTStorage) (((CraftServer) plugin().getServer()).getServer().worlds.get(0).getDataManager());
+ WorldNBTStorage storage = ((CraftServer) plugin().getServer()).getServer().getWorlds().
+ iterator().next().getDataManager();
NBTTagCompound rawPlayer = storage.getPlayerData(playerUID.toString());
if (rawPlayer != null) {
@@ -85,10 +86,10 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
int food = rawPlayer.getInt("foodLevel");
// Fun NMS inventory reconstruction from file data.
- net.minecraft.server.v1_12_R1.PlayerInventory nms_pl_inv = new net.minecraft.server.v1_12_R1.PlayerInventory(null);
+ net.minecraft.server.v1_14_R1.PlayerInventory nms_pl_inv = new net.minecraft.server.v1_14_R1.PlayerInventory(null);
NBTTagList inv = rawPlayer.getList("Inventory", rawPlayer.getTypeId());
nms_pl_inv.b(inv); // We use this to bypass the Craft code which requires a player object, unlike NMS.
- PlayerInventory pl_inv = (PlayerInventory) new CraftInventoryPlayer(nms_pl_inv);
+ PlayerInventory pl_inv = new CraftInventoryPlayer(nms_pl_inv);
invSee(sender, pl_inv, health, food, playername);
return true;
@@ -124,14 +125,14 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
}
public void adminCloseInventory(InventoryCloseEvent event) {
- if (event.getPlayer() != null && this.adminsWithInv.contains(event.getPlayer().getUniqueId())) {
+ if (this.adminsWithInv.contains(event.getPlayer().getUniqueId())) {
this.adminsWithInv.remove(event.getPlayer().getUniqueId());
}
}
private void invSee(CommandSender sender, PlayerInventory pl_inv, double health, int food, String playername) {
if (!(sender instanceof Player)) { // send text only.
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append(playername).append("'s\n Health: ").append((int)health*2);
sb.append("\n Food: ").append(food);
sb.append("\n Inventory: ");
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvisibleFix.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvisibleFix.java
deleted file mode 100644
index 088ed711..00000000
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvisibleFix.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package com.programmerdan.minecraft.simpleadminhacks.hacks;
-
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.UUID;
-import java.util.concurrent.LinkedTransferQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.bukkit.Bukkit;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.scheduler.BukkitTask;
-
-import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
-import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
-import com.programmerdan.minecraft.simpleadminhacks.configs.InvisibleFixConfig;
-
-/**
- * Sometimes when joining, a player is invisible due to some kind of spigot bug that's been
- * known since 2015 but unfixed.
- *
- * This is widely reported as a fix -- hide then show the player to the other players online.
- * To do this safely w/o crashing all the things, I schedule the hide and show delayed
- * so if we get a huge influx of joins this doesn't take forever.
- *
- * @author ProgrammerDan
- */
-public class InvisibleFix extends SimpleHack implements Listener {
- public static final String NAME = "InvisibleFix";
- private AtomicInteger activeJoins = new AtomicInteger(0);
-
- private LinkedTransferQueue ltq = new LinkedTransferQueue();
- private BukkitTask recheckTask = null;
-
- public InvisibleFix(SimpleAdminHacks plugin, InvisibleFixConfig config) {
- super(plugin, config);
- }
-
- @EventHandler(priority=EventPriority.MONITOR, ignoreCancelled = true)
- public void JoinEvent(PlayerJoinEvent event) {
- if (!config.isEnabled()) return; // ignore if off
- Player p = event.getPlayer();
- if (p == null) return;
- final UUID uuid = p.getUniqueId();
- ltq.offer(uuid);
-
- if (p.isOp() && config.getIgnoreOps()) return;
- String tPerm = config.getIgnorePermission();
- if (tPerm != null && p.hasPermission(tPerm)) return;
-
- Bukkit.getScheduler().runTaskLater(plugin(), new Runnable() {
- @Override
- public void run() {
- plugin().debug("Hopefully fixing any invisibility for {0}", uuid);
- try {
- if (uuid == null) return;
- Player p = Bukkit.getPlayer(uuid);
- if (p == null) return;
- for (Player online : Bukkit.getOnlinePlayers()) {
- if (online != p) {
- online.hidePlayer(p);
- p.hidePlayer(online);
- online.showPlayer(p);
- p.showPlayer(online);
- }
- }
- } finally {
- if (activeJoins.decrementAndGet() < 0) {
- activeJoins.set(0);
- }
- }
- }
- }, activeJoins.incrementAndGet() * 20);
- }
-
- @Override
- public void registerListeners() {
- if (config.isEnabled()) {
- plugin().log("Registering InvisibleFix listener");
- plugin().registerListener(this);
- plugin().log("Starting recheck task");
- this.recheckTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin(),
- new Runnable() {
- @Override
- public void run() {
- if (!config.isEnabled()) return;
- doRecheck();
- }
- },
- config.getRecheckInterval(), config.getRecheckInterval());
- }
- }
-
- private void doRecheck() {
- // unspool, then recheck.
- plugin().debug("Refixing invisibles...");
- HashSet refix = new HashSet(config.getMaxPlayersPerRecheck());
- LinkedList skiplist = new LinkedList();
- int cnt = 0;
- // accumulate
- while (this.ltq.peek() != null && cnt < config.getMaxPlayersPerRecheck()) {
- UUID fixerUUID = ltq.poll();
- if (fixerUUID == null) break;
- Player fixer = Bukkit.getPlayer(fixerUUID);
- if (fixer != null) {
- if (fixer.isOp() && config.getIgnoreOps()) {
- skiplist.add(fixerUUID);
- continue;
- }
- String tPerm = config.getIgnorePermission();
- if (tPerm != null && fixer.hasPermission(tPerm)) {
- skiplist.add(fixerUUID);
- continue;
- }
- refix.add(fixer);
- cnt++;
- }
- }
- if (cnt > 0) {
- plugin().debug("Found {0} players to refix", cnt);
- // unblind
- for (Player online : Bukkit.getOnlinePlayers()) {
- for (Player fix : refix) {
- if (!refix.contains(fix)) {
- online.hidePlayer(fix);
- fix.hidePlayer(online);
- online.showPlayer(fix);
- fix.hidePlayer(online);
- }
- }
- }
- // add them back.
- for (Player fix : refix) {
- this.ltq.offer(fix.getUniqueId());
- }
- }
- for (UUID skip : skiplist) {
- this.ltq.offer(skip);
- }
- }
-
- @Override
- public void registerCommands() {
- }
-
- @Override
- public void dataBootstrap() {
- activeJoins.set(0);
- ltq.clear();
- }
-
- @Override
- public void unregisterListeners() {
- if (this.recheckTask != null) {
- plugin().debug("Stopping InvisibleFix recheck task");
- this.recheckTask.cancel();
- }
- }
-
- @Override
- public void unregisterCommands() {
- }
-
- @Override
- public void dataCleanup() {
- ltq.clear();
- }
-
- @Override
- public String status() {
- if (config != null && config.isEnabled()) {
- return "InvisibleFix active";
- } else {
- return "InvisibleFix not active";
- }
- }
-
- public static InvisibleFixConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
- return new InvisibleFixConfig(plugin, config);
- }
-}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvisibleFixTwo.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvisibleFixTwo.java
deleted file mode 100644
index 7e6f4a84..00000000
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/InvisibleFixTwo.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package com.programmerdan.minecraft.simpleadminhacks.hacks;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.bukkit.Server;
-import org.bukkit.World;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
-import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.Player;
-import org.bukkit.entity.Vehicle;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerMoveEvent;
-import org.bukkit.event.player.PlayerTeleportEvent;
-import org.bukkit.event.vehicle.VehicleMoveEvent;
-
-import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
-import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
-import com.programmerdan.minecraft.simpleadminhacks.configs.InvisibleFixTwoConfig;
-
-import net.minecraft.server.v1_12_R1.EntityTracker;
-import net.minecraft.server.v1_12_R1.EntityTrackerEntry;
-import net.minecraft.server.v1_12_R1.PacketPlayOutEntityTeleport;
-import net.minecraft.server.v1_12_R1.WorldServer;
-
-/**
- * DISABLE WITH 1.11 -- This is for 1.10 only. Basically doing what Mojang was too
- * busy / lazy to do before 1.11. Note this is not a perfect fix, but at least
- * seems to deal with the largest areas of issue, namely, boats and horses,
- * by forcing a location packet to be broadcast to other players that are tracking.
- *
- * Portions adapted and heavily modified from code by aadnk: https://gist.github.com/aadnk/3773860
- *
- * @author ProgrammerDan
- */
-public class InvisibleFixTwo extends SimpleHack implements Listener {
- public static final String NAME = "InvisibleFixTwo";
-
- private Server server;
- private Map updateMap;
-
- public InvisibleFixTwo(SimpleAdminHacks plugin, InvisibleFixTwoConfig config) {
- super(plugin, config);
- this.server = plugin.getServer();
- }
-
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
- public void onPlayerTeleport(PlayerTeleportEvent event) {
- if (!config.isEnabled()) return; // ignore if off
-
- final Player player = event.getPlayer();
-
- if (player.isOp() && config.getIgnoreOps()) return;
- String tPerm = config.getIgnorePermission();
- if (tPerm != null && player.hasPermission(tPerm)) return;
-
- server.getScheduler().runTaskLater(plugin(), new Runnable() {
- @Override
- public void run() {
- try {
- forceUpdate(player);
- } catch (NullPointerException npe) {
- plugin().debug("Player offline, no forcefix");
- }
- }
- }, config.getTeleportFixDelay());
- }
-
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
- public void onPlayerVehicleMove(VehicleMoveEvent move) {
- if (!config.isEnabled()) return; // ignore if off
-
- Vehicle vehicle = move.getVehicle();
- if (vehicle == null) return;
- if (vehicle.getPassengers() == null || vehicle.getPassengers().size() == 0) return;
-
- for (Entity e : vehicle.getPassengers()) {
- if (e == null) continue;
-
- if (e.isOp() && config.getIgnoreOps()) continue;
- String tPerm = config.getIgnorePermission();
- if (tPerm != null && e.hasPermission(tPerm)) continue;
-
- forceUpdate(e);
- }
- }
-
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
- public void onPlayerMoveInVehicle(PlayerMoveEvent move) {
- if (!config.isEnabled()) return; // ignore if off
-
- Player p = move.getPlayer();
- if (p == null) return;
-
- if (p.isOp() && config.getIgnoreOps()) return;
- String tPerm = config.getIgnorePermission();
- if (tPerm != null && p.hasPermission(tPerm)) return;
-
- Entity vehicle = p.getVehicle();
- if (vehicle == null) return;
- forceUpdate(p);
- }
-
- private void forceUpdate(Entity entity) {
- Long last = updateMap.get(entity.getEntityId());
- long now = System.currentTimeMillis();
- if (last == null || last < now - config.getFixInterval()) {
- updateEntities(entity);
- updateMap.put(entity.getEntityId(), now);
- //plugin().debug("Forcing packet-based update for {0}", entity);
- }
- }
-
- private void updateEntities(final Entity entity) {
- World world = entity.getWorld();
- WorldServer worldServer = ((CraftWorld) world).getHandle();
-
- EntityTracker tracker = worldServer.tracker;
-
- EntityTrackerEntry entry = (EntityTrackerEntry) tracker.trackedEntities
- .get(entity.getEntityId());
-
- net.minecraft.server.v1_12_R1.Entity eEntity = getNmsEntity(entity);
-
- entry.broadcast(new PacketPlayOutEntityTeleport(eEntity));
- }
-
- private net.minecraft.server.v1_12_R1.Entity getNmsEntity(final Entity entity) {
- CraftEntity craftEntity = (CraftEntity) entity;
- return craftEntity.getHandle();
- }
-
- @Override
- public void registerListeners() {
- if (config.isEnabled()) {
- plugin().log("Registering InvisibleFixTwo listener");
- plugin().registerListener(this);
- }
- }
-
- @Override
- public void registerCommands() {
- }
-
- @Override
- public void dataBootstrap() {
- updateMap = new HashMap();
- }
-
- @Override
- public void unregisterListeners() {
- }
-
- @Override
- public void unregisterCommands() {
- }
-
- @Override
- public void dataCleanup() {
- if (updateMap != null) {
- updateMap.clear();
- }
- }
-
- @Override
- public String status() {
- if (config != null && config.isEnabled()) {
- return "InvisibleFixTwo active";
- } else {
- return "InvisibleFixTwo not active";
- }
- }
-
- public static InvisibleFixTwoConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
- return new InvisibleFixTwoConfig(plugin, config);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/NewfriendAssist.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/NewfriendAssist.java
index 7acc2329..56e9322b 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/NewfriendAssist.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/NewfriendAssist.java
@@ -48,7 +48,7 @@ public NewfriendAssist(SimpleAdminHacks plugin, NewfriendAssistConfig config) {
* Track standard quit events to monitor newfriend playtime on the day of join.
*/
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true)
- public void NewLeaveEvent(PlayerQuitEvent exit) {
+ public void newLeaveEvent(PlayerQuitEvent exit) {
if (!config.isEnabled()) return;
doLeave(exit.getPlayer());
}
@@ -57,7 +57,7 @@ public void NewLeaveEvent(PlayerQuitEvent exit) {
* Track standard kick events to monitor newfriend playtime on the day of join.
*/
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true)
- public void NewKickEvent(PlayerKickEvent exit) {
+ public void newKickEvent(PlayerKickEvent exit) {
if (!config.isEnabled()) return;
doLeave(exit.getPlayer());
}
@@ -95,7 +95,7 @@ public void NewJoinEvent(PlayerJoinEvent join) {
newfriendNames.put(newUUID, newfriend.getName());
newfriendSessionTime.put(newUUID, new SessionTime(System.currentTimeMillis()));
- if (config.getAnnounceBroadcast().size() > 0) {
+ if (!config.getAnnounceBroadcast().isEmpty()) {
// Prepare message
String cleanMessage = cleanMessage(join);
@@ -155,8 +155,8 @@ public void registerCommands() {
@Override
public void dataBootstrap() {
- this.newfriendNames = new HashMap();
- this.newfriendSessionTime = new HashMap();
+ this.newfriendNames = new HashMap<>();
+ this.newfriendSessionTime = new HashMap<>();
}
@Override
@@ -185,7 +185,7 @@ public void dataCleanup() {
*/
@Override
public String status() {
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
if (config != null && config.isEnabled()) {
sb.append("NewfriendAssist.PlayerJoin/Quit/KickEvent monitoring active");
} else {
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/PhantomOfTheOpera.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/PhantomOfTheOpera.java
new file mode 100644
index 00000000..925d6b8c
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/PhantomOfTheOpera.java
@@ -0,0 +1,124 @@
+package com.programmerdan.minecraft.simpleadminhacks.hacks;
+
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
+import com.programmerdan.minecraft.simpleadminhacks.configs.PhantomOfTheOperaConfig;
+import org.bukkit.ChatColor;
+import org.bukkit.Statistic;
+import org.bukkit.World;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.player.PlayerStatisticIncrementEvent;
+
+public class PhantomOfTheOpera extends SimpleHack implements Listener {
+
+ public PhantomOfTheOpera(SimpleAdminHacks plugin, PhantomOfTheOperaConfig config) {
+ super(plugin, config);
+ }
+
+ @Override
+ public String status() {
+ if (!config.isEnabled()) {
+ return "Phantom Manager disabled.";
+ }
+ return String.format("Phantom Manager enabled. [CAP: %S, NIGHT: %S, STORM: %S]",
+ config.getTimeSinceRestCap(), config.canNightSpawn(), config.canStormSpawn());
+ }
+
+ // ------------------------------------------------------------
+ // Listeners
+ // ------------------------------------------------------------
+
+ @Override
+ public void registerListeners() {
+ this.plugin().registerListener(this);
+ }
+
+ @Override
+ public void unregisterListeners() {
+ HandlerList.unregisterAll(this);
+ }
+
+ @EventHandler
+ public void onCreatureSpawn(CreatureSpawnEvent event) {
+ // Do not regulate unless the creature is a phantom
+ if (event.getEntityType() != EntityType.PHANTOM) {
+ return;
+ }
+ // Do not regulate phantom spawning unless it's natural
+ switch (event.getSpawnReason()) {
+ case NATURAL:
+ case DEFAULT:
+ break;
+ default:
+ return;
+ }
+ if (!config.canNightSpawn() && !config.canStormSpawn()) {
+ event.setCancelled(true);
+ plugin().debug("Phantom prevented from spawning: cannot spawn during the night nor during storms.");
+ return;
+ }
+ World world = event.getLocation().getWorld();
+ if (world == null) {
+ return;
+ }
+ if (!config.canNightSpawn() && config.canStormSpawn()) {
+ if (!world.hasStorm()) {
+ event.setCancelled(true);
+ plugin().debug("Phantom prevented from spawning: night spawning disabled.");
+ }
+ }
+ else if (config.canNightSpawn() && !config.canStormSpawn()) {
+ if (world.getTime() < 12300 || world.getTime() > 23850) {
+ event.setCancelled(true);
+ plugin().debug("Phantom prevented from spawning: storm spawning disabled.");
+ }
+ }
+ }
+
+ @EventHandler
+ public void onStatisticIncrease(PlayerStatisticIncrementEvent event) {
+ if (event.getStatistic() != Statistic.TIME_SINCE_REST) {
+ return;
+ }
+ if (event.getNewValue() == 72_000) {
+ event.getPlayer().sendMessage(ChatColor.DARK_RED + "You haven't slept in a while...");
+ }
+ int cap = config.getTimeSinceRestCap();
+ if (cap <= -1 || event.getNewValue() < cap) {
+ return;
+ }
+ event.getPlayer().setStatistic(Statistic.TIME_SINCE_REST,
+ Math.min(event.getNewValue(), cap));
+ event.setCancelled(true); // Prevent the increment
+ }
+
+ // ------------------------------------------------------------
+ // Commands
+ // ------------------------------------------------------------
+
+ @Override
+ public void registerCommands() { }
+
+ @Override
+ public void unregisterCommands() { }
+
+ // ------------------------------------------------------------
+ // Setup
+ // ------------------------------------------------------------
+
+ @Override
+ public void dataBootstrap() { }
+
+ @Override
+ public void dataCleanup() { }
+
+ public static PhantomOfTheOperaConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
+ return new PhantomOfTheOperaConfig(plugin, config);
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/ReinforcedChestBreak.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/ReinforcedChestBreak.java
index 03ceff04..a0e141ba 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/ReinforcedChestBreak.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/ReinforcedChestBreak.java
@@ -42,7 +42,9 @@ public static ReinforcedChestBreakConfig generate(SimpleAdminHacks plugin, Confi
@Override
public void registerListeners() {
- if (!config.isEnabled()) return;
+ if (!config.isEnabled()) {
+ return;
+ }
Bukkit.getPluginManager().registerEvents(this, plugin());
}
@@ -51,10 +53,12 @@ public void registerCommands() {}
@Override
public void dataBootstrap() {
- if (!config.isEnabled()) return;
+ if (!config.isEnabled()) {
+ return;
+ }
messages = new HashSet<>();
- manager = Citadel.getReinforcementManager();
+ manager = Citadel.getInstance().getReinforcementManager();
messenger = new Messenger();
Bukkit.getScheduler().runTaskTimer(plugin(), messenger, 0, config.getDelay() * 20);
@@ -80,17 +84,38 @@ public String status() {
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true)
public void onBlockBreak(BlockBreakEvent eve) {
- if (!config.isEnabled()) return;
- if (eve.getPlayer() == null) return;
- if (eve.getBlock() == null) return;
+ if (!config.isEnabled()) {
+ return;
+ }
Material bbe = eve.getBlock().getType();
- if (bbe == null) return;
- if (manager == null) manager = Citadel.getReinforcementManager();
+ if (manager == null) {
+ manager = Citadel.getInstance().getReinforcementManager();
+ }
+ // the list of items with inventories has grown a bit (1.14)
if (Material.CHEST.equals(bbe) || Material.TRAPPED_CHEST.equals(bbe)
|| Material.ENDER_CHEST.equals(bbe) || Material.FURNACE.equals(bbe)
- || Material.BURNING_FURNACE.equals(bbe) || Material.DISPENSER.equals(bbe)
- || Material.DROPPER.equals(bbe) || Material.HOPPER.equals(bbe)) {
- if(manager.isReinforced(eve.getBlock())) {
+ || Material.BLAST_FURNACE.equals(bbe) || Material.DISPENSER.equals(bbe)
+ || Material.DROPPER.equals(bbe) || Material.HOPPER.equals(bbe)
+ || Material.BARREL.equals(bbe) || Material.SMOKER.equals(bbe)
+ || Material.BLACK_SHULKER_BOX.equals(bbe)
+ || Material.BLUE_SHULKER_BOX.equals(bbe)
+ || Material.BROWN_SHULKER_BOX.equals(bbe)
+ || Material.CYAN_SHULKER_BOX.equals(bbe)
+ || Material.GRAY_SHULKER_BOX.equals(bbe)
+ || Material.GREEN_SHULKER_BOX.equals(bbe)
+ || Material.LIGHT_BLUE_SHULKER_BOX.equals(bbe)
+ || Material.LIGHT_GRAY_SHULKER_BOX.equals(bbe)
+ || Material.LIME_SHULKER_BOX.equals(bbe)
+ || Material.MAGENTA_SHULKER_BOX.equals(bbe)
+ || Material.ORANGE_SHULKER_BOX.equals(bbe)
+ || Material.PINK_SHULKER_BOX.equals(bbe)
+ || Material.PURPLE_SHULKER_BOX.equals(bbe)
+ || Material.RED_SHULKER_BOX.equals(bbe)
+ || Material.SHULKER_BOX.equals(bbe)
+ || Material.WHITE_SHULKER_BOX.equals(bbe)
+ || Material.YELLOW_SHULKER_BOX.equals(bbe)
+ || Material.LECTERN.equals(bbe) || Material.BREWING_STAND.equals(bbe)) {
+ if(manager.getReinforcement(eve.getBlock()) != null) {
String name = eve.getPlayer().getDisplayName();
Location loc = eve.getBlock().getLocation();
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/TimingsHack.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/TimingsHack.java
index 299b8e7b..44bc8b3b 100644
--- a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/TimingsHack.java
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/TimingsHack.java
@@ -30,6 +30,7 @@
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapPalette;
import org.bukkit.map.MapRenderer;
@@ -256,9 +257,10 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
view.getRenderers().forEach(view::removeRenderer);
view.addRenderer(this.tickVisualize);
- ItemStack viewMap = new ItemStack(Material.MAP, 1, view.getId());
+ ItemStack viewMap = new ItemStack(Material.MAP, 1);
- ItemMeta mapMeta = viewMap.getItemMeta();
+ MapMeta mapMeta = (MapMeta) viewMap.getItemMeta();
+ mapMeta.setMapView(view);
mapMeta.setDisplayName("Tick Health Monitor");
mapMeta.setLore(Arrays.asList(
"TPS",
@@ -286,7 +288,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
// Delay a few ticks, then give into inventory a map that shows the class % of TPS use
MapView view = null;
- Short mapId = config.getBindMap(args[0]);
+ Integer mapId = config.getBindMap(args[0]);
if (mapId != null) {
view = Bukkit.getMap(config.getBindMap(args[0]));
if (!bindVisualizers.containsKey(args[0])) {
@@ -303,9 +305,10 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
view.getRenderers().forEach(view::removeRenderer);
view.addRenderer(this.bindVisualizers.get(args[0]));
- ItemStack viewMap = new ItemStack(Material.MAP, 1, view.getId());
+ ItemStack viewMap = new ItemStack(Material.MAP);
- ItemMeta mapMeta = viewMap.getItemMeta();
+ MapMeta mapMeta = (MapMeta) viewMap.getItemMeta();
+ mapMeta.setMapView(view);
mapMeta.setDisplayName(args[0] + " Utilization Monitor");
mapMeta.setLore(Arrays.asList(
args[0],
@@ -338,7 +341,7 @@ public void registerListeners() {
@EventHandler(ignoreCancelled = true)
public void onMapInit(MapInitializeEvent event) {
MapView view = event.getMap();
- if (config.getTimingsMap() != null && view.getId() == config.getTimingsMap().shortValue()) {
+ if (config.getTimingsMap() != null && view.getId() == config.getTimingsMap()) {
view.getRenderers().forEach(view::removeRenderer);
view.addRenderer(this.tickVisualize);
} else {
@@ -360,21 +363,21 @@ public void onItemHeldChange(PlayerItemHeldEvent event) {
PlayerInventory inventory = player.getInventory();
ItemStack newHeld = inventory.getItem(event.getNewSlot());
if (newHeld != null && newHeld.getType().equals(Material.MAP)) {
- ItemMeta baseMeta = newHeld.getItemMeta();
+ MapMeta baseMeta = (MapMeta) newHeld.getItemMeta();
if (baseMeta.hasLore()) {
try {
String ID = baseMeta.getLore().get(0);
if (ID.equals("TPS")) {
- MapView view = Bukkit.getMap(newHeld.getDurability());
+ MapView view = baseMeta.hasMapView() ? baseMeta.getMapView() : Bukkit.getMap(baseMeta.getMapId());
if (view.getRenderers().size() == 1 && !view.getRenderers().get(0).equals(this.tickVisualize)) {
view.getRenderers().forEach(view::removeRenderer);
view.addRenderer(this.tickVisualize);
}
} else {
- String bind = config.getBindFromId(newHeld.getDurability());
+ String bind = config.getBindFromId(baseMeta.getMapId());
if (bind.equalsIgnoreCase(ID)) {
- MapView view = Bukkit.getMap(newHeld.getDurability());
+ MapView view = baseMeta.hasMapView() ? baseMeta.getMapView() : Bukkit.getMap(baseMeta.getMapId());
BindTimingMap bindViz = null;
if (!this.bindVisualizers.containsKey(bind)) {
bindVisualizers.put(bind, new BindTimingMap(bind)); // on demand binding.
@@ -418,7 +421,7 @@ public void dataBootstrap() {
tickErrors = 0;
for (int i = 0; i < LQ_CYCLES; i++) {
- hqTickMap[i] = new ConcurrentHashMap(100);
+ hqTickMap[i] = new ConcurrentHashMap<>(100);
}
lastTick = System.nanoTime();
@@ -431,7 +434,7 @@ public void run(){
}, 0l, 1l);
tickVisualize = new TimingsMap();
- bindVisualizers = new ConcurrentHashMap();
+ bindVisualizers = new ConcurrentHashMap<>();
rootThread = Thread.currentThread().getId();
threadBean = ManagementFactory.getThreadMXBean();
@@ -1057,7 +1060,7 @@ public void run() {
.append(ChatColor.AQUA).append("\n Elapsed Time: \n").append(ChatColor.BLUE)
.append(String.format(" %13d", hqToLqElapsedTime[checkTick])).append(ChatColor.AQUA).append("ns");
- TreeMap reveals = new TreeMap();
+ TreeMap reveals = new TreeMap<>();
for (ClassMethod cm : hqTickMap[checkTick].values()) {
reveals.compute(cm.max(), (k, S) -> {
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/ToggleLamp.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/ToggleLamp.java
new file mode 100644
index 00000000..eba935fc
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/ToggleLamp.java
@@ -0,0 +1,142 @@
+package com.programmerdan.minecraft.simpleadminhacks.hacks;
+
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.block.data.Lightable;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.metadata.FixedMetadataValue;
+import org.bukkit.metadata.MetadataValue;
+
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
+import com.programmerdan.minecraft.simpleadminhacks.configs.ToggleLampConfig;
+
+import vg.civcraft.mc.citadel.Citadel;
+import vg.civcraft.mc.citadel.ReinforcementManager;
+import vg.civcraft.mc.citadel.model.Reinforcement;
+
+public class ToggleLamp extends SimpleHack implements Listener {
+
+ public static final String NAME = "ToggleLamp";
+
+ private static final String META_COOLDOWN = "ToggleLamp_NextToggle";
+ private static final String META_TOGGLED = "ToggleLamp_Toggled";
+
+ private ReinforcementManager rm;
+
+ public ToggleLamp(SimpleAdminHacks plugin, ToggleLampConfig config) {
+ super(plugin, config);
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ public void onInteract(PlayerInteractEvent event) {
+ if (!config.isEnabled()) {
+ return;
+ }
+ Block clickedBlock = event.getClickedBlock();
+ if (clickedBlock == null) {
+ return;
+ }
+ if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
+ return;
+ }
+ if (event.getItem() == null) {
+ return;
+ }
+ if (event.getHand() != EquipmentSlot.HAND || event.getItem().getType() != Material.STICK) {
+ return;
+ }
+
+ Player eventPlayer = event.getPlayer();
+ Material clickedBlockMat = clickedBlock.getType();
+
+ if (clickedBlockMat != Material.REDSTONE_LAMP) {
+ return;
+ }
+
+ boolean toggled = clickedBlock.hasMetadata(META_TOGGLED)
+ && clickedBlock.getMetadata(META_TOGGLED).get(0).asBoolean();
+
+ if (clickedBlock.hasMetadata(META_COOLDOWN)) {
+ MetadataValue val = clickedBlock.getMetadata(META_COOLDOWN).get(0);
+ if (((long) val.value()) > System.currentTimeMillis()) {
+ return;
+ }
+ }
+
+ if (rm != null) {
+ Reinforcement rein = rm.getReinforcement(clickedBlock);
+ if (rein != null) {
+ if (!rein.getGroup().isMember(eventPlayer.getUniqueId())) {
+ return;
+ }
+ }
+ }
+ switchLamp(clickedBlock, !toggled);
+ eventPlayer.getWorld().playSound(clickedBlock.getLocation(), Sound.BLOCK_LEVER_CLICK, 0.5F, 1.0F);
+
+ }
+
+ @Override
+ public void registerListeners() {
+ if (config.isEnabled()) {
+ plugin().log("Registering ToggleLamp listeners");
+ plugin().registerListener(this);
+ }
+ }
+
+ @Override
+ public void registerCommands() {
+ }
+
+ @Override
+ public void dataBootstrap() {
+ rm = plugin().serverHasPlugin("Citadel") ? Citadel.getInstance().getReinforcementManager() : null;
+ }
+
+ @Override
+ public void unregisterListeners() {
+ }
+
+ @Override
+ public void unregisterCommands() {
+ }
+
+ @Override
+ public void dataCleanup() {
+ rm = null;
+ }
+
+ @Override
+ public String status() {
+ return config.isEnabled() ? "ToggleLamp enabled." : "ToggleLamp disabled.";
+ }
+
+ public static ToggleLampConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
+ return new ToggleLampConfig(plugin, config);
+ }
+
+ private void switchLamp(Block block, boolean lit) {
+
+ if (block.getType() != Material.REDSTONE_LAMP) {
+ return;
+ }
+
+ Lightable lightable = (Lightable) block.getBlockData();
+ lightable.setLit(lit);
+ block.setBlockData(lightable);
+
+ block.setMetadata(META_TOGGLED, new FixedMetadataValue(plugin(), lit));
+ block.setMetadata(META_COOLDOWN,
+ new FixedMetadataValue(plugin(), System.currentTimeMillis() + config.getCooldownTime()));
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/AntiFastBreak.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/AntiFastBreak.java
new file mode 100644
index 00000000..05d4cae3
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/AntiFastBreak.java
@@ -0,0 +1,214 @@
+package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.events.PacketAdapter;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.wrappers.BlockPosition;
+import com.programmerdan.minecraft.simpleadminhacks.BasicHack;
+import com.programmerdan.minecraft.simpleadminhacks.BasicHackConfig;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.autoload.AutoLoad;
+
+import net.minecraft.server.v1_14_R1.IBlockData;
+import vg.civcraft.mc.civmodcore.api.MaterialAPI;
+import vg.civcraft.mc.civmodcore.ratelimiting.RateLimiter;
+import vg.civcraft.mc.civmodcore.ratelimiting.RateLimiting;
+import vg.civcraft.mc.civmodcore.util.cooldowns.ICoolDownHandler;
+import vg.civcraft.mc.civmodcore.util.cooldowns.MilliSecCoolDownHandler;
+
+/**
+ * Prevents "CivBreak" by denying continuos block break packages for
+ * non-instabreaking
+ *
+ */
+public class AntiFastBreak extends BasicHack {
+
+ private Map> miningLocations;
+ private RateLimiter violationLimiter;
+
+ @AutoLoad
+ private double laggLenciency;
+ @AutoLoad
+ private long breakDenyDuration;
+
+ private ICoolDownHandler punishCooldown;
+
+ public AntiFastBreak(SimpleAdminHacks plugin, BasicHackConfig config) {
+ super(plugin, config);
+ miningLocations = new TreeMap<>();
+ violationLimiter = RateLimiting.createRateLimiter("antiCivBreak", 5, 5, 1, 2000L);
+ if (config.isEnabled()) {
+ registerPacketListener();
+ Bukkit.getPluginManager().registerEvents(this, plugin);
+ }
+ }
+
+ public static BasicHackConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
+ return new BasicHackConfig(plugin, config);
+ }
+
+ private void registerPacketListener() {
+ ProtocolManager manager = ProtocolLibrary.getProtocolManager();
+ manager.addPacketListener(new PacketAdapter(SimpleAdminHacks.instance(), PacketType.Play.Client.BLOCK_DIG) {
+ @Override
+ public void onPacketReceiving(PacketEvent event) {
+ PacketContainer packet = event.getPacket();
+ BlockPosition pos = packet.getBlockPositionModifier().read(0);
+ Location loc = pos.toLocation(event.getPlayer().getWorld());
+ switch (packet.getPlayerDigTypes().read(0)) {
+ case START_DESTROY_BLOCK:
+ handleStartDigging(event.getPlayer(), loc);
+ return;
+ case STOP_DESTROY_BLOCK:
+ handleFinishingDigging(event.getPlayer(), loc);
+ return;
+ default:
+ // some other stuff we dont care about
+ return;
+ }
+ }
+ });
+ }
+
+ @EventHandler
+ public void logOff(PlayerQuitEvent e) {
+ miningLocations.remove(e.getPlayer().getUniqueId());
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
+ public void blockBreak(BlockBreakEvent e) {
+ if (punishCooldown != null && punishCooldown.onCoolDown(e.getPlayer().getUniqueId())) {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(ChatColor.RED + "Denying break due to abnormal break speed");
+ }
+ }
+
+ private void handleStartDigging(Player player, Location loc) {
+ Map miningLocs = miningLocations.computeIfAbsent(player.getUniqueId(), p -> new HashMap<>());
+ miningLocs.putIfAbsent(loc, System.currentTimeMillis());
+ }
+
+ private void handleFinishingDigging(Player player, Location loc) {
+ Map miningLocs = miningLocations.computeIfAbsent(player.getUniqueId(), p -> new HashMap<>());
+ int ticksToBreak = getTicksToBreak(loc.getBlock(), player);
+ Long timeStarted = miningLocs.remove(loc);
+ if (timeStarted == null) {
+ if (ticksToBreak > 1) {
+ punish(player);
+ }
+ return;
+ }
+ if (ticksToBreak == 0) {
+ return;
+ }
+
+ long msToBreak = ticksToBreak * 50L;
+ long timePassed = System.currentTimeMillis() - timeStarted;
+ if (timePassed * laggLenciency < msToBreak) {
+ punish(player);
+ }
+ }
+
+ private void punish(Player player) {
+ if (punishCooldown == null) {
+ // delayed instanciation, because config values are not available in constructor
+ punishCooldown = new MilliSecCoolDownHandler<>(breakDenyDuration);
+ }
+ if (!violationLimiter.pullToken(player)) {
+ Bukkit.getScheduler().scheduleSyncDelayedTask(SimpleAdminHacks.instance(), () -> {
+ punishCooldown.putOnCoolDown(player.getUniqueId());
+ plugin().getLogger().info(String.format("%s is possibly using civ break, fast break detected", player.getName()));
+ player.sendMessage(ChatColor.RED + "You are breaking blocks too fast");
+ });
+ }
+ }
+
+ private static float getDamagePerTick(Material mat, Player player) {
+ ItemStack tool = player.getInventory().getItemInMainHand();
+ IBlockData blockData = getNMSBlockData(mat);
+ if (blockData == null) {
+ throw new IllegalArgumentException("Could not determine block break type for " + mat);
+ }
+ // if you ever need to version upgrade this, search for a method in n.m.s.Item
+ // calling
+ // "getDestroySpeed(this,blockData)" in n.m.s.ItemStack
+ float damagePerTick = CraftItemStack.asNMSCopy(tool).a(blockData);
+ // above method does not include efficiency or haste, so we add it ourselves
+ int effLevel = tool.getEnchantmentLevel(Enchantment.DIG_SPEED);
+ int efficiencyBonus = 0;
+ if (effLevel > 0 && isProperTool(tool, mat)) {
+ efficiencyBonus = effLevel * effLevel + 1;
+ }
+ damagePerTick += efficiencyBonus;
+ int hasteLevel = 0;
+ PotionEffect hasteEffect = player.getPotionEffect(PotionEffectType.FAST_DIGGING);
+ if (hasteEffect != null) {
+ // amplifier of 0 is potion effect at level one
+ hasteLevel = hasteEffect.getAmplifier() + 1;
+ }
+ damagePerTick *= 1.0 + 0.2 * hasteLevel;
+ return damagePerTick;
+ }
+
+ private static int getTicksToBreak(Block b, Player p) {
+ Material mat = b.getType();
+ if (!mat.isBlock() || MaterialAPI.isAir(mat)) {
+ // lagg, player is breaking a block already gone
+ return 0;
+ }
+ float damageToDeal = mat.getHardness() * 30;
+ float damagePerTick = getDamagePerTick(mat, p);
+ if (damageToDeal <= damagePerTick) {
+ // instabreak
+ return 0;
+ }
+ return (int) Math.ceil(damageToDeal / damagePerTick);
+ }
+
+ private static boolean isProperTool(ItemStack tool, Material block) {
+ net.minecraft.server.v1_14_R1.Block nmsBlock = org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers
+ .getBlock(block);
+ if (nmsBlock == null) {
+ return false;
+ }
+ net.minecraft.server.v1_14_R1.IBlockData data = nmsBlock.getBlockData();
+ return data.getMaterial().isAlwaysDestroyable() || tool != null && tool.getType() != Material.AIR
+ && org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers.getItem(tool.getType())
+ .canDestroySpecialBlock(data);
+ }
+
+ private static IBlockData getNMSBlockData(Material mat) {
+ net.minecraft.server.v1_14_R1.Block nmsBlock = org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers
+ .getBlock(mat);
+ if (nmsBlock == null) {
+ return null;
+ }
+ return nmsBlock.getBlockData();
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/ArthropodEggHack.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/ArthropodEggHack.java
new file mode 100644
index 00000000..44e7c243
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/ArthropodEggHack.java
@@ -0,0 +1,93 @@
+package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
+
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Ageable;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.inventory.ItemStack;
+
+import com.programmerdan.minecraft.simpleadminhacks.BasicHack;
+import com.programmerdan.minecraft.simpleadminhacks.BasicHackConfig;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+import com.programmerdan.minecraft.simpleadminhacks.autoload.AutoLoad;
+
+import vg.civcraft.mc.civmodcore.api.SpawnEggAPI;
+
+public class ArthropodEggHack extends BasicHack {
+
+ @AutoLoad
+ private double eggChance;
+
+ @AutoLoad
+ private double lootingChance;
+
+ @AutoLoad
+ private boolean removeDrops;
+
+ @AutoLoad
+ private List allowedTypes;
+
+ public ArthropodEggHack(SimpleAdminHacks plugin, BasicHackConfig config) {
+ super(plugin, config);
+ }
+
+ public static BasicHackConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
+ return new BasicHackConfig(plugin, config);
+ }
+
+ @EventHandler
+ public void onEntityDeath(EntityDeathEvent event) {
+ Player targetPlayer = event.getEntity().getKiller();
+ if (null == targetPlayer) {
+ return;
+ }
+
+ String type = event.getEntity().getType().toString();
+ if (allowedTypes == null || !allowedTypes.contains(type)) {
+ return;
+ }
+
+ // Check for a baby animal
+ if (event.getEntity() instanceof Ageable) {
+ Ageable ageableEntity = (Ageable) event.getEntity();
+ if (!ageableEntity.isAdult()) {
+ return;
+ }
+ }
+
+ // Check the player's currently equipped weapon
+ ItemStack handstack = targetPlayer.getEquipment().getItemInMainHand();
+ // Get the map of enchantments on that item
+ Map itemEnchants = handstack.getEnchantments();
+ if (itemEnchants.isEmpty()) {
+ return;
+ }
+
+ // Check if one enchantment is BaneOfArthropods
+ if (null == itemEnchants.get(Enchantment.DAMAGE_ARTHROPODS)) {
+ return;
+ }
+
+ double randomNum = Math.random();
+ double levelOfArthropod = handstack.getEnchantmentLevel(Enchantment.DAMAGE_ARTHROPODS);
+ double levelOfLooting = handstack.getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS);
+
+ double targetPercentage = (eggChance * levelOfArthropod) + (lootingChance * levelOfLooting);
+
+ // Check if egg should be spawned
+ if (randomNum < targetPercentage) {
+ ItemStack item = new ItemStack(SpawnEggAPI.getSpawnEgg(event.getEntityType()), 1);
+ if (removeDrops) {
+ event.getDrops().clear();
+ event.setDroppedExp(0);
+ }
+ event.getDrops().add(item);
+ }
+ }
+
+}
diff --git a/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/EventDebugHack.java b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/EventDebugHack.java
new file mode 100644
index 00000000..7d472610
--- /dev/null
+++ b/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/EventDebugHack.java
@@ -0,0 +1,234 @@
+package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.Server;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.craftbukkit.libs.org.apache.commons.lang3.ClassUtils;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
+import org.bukkit.event.EventException;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.EventExecutor;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.RegisteredListener;
+
+import com.programmerdan.minecraft.simpleadminhacks.BasicHack;
+import com.programmerdan.minecraft.simpleadminhacks.BasicHackConfig;
+import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
+
+public class EventDebugHack extends BasicHack {
+
+ private Map, List> classToListeners;
+ private Map, HandlerList> classToHandler;
+
+ public EventDebugHack(SimpleAdminHacks plugin, BasicHackConfig config) {
+ super(plugin, config);
+ classToListeners = new HashMap<>();
+ classToHandler = new HashMap<>();
+ }
+
+ public static BasicHackConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
+ return new BasicHackConfig(plugin, config);
+ }
+
+ @Override
+ public void registerCommands() {
+ plugin().registerCommand("debugevent", new CommandExecutor() {
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command arg1, String arg2, String[] args) {
+ if (args.length == 0) {
+ sender.sendMessage(ChatColor.RED + "You must give an event");
+ return false;
+ }
+ if (untargetEvent(args[0])) {
+ sender.sendMessage(ChatColor.GREEN + "Disabled tracking for " + args[0]);
+ return true;
+ }
+ targetEvent(args[0], sender);
+ return true;
+ }
+ });
+ }
+
+ public boolean untargetEvent(String eventName) {
+ Class extends Event> eventClass = getEventClass(eventName);
+ if (eventClass == null) {
+ return false;
+ }
+ HandlerList handler = classToHandler.get(eventClass);
+ List listeners = classToListeners.get(eventClass);
+ if (handler == null || listeners == null) {
+ return false;
+ }
+ listeners.forEach(handler::unregister);
+ classToHandler.remove(eventClass);
+ classToListeners.remove(eventClass);
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class extends Event> getEventClass(String eventName) {
+ if (eventName.startsWith(".")) {
+ eventName = "org.bukkit.event" + eventName;
+ }
+ try {
+ return (Class) Class.forName(eventName);
+ } catch (ClassCastException | ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ public void targetEvent(String eventName, CommandSender sender) {
+ Class extends Event> eventClass = getEventClass(eventName);
+ if (eventClass == null) {
+ sender.sendMessage(ChatColor.RED + "No event class with that path exists");
+ return;
+ }
+ if (classToHandler.containsKey(eventClass)) {
+ sender.sendMessage(ChatColor.RED + "Event is already being investigated");
+ return;
+ }
+ Method handlerGetter;
+ try {
+ handlerGetter = eventClass.getMethod("getHandlerList");
+ } catch (NoSuchMethodException | SecurityException e) {
+ sender.sendMessage(ChatColor.RED + "The class did not have a handler getter");
+ return;
+ }
+ if (handlerGetter.getReturnType() != HandlerList.class) {
+ sender.sendMessage(ChatColor.RED + "Getter had wrong return type");
+ return;
+ }
+ HandlerList handlerList;
+ try {
+ handlerList = (HandlerList) handlerGetter.invoke(eventClass);
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ sender.sendMessage(ChatColor.RED + "Could not invoke handler getter");
+ return;
+ }
+ sender.sendMessage(
+ ChatColor.GOLD + "Currently registered listeners for " + eventClass.getSimpleName() + " are:");
+ for (RegisteredListener listener : handlerList.getRegisteredListeners()) {
+ for (Method method : listener.getListener().getClass().getMethods()) {
+ if (method.isBridge() || method.isSynthetic()) {
+ continue;
+ }
+ if (Modifier.isStatic(method.getModifiers())) {
+ continue;
+ }
+ if (!method.isAnnotationPresent(EventHandler.class)) {
+ continue;
+ }
+ if (method.getParameterCount() != 1) {
+ continue;
+ }
+ Class> clazz = method.getParameterTypes()[0];
+ if (clazz != eventClass) {
+ continue;
+ }
+ sender.sendMessage(String.format("[%s] on %s is %s", listener.getPlugin().getName(),
+ listener.getPriority(), listener.getListener().getClass().getSimpleName()));
+ }
+ }
+ Listener fakeListener = new Listener() {
+ };
+ // need to hack our listener in, because can't dynamically declare an actual
+ // class with annotations etc.
+ List listeners = new LinkedList<>();
+ for (EventPriority prio : EventPriority.values()) {
+ RegisteredListener listener = new RegisteredListener(fakeListener, new EventExecutor() {
+
+ @Override
+ public void execute(Listener arg0, Event arg1) throws EventException {
+ printEventState(prio, arg1);
+ }
+ }, prio, SimpleAdminHacks.instance(), false);
+ listeners.add(listener);
+ handlerList.register(listener);
+ }
+ classToHandler.put(eventClass, handlerList);
+ classToListeners.put(eventClass, listeners);
+ }
+
+ private void printEventState(EventPriority prio, Event event) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("At stage " + prio.toString() + " " + event.getEventName() + " is as follows: \n");
+ deepInspectObject(event, "event", sb, 0, new HashSet<>());
+ SimpleAdminHacks.instance().getLogger().info(sb.toString());
+ }
+
+ private static void deepInspectObject(Object o, String fieldName, StringBuilder sb, int depth, Set