diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0331d89
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,62 @@
+
+ 4.0.0
+
+ com.zivilon
+ AdminTools
+ 1.4
+ jar
+
+ AdminTools
+
+
+ UTF-8
+ 1.7
+ 1.7
+
+
+
+
+
+ org.bukkit
+ bukkit
+ 1.7.10-R0.1-SNAPSHOT
+ provided
+
+
+ com.github.flinbein
+ PowerNBT
+ 0.8.9.2
+
+
+ com.sk89q
+ worldguard
+ 6.1.2
+
+
+ com.comphenix.protocol
+ ProtocolLib
+ 3.6.5
+ provided
+
+
+
+ package
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ 1.8
+ 1.8
+
+
+
+
+
diff --git a/src/main/java/com/zivilon/admintools/AdminTools.java b/src/main/java/com/zivilon/admintools/AdminTools.java
new file mode 100644
index 0000000..fd02619
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/AdminTools.java
@@ -0,0 +1,90 @@
+package com.zivilon.admintools;
+
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.ProtocolLibrary;
+
+import com.zivilon.admintools.commands.clean_entities_command;
+import com.zivilon.admintools.commands.count_units_command;
+import com.zivilon.admintools.commands.chunkloader_command;
+import com.zivilon.admintools.commands.block_swap_command;
+import com.zivilon.admintools.commands.world_summon_command;
+import com.zivilon.admintools.commands.world_setblock_command;
+import com.zivilon.admintools.commands.set_login_location_command;
+import com.zivilon.admintools.commands.area_message_command;
+import com.zivilon.admintools.commands.areaeffect_command;
+import com.zivilon.admintools.commands.effect_command;
+import com.zivilon.admintools.commands.check_players_command;
+import com.zivilon.admintools.commands.region_teleport_command;
+import com.zivilon.admintools.commands.entity_effect_command;
+import com.zivilon.admintools.listeners.ranged_immunity_listener;
+
+public class AdminTools extends JavaPlugin {
+ private ProtocolManager protocolManager;
+ private FileConfiguration unitNamesConfig;
+ private FileConfiguration chunkLoaderConfig;
+
+ @Override
+ public void onEnable() {
+ saveDefaultConfig();
+ this.unitNamesConfig = loadConfigFile("unit_names.yml");
+ this.chunkLoaderConfig = loadConfigFile("chunkloaders.yml");
+
+ protocolManager = ProtocolLibrary.getProtocolManager();
+
+ // Register the /clean_entities command
+ this.getCommand("clean_entities").setExecutor(new clean_entities_command());
+ // Register the /count_units command
+ this.getCommand("count_units").setExecutor(new count_units_command(this));
+ // Register the /chunkloader command
+ this.getCommand("chunkloader").setExecutor(new chunkloader_command(this));
+ // Register the /block_swap command
+ this.getCommand("block_swap").setExecutor(new block_swap_command(protocolManager));
+ // Register the /wsummon command
+ this.getCommand("wsummon").setExecutor(new world_summon_command());
+ // Register the /wsetblock command
+ this.getCommand("wsetblock").setExecutor(new world_setblock_command());
+ // Register the /set_login_location command
+ this.getCommand("set_login_location").setExecutor(new set_login_location_command());
+ // Register the /area_message command
+ this.getCommand("area_message").setExecutor(new area_message_command());
+ // Register the /areaeffect command
+ this.getCommand("areaeffect").setExecutor(new areaeffect_command());
+ // Register the /effect command
+ this.getCommand("effect").setExecutor(new effect_command());
+ // Register the /check_players command
+ this.getCommand("check_players").setExecutor(new check_players_command(this));
+ // Register the /check_players command
+ this.getCommand("region_tp").setExecutor(new region_teleport_command(this));
+ // Register the /entityeffect command
+ this.getCommand("entityeffect").setExecutor(new entity_effect_command());
+
+
+ getServer().getPluginManager().registerEvents(new ranged_immunity_listener(this), this);
+ }
+
+ @Override
+ public void onDisable() {
+ }
+
+ public FileConfiguration getUnitNamesConfig() {
+ return this.unitNamesConfig;
+ }
+
+ public FileConfiguration getChunkLoaderConfig() {
+ return this.chunkLoaderConfig;
+ }
+
+ private FileConfiguration loadConfigFile(String fileName) {
+ File file = new File(getDataFolder(), fileName);
+ if (!file.exists()) {
+ saveResource(fileName, false);
+ }
+ return YamlConfiguration.loadConfiguration(file);
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/area_message_command.java b/src/main/java/com/zivilon/admintools/commands/area_message_command.java
new file mode 100644
index 0000000..29863ac
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/area_message_command.java
@@ -0,0 +1,91 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class area_message_command implements CommandExecutor {
+
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission("admintools.area_message")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+ double x, y, z, radius;
+ if (args.length < 6) {
+ sender.sendMessage("Usage: /area_message [-d -s] ");
+ return false;
+
+ }
+
+ boolean debug_flag = false;
+ boolean silent_flag = false;
+ int argument_offset = 0; // this offset helps us handle the arguments correctly
+
+ // Iterate over flags
+ for (; argument_offset < args.length; argument_offset++) {
+ if (args[argument_offset].startsWith("-")) {
+ debug_flag |= args[argument_offset].contains("d");
+ silent_flag |= args[argument_offset].contains("s");
+ } else {
+ break;
+ }
+ }
+
+ if (args.length - argument_offset < 6) {
+ if (debug_flag) sender.sendMessage("Failed at args.length - argument_offset < 6 with args.length " + args.length + " and argument_offset " + argument_offset);
+ sender.sendMessage(ChatColor.RED + "Usage: /area_message [-d -s] ");
+ return false;
+ }
+
+ World world = Bukkit.getWorld(args[0 + argument_offset]);
+
+ try {
+ x = Double.parseDouble(args[1 + argument_offset]);
+ y = Double.parseDouble(args[2 + argument_offset]);
+ z = Double.parseDouble(args[3 + argument_offset]);
+ radius = Double.parseDouble(args[4 + argument_offset]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(ChatColor.RED + "Coordinates and radius need to be numbers.");
+ return true;
+ }
+
+ if (world == null) {
+ sender.sendMessage(ChatColor.RED + String.format("There is no such world with name %s.", args[0 + argument_offset]));
+ return true;
+ }
+
+ // Construct the location object
+ Location target_location = new Location(world, x, y, z);
+
+ // Construct the message from the remaining arguments
+ StringBuilder message_builder = new StringBuilder();
+ for (int i = 5 + argument_offset; i < args.length; i++) {
+ message_builder.append(args[i]);
+ if (i != args.length - 1) {
+ message_builder.append(" ");
+ }
+ }
+ String message = message_builder.toString();
+ String coloredMessage = ChatColor.translateAlternateColorCodes('&', message);
+
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.getWorld().equals(world) && player.getLocation().distanceSquared(target_location) <= Math.pow(radius, 2)) {
+ player.sendMessage(coloredMessage);
+ }
+ }
+
+
+ // If the command is not silent, inform the command sender
+ if (!silent_flag) {
+ sender.sendMessage(ChatColor.GREEN + "Message has been sent.");
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/areaeffect_command.java b/src/main/java/com/zivilon/admintools/commands/areaeffect_command.java
new file mode 100644
index 0000000..d1d89bb
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/areaeffect_command.java
@@ -0,0 +1,88 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.potion.PotionEffect;
+
+
+public class areaeffect_command implements CommandExecutor {
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission("admintools.areaeffect")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ if (args.length < 8) {
+ sender.sendMessage("Incorrect arguments. Usage: /areaeffect [-d -s] ");
+ return true;
+ }
+
+ boolean debug_flag = false;
+ boolean silent_flag = false;
+ int argument_offset = 0; // this offset helps us handle the arguments correctly
+
+ // Iterate over flags
+ for (; argument_offset < args.length; argument_offset++) {
+ if (args[argument_offset].startsWith("-")) {
+ debug_flag |= args[argument_offset].contains("d");
+ silent_flag |= args[argument_offset].contains("s");
+ } else {
+ break;
+ }
+ }
+
+ if (args.length < (8 + argument_offset)) {
+ sender.sendMessage("Incorrect arguments. Usage: /areaeffect [-d -s] ");
+ return true;
+ }
+
+ try {
+ String worldName = args[0 + argument_offset]; // Get the world name from the arguments
+ int x = Integer.parseInt(args[1 + argument_offset]);
+ int y = Integer.parseInt(args[2 + argument_offset]);
+ int z = Integer.parseInt(args[3 + argument_offset]);
+ int radius = Integer.parseInt(args[4 + argument_offset]);
+ String effectName = args[5 + argument_offset];
+ int duration = Integer.parseInt(args[6 + argument_offset]) * 20; // Convert duration from seconds to ticks
+ int level = Integer.parseInt(args[7 + argument_offset]);
+
+ PotionEffectType effectType = PotionEffectType.getByName(effectName);
+ if (effectType == null) {
+ sender.sendMessage("Invalid effect name!");
+ return true;
+ }
+
+ World world = Bukkit.getServer().getWorld(worldName);
+ if (world == null) {
+ sender.sendMessage("World " + worldName + " not found!");
+ return true;
+ }
+
+ Location center = new Location(world, x, y, z);
+ for (Player player : Bukkit.getServer().getOnlinePlayers()) {
+ if (player.getWorld().equals(world) && player.getLocation().distance(center) <= radius) {
+ if(level == 0){
+ if(player.hasPotionEffect(effectType)){
+ player.removePotionEffect(effectType);
+ if (!silent_flag) sender.sendMessage("Removed " + effectName + " from " + player.getName());
+ }
+ }else{
+ player.addPotionEffect(new PotionEffect(effectType, duration, level - 1, false), true);
+ if (!silent_flag) sender.sendMessage("Added " + effectName + " level " + level + " to " + player.getName());
+ }
+ }
+ }
+ } catch (NumberFormatException e) {
+ sender.sendMessage("Invalid number format!");
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/block_swap_command.java b/src/main/java/com/zivilon/admintools/commands/block_swap_command.java
new file mode 100644
index 0000000..260f1ec
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/block_swap_command.java
@@ -0,0 +1,100 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.ChatColor;
+import org.bukkit.material.MaterialData;
+import org.bukkit.entity.Player;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.events.PacketContainer;
+
+import java.lang.reflect.InvocationTargetException;
+
+public class block_swap_command implements CommandExecutor {
+ private ProtocolManager protocolManager;
+
+ public block_swap_command(ProtocolManager protocolManager) {
+ this.protocolManager = protocolManager;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission("admintools.block_swap")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+ if(args.length != 4){
+ sender.sendMessage("Incorrect command format! Use: /block_swap ");
+ return true;
+ }
+
+ String[] corner1 = args[0].split(",");
+ String[] corner2 = args[1].split(",");
+ String[] materialDataArg = args[2].split(":");
+ String playerName = args[3];
+
+ if (corner1.length != 3 || corner2.length != 3 || materialDataArg.length != 2) {
+ sender.sendMessage("Incorrect command format! Use: /block_swap ");
+ return true;
+ }
+
+ try {
+ int x1 = Integer.parseInt(corner1[0]);
+ int y1 = Integer.parseInt(corner1[1]);
+ int z1 = Integer.parseInt(corner1[2]);
+
+ int x2 = Integer.parseInt(corner2[0]);
+ int y2 = Integer.parseInt(corner2[1]);
+ int z2 = Integer.parseInt(corner2[2]);
+
+ Material material = Material.getMaterial(materialDataArg[0].toUpperCase());
+ if (material == null) {
+ sender.sendMessage("Invalid material: " + materialDataArg[0]);
+ return true;
+ }
+
+ int data = Integer.parseInt(materialDataArg[1]);
+
+ Player targetPlayer = Bukkit.getServer().getPlayer(playerName);
+ if (targetPlayer == null) {
+ sender.sendMessage("Could not find player: " + playerName);
+ return true;
+ }
+
+ MaterialData materialData = new MaterialData(material, (byte) data);
+
+ for (int x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) {
+ for (int y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) {
+ for (int z = Math.min(z1, z2); z <= Math.max(z1, z2); z++) {
+ Location location = new Location(targetPlayer.getWorld(), x, y, z);
+ PacketContainer packet = protocolManager.createPacket(PacketType.Play.Server.BLOCK_CHANGE);
+ packet.getIntegers()
+ .write(0, location.getBlockX())
+ .write(1, location.getBlockY())
+ .write(2, location.getBlockZ());
+ packet.getBlocks().write(0, materialData.getItemType());
+ packet.getIntegers().write(3, (int) materialData.getData());
+
+ try {
+ protocolManager.sendServerPacket(targetPlayer, packet);
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ } catch (NumberFormatException e){
+ sender.sendMessage("The coordinates and data must be integers!");
+ return true;
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/zivilon/admintools/commands/check_players_command.java b/src/main/java/com/zivilon/admintools/commands/check_players_command.java
new file mode 100644
index 0000000..64118fd
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/check_players_command.java
@@ -0,0 +1,97 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Location;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.Location;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
+import com.sk89q.worldguard.protection.managers.RegionManager;
+import com.sk89q.worldguard.protection.regions.ProtectedRegion;
+
+import com.zivilon.admintools.AdminTools;
+
+public class check_players_command implements CommandExecutor {
+
+ private final AdminTools plugin;
+ private WorldGuardPlugin worldGuardPlugin;
+
+ public check_players_command(AdminTools plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ if (!sender.hasPermission("admintools.check_players")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ if (args.length < 3) {
+ sender.sendMessage("Usage: /check_players ");
+ return true;
+ }
+
+ // Logic to join arguments for command-if-empty
+ StringBuilder commandIfEmpty = new StringBuilder();
+ int i = 1;
+ while (i < args.length && !args[i].endsWith("\"")) {
+ commandIfEmpty.append(args[i]).append(" ");
+ i++;
+ }
+ commandIfEmpty.append(args[i]);
+
+ String emptyCommand = commandIfEmpty.toString().replaceAll("\"", "").trim();
+
+ // Logic to join arguments for command-if-players
+ StringBuilder commandIfPlayers = new StringBuilder();
+ i++;
+ while (i < args.length && !args[i].endsWith("\"")) {
+ commandIfPlayers.append(args[i]).append(" ");
+ i++;
+ }
+ commandIfPlayers.append(args[i]);
+
+ String playersCommand = commandIfPlayers.toString().replaceAll("\"", "").trim();
+
+ Plugin plugin = Bukkit.getServer().getPluginManager().getPlugin("WorldGuard");
+ if (plugin instanceof WorldGuardPlugin) {
+ worldGuardPlugin = (WorldGuardPlugin) plugin;
+ }
+
+ World dim100World = Bukkit.getWorld("DIM100");
+ if (dim100World == null) {
+ plugin.getLogger().warning("World DIM100 not found! Ensure the world name is correct.");
+ return true;
+ }
+
+ RegionManager regionManager = worldGuardPlugin.getRegionManager(dim100World);
+
+ boolean playersFound = false;
+
+ String[] regionNames = args[0].split(","); // Split region names by comma
+
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ for (String regionName : regionNames) {
+ ProtectedRegion region = regionManager.getRegion(regionName);
+ if (region != null && region.contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ())) {
+ playersFound = true;
+ break;
+ }
+ }
+ if (playersFound) break; // Break outer loop if players are found in any of the specified regions
+ }
+
+ // Execute the appropriate command based on player presence
+ String commandToExecute = playersFound ? playersCommand : emptyCommand;
+ plugin.getServer().dispatchCommand(sender, commandToExecute);
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/chunkloader_command.java b/src/main/java/com/zivilon/admintools/commands/chunkloader_command.java
new file mode 100644
index 0000000..d4fd0d4
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/chunkloader_command.java
@@ -0,0 +1,268 @@
+package com.zivilon.admintools.commands;
+
+import com.zivilon.admintools.AdminTools;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.entity.Player;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.lang.Math.abs;
+
+public class chunkloader_command implements CommandExecutor {
+
+ private final AdminTools plugin;
+ private final Map chunkLoaders = new HashMap<>();
+ private final FileConfiguration chunkLoaderConfig;
+
+ public chunkloader_command(AdminTools plugin) {
+ this.plugin = plugin;
+ this.chunkLoaderConfig = plugin.getChunkLoaderConfig();
+ loadChunkLoaders();
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ if (!sender.hasPermission("admintools.chunkloader")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ Player player = null;
+ if (sender instanceof Player) {
+ player = (Player) sender;
+ }
+
+ if (cmd.getName().equalsIgnoreCase("chunkloader")) {
+ if (args.length == 0) {
+ sender.sendMessage(ChatColor.YELLOW + "Usage: /chunkloader create [ ]");
+ sender.sendMessage(ChatColor.YELLOW + " /chunkloader load ");
+ sender.sendMessage(ChatColor.YELLOW + " /chunkloader delete ");
+ sender.sendMessage(ChatColor.YELLOW + " /chunkloader isloaded ");
+ return true;
+ }
+
+ if (args[0].equalsIgnoreCase("create")) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(ChatColor.RED + "This command can only be run by a player!");
+ return true;
+ }
+
+ if (args.length < 3 || args.length > 5) {
+ sender.sendMessage(ChatColor.RED + "Usage: /chunkloader create [ ]");
+ return true;
+ }
+
+ String name = args[1];
+ int radius = Integer.parseInt(args[2]);
+ Location location = args.length == 5 ?
+ new Location(player.getWorld(), Double.parseDouble(args[3]), 0.0, Double.parseDouble(args[4])) :
+ player.getLocation();
+
+ ChunkLoader loader = new ChunkLoader(name, location, radius);
+ chunkLoaders.put(name, loader);
+ loader.saveChunkLoader(loader);
+ saveConfig();
+
+ sender.sendMessage(ChatColor.GREEN + "Chunk loader " + name + " created!");
+ return true;
+ }
+
+ if (args[0].equalsIgnoreCase("load")) {
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Usage: /chunkloader load ");
+ return true;
+ }
+
+ String name = args[1];
+ ChunkLoader loader = chunkLoaders.get(name);
+
+ if (loader == null) {
+ sender.sendMessage(ChatColor.RED + "Chunk loader " + name + " not found!");
+ return true;
+ }
+
+ loader.loadChunk();
+ sender.sendMessage(ChatColor.GREEN + "Chunk loader " + name + " loaded!");
+ return true;
+ }
+
+ if (args[0].equalsIgnoreCase("delete")) {
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Usage: /chunkloader delete ");
+ return true;
+ }
+
+ String name = args[1];
+ ChunkLoader loader = chunkLoaders.get(name);
+
+ if (loader == null) {
+ sender.sendMessage(ChatColor.RED + "Chunk loader " + name + " not found!");
+ return true;
+ }
+
+ chunkLoaders.remove(name);
+ chunkLoaderConfig.set(name, null);
+ saveConfig();
+
+ sender.sendMessage(ChatColor.GREEN + "Chunk loader " + name + " deleted!");
+ return true;
+ }
+
+ if (args[0].equalsIgnoreCase("isloaded")) {
+ if (args.length != 3) {
+ sender.sendMessage(ChatColor.RED + "Usage: /chunkloader isloaded ");
+ return true;
+ }
+
+ int x = Integer.parseInt(args[1]);
+ int z = Integer.parseInt(args[2]);
+ World world = player.getWorld();
+ Location location = new Location(world, x, 0, z);
+
+ if (isChunkLoaded(location)) {
+ sender.sendMessage(ChatColor.GREEN + "Chunk is loaded!");
+ } else {
+ sender.sendMessage(ChatColor.RED + "Chunk is not loaded!");
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isChunkLoaded(Location location) {
+ int chunkX = location.getBlockX() >> 4;
+ int chunkZ = location.getBlockZ() >> 4;
+ World world = location.getWorld();
+ return world.isChunkLoaded(chunkX, chunkZ);
+ }
+
+ public class ChunkLoader {
+ private String name;
+ private Location location;
+ private int radius;
+
+ public ChunkLoader(String name, Location location, int radius) {
+ this.name = name;
+ this.location = location;
+ this.radius = radius;
+ }
+
+ public ChunkLoader(ConfigurationSection config) {
+ this.name = config.getName();
+ this.location = new Location(
+ Bukkit.getWorld(config.getString("world")),
+ config.getDouble("x"),
+ config.getDouble("y"),
+ config.getDouble("z"));
+ this.radius = config.getInt("radius");
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public Location getLocation() {
+ return this.location;
+ }
+
+ public int getRadius() {
+ return this.radius;
+ }
+
+ public void saveChunkLoader(ChunkLoader loader) {
+ String name = loader.getName();
+ Location location = loader.getLocation();
+ int radius = loader.getRadius();
+
+ ConfigurationSection loaderSection = chunkLoaderConfig.createSection("chunkloaders." + name);
+
+ loaderSection.set("world", location.getWorld().getName());
+ loaderSection.set("x", location.getX());
+ loaderSection.set("y", location.getY());
+ loaderSection.set("z", location.getZ());
+ loaderSection.set("radius", radius);
+ }
+
+
+ public boolean containsChunk(Chunk chunk) {
+ int chunkX = chunk.getX();
+ int chunkZ = chunk.getZ();
+ int centerChunkX = location.getBlockX() >> 4;
+ int centerChunkZ = location.getBlockZ() >> 4;
+ return abs(chunkX - centerChunkX) <= radius && abs(chunkZ - centerChunkZ) <= radius;
+ }
+
+ public void loadChunk() {
+ // Load all chunks within the radius
+ World world = location.getWorld();
+ int centerChunkX = location.getBlockX() >> 4;
+ int centerChunkZ = location.getBlockZ() >> 4;
+ int radiusChunks = (radius >> 4) + 1;
+ for (int dx = -radiusChunks; dx <= radiusChunks; dx++) {
+ for (int dz = -radiusChunks; dz <= radiusChunks; dz++) {
+ int chunkX = centerChunkX + dx;
+ int chunkZ = centerChunkZ + dz;
+ Chunk chunk = world.getChunkAt(chunkX, chunkZ);
+ chunk.load();
+ }
+ }
+ }
+
+ private boolean chunkInUse(Chunk chunk) {
+ return Bukkit.getOnlinePlayers().stream()
+ .anyMatch(player -> player.getWorld().equals(chunk.getWorld())
+ && player.getLocation().getBlockX() >> 4 == chunk.getX()
+ && player.getLocation().getBlockZ() >> 4 == chunk.getZ());
+ }
+ }
+
+ private void loadChunkLoaders() {
+ if (chunkLoaderConfig.isConfigurationSection("chunkloaders")) {
+ ConfigurationSection loaderSection = chunkLoaderConfig.getConfigurationSection("chunkloaders");
+ for (String key : loaderSection.getKeys(false)) {
+ ConfigurationSection loaderConfig = loaderSection.getConfigurationSection(key);
+
+ String name = key;
+ String worldName = loaderConfig.getString("world");
+ double x = loaderConfig.getDouble("x");
+ double y = loaderConfig.getDouble("y");
+ double z = loaderConfig.getDouble("z");
+ int radius = loaderConfig.getInt("radius");
+
+ World world = Bukkit.getServer().getWorld(worldName);
+
+ if (world != null) {
+ // Create a new ChunkLoader object and add it to the map
+ ChunkLoader loader = new ChunkLoader(name, new Location(world, x, y, z), radius);
+ chunkLoaders.put(name, loader);
+ } else {
+ Bukkit.getLogger().warning("Could not load chunkloader " + name + ": World " + worldName + " not found");
+ }
+ }
+ }
+ }
+
+
+
+ private void saveConfig() {
+ try {
+ chunkLoaderConfig.save(new File(plugin.getDataFolder(), "chunkloaders.yml"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/clean_entities_command.java b/src/main/java/com/zivilon/admintools/commands/clean_entities_command.java
new file mode 100644
index 0000000..92b8882
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/clean_entities_command.java
@@ -0,0 +1,98 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+
+import me.dpohvar.powernbt.api.NBTCompound;
+import me.dpohvar.powernbt.api.NBTManager;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class clean_entities_command implements CommandExecutor {
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+
+ if (!sender.hasPermission("admintools.clean_entities")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ if(args.length != 6){
+ sender.sendMessage("Incorrect command format! Use: /cleanentities ");
+ return true;
+ }
+
+ int x, y, z, radius;
+ try {
+ x = Integer.parseInt(args[0]);
+ y = Integer.parseInt(args[1]);
+ z = Integer.parseInt(args[2]);
+ radius = Integer.parseInt(args[4]);
+ } catch (NumberFormatException e){
+ sender.sendMessage("The coordinates and radius must be integers!");
+ return true;
+ }
+
+ World world = Bukkit.getWorld(args[3]);
+ if (world == null) {
+ sender.sendMessage("Invalid world: " + args[3]);
+ return true;
+ }
+
+ String targetEntityId = args[5];
+ if (!targetEntityId.equals("ALL") && targetEntityId.isEmpty()) {
+ sender.sendMessage("Invalid entity ID: " + args[5]);
+ return true;
+ }
+
+ Location center = new Location(world, x, y, z);
+
+ // Convert wildcard format to regex
+ String regex = targetEntityId.replaceAll("\\*", ".*");
+
+ // Obtain an instance of NBTManager
+ NBTManager nbtManager = me.dpohvar.powernbt.PowerNBT.getApi();
+
+ // List of entities to exclude from deletion
+ List excludeEntityIds = Arrays.asList("lotr.WallBanner", "lotr.Banner", "ItemFrame");
+
+ for (Entity entity : world.getEntities()) {
+ if (entity != null && entity.getLocation().distance(center) <= radius) {
+ // Skip if the entity is a player
+ if (entity instanceof Player) {
+ continue;
+ }
+
+ // Get NBT data of entity
+ NBTCompound nbtData = nbtManager.read(entity);
+
+ String entityId = (String) nbtData.get("id");
+ if (entityId == null) {
+ continue;
+ }
+
+ if (excludeEntityIds.contains(entityId)) {
+ continue;
+ }
+
+ // If a specific entityId is provided, only delete entities that match the pattern
+ if (!targetEntityId.equals("ALL") && !Pattern.matches(regex, entityId)) {
+ continue;
+ }
+
+ // Delete the entity if not excluded
+ entity.remove();
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/count_units_command.java b/src/main/java/com/zivilon/admintools/commands/count_units_command.java
new file mode 100644
index 0000000..b4e6431
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/count_units_command.java
@@ -0,0 +1,131 @@
+package com.zivilon.admintools.commands;
+
+import me.dpohvar.powernbt.api.NBTCompound;
+import me.dpohvar.powernbt.api.NBTManager;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import com.zivilon.admintools.AdminTools;
+
+public class count_units_command implements CommandExecutor {
+ private final AdminTools plugin;
+
+ public count_units_command(AdminTools plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+
+ if (!sender.hasPermission("admintools.count_units")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ FileConfiguration unitNamesConfig = plugin.getUnitNamesConfig();
+
+ if(args.length < 1 || args.length > 3){
+ sender.sendMessage("Incorrect command format! Use: /count_units [-d] [radius]");
+ return true;
+ }
+
+ boolean debug = false;
+ String playerName;
+ int radius = 100;
+
+ if(args[0].equals("-d")){
+ debug = true;
+ playerName = args[1];
+ if(args.length == 3){
+ try {
+ radius = Integer.parseInt(args[2]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage("The radius must be an integer!");
+ return true;
+ }
+ }
+ }
+ else{
+ playerName = args[0];
+ if(args.length == 2){
+ try {
+ radius = Integer.parseInt(args[1]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage("The radius must be an integer!");
+ return true;
+ }
+ }
+ }
+
+ Player targetPlayer = Bukkit.getPlayer(playerName);
+ if (targetPlayer == null) {
+ sender.sendMessage("Invalid player: " + playerName);
+ return true;
+ }
+
+ if(debug) {
+ sender.sendMessage("Passed argument check");
+ }
+ Location playerLoc = targetPlayer.getLocation();
+ UUID playerUUID = targetPlayer.getUniqueId();
+ if (debug) {sender.sendMessage("Passed coordinate retrieval");}
+
+ NBTManager nbtManager = me.dpohvar.powernbt.PowerNBT.getApi();
+
+ // Use a map to keep count of the different types of entities
+ Map entityCounts = new HashMap<>();
+
+ for (Entity entity : playerLoc.getWorld().getEntities()) {
+ if (entity.getLocation().distance(playerLoc) <= radius) {
+ if (debug) {sender.sendMessage("FOR LOOP: Passed distance check");}
+
+ // Get NBT data of entity
+ NBTCompound nbtData = nbtManager.read(entity);
+ NBTCompound hiredNPCInfo = (NBTCompound) nbtData.get("HiredNPCInfo");
+
+ if (debug) {sender.sendMessage("FOR LOOP: Started HiredNPCInfo null check on " + nbtData.get("id"));}
+ if (hiredNPCInfo == null) {
+ if (debug) {sender.sendMessage("FOR LOOP: Is null");}
+ continue;
+ }
+
+ if (debug) {sender.sendMessage("FOR LOOP: Started HiringPlayerUUID null check");}
+ String hiringPlayerUUID = (String) hiredNPCInfo.get("HiringPlayerUUID");
+ if (hiringPlayerUUID == null) {
+ if (debug) {sender.sendMessage("FOR LOOP: Is null");}
+ continue;
+ }
+ if (debug) {sender.sendMessage("FOR LOOP: Passed HiredNPCInfo null check");}
+
+ if (hiringPlayerUUID.equals(playerUUID.toString())) {
+ if (debug) {sender.sendMessage("FOR LOOP: Started HiredNPCInfo value check");}
+ String entityType = (String) nbtData.get("id");
+ if (debug) {sender.sendMessage("FOR LOOP: Got HiredNPCInfo value");}
+
+ // Increment the count for this entity type
+ entityCounts.put(entityType, entityCounts.getOrDefault(entityType, 0) + 1);
+ if (debug) {sender.sendMessage("FOR LOOP: Added to entity count");}
+ }
+ }
+ }
+ if (debug) {sender.sendMessage("FOR LOOP: Ended loop");}
+ sender.sendMessage(ChatColor.GRAY + "Player " + playerName + "'s units:");
+ for (Map.Entry entry : entityCounts.entrySet()) {
+ String friendlyName = unitNamesConfig.getString(entry.getKey(), entry.getKey());
+ sender.sendMessage(ChatColor.DARK_AQUA + "[" + ChatColor.AQUA + "x" + entry.getValue() + ChatColor.DARK_AQUA + "] " + ChatColor.GRAY + friendlyName);
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/effect_command.java b/src/main/java/com/zivilon/admintools/commands/effect_command.java
new file mode 100644
index 0000000..63518d3
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/effect_command.java
@@ -0,0 +1,83 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.potion.PotionEffect;
+
+public class effect_command implements CommandExecutor {
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission("admintools.effect")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ if (args.length < 2) {
+ sender.sendMessage(ChatColor.RED + "Usage: /effect [-d -s] [seconds] [amplifier]");
+ return false;
+ }
+
+ boolean debug_flag = false;
+ boolean silent_flag = false;
+ int argument_offset = 0;
+
+ // Iterate over flags
+ for (; argument_offset < args.length; argument_offset++) {
+ if (args[argument_offset].startsWith("-")) {
+ debug_flag |= args[argument_offset].contains("d");
+ silent_flag |= args[argument_offset].contains("s");
+ } else {
+ break;
+ }
+ }
+
+ if (args.length < (2 + argument_offset)) {
+ sender.sendMessage(ChatColor.RED + "Usage: /effect [-d -s] [seconds] [amplifier]");
+ return false;
+ }
+
+
+ Player targetPlayer = Bukkit.getPlayerExact(args[0 + argument_offset]);
+ if (targetPlayer == null) {
+ sender.sendMessage(ChatColor.RED + "Could not find player: " + args[0 + argument_offset]);
+ return true;
+ }
+
+ if ("clear".equalsIgnoreCase(args[1 + argument_offset])) {
+ targetPlayer.getActivePotionEffects().forEach(effect -> targetPlayer.removePotionEffect(effect.getType()));
+ if (!silent_flag) {
+ sender.sendMessage("Effect has been removed from " + targetPlayer.getName());
+ }
+ return true;
+ }
+
+ PotionEffectType effectType = findPotionEffectType(args[1 + argument_offset]);
+ if (effectType == null) {
+ sender.sendMessage(ChatColor.RED + "Invalid effect: " + args[1 + argument_offset]);
+ return true;
+ }
+
+ int duration = (args.length > argument_offset + 2) ? Integer.parseInt(args[2 + argument_offset]) * 20 : 60 * 20;
+ int amplifier = (args.length > argument_offset + 3) ? Integer.parseInt(args[3 + argument_offset]) : 0;
+
+ targetPlayer.addPotionEffect(new PotionEffect(effectType, duration, amplifier, false), true);
+ if (!silent_flag) {
+ targetPlayer.sendMessage("You have been given " + effectType.getName() + ".");
+ }
+
+ return true;
+ }
+
+ private PotionEffectType findPotionEffectType(String nameOrId) {
+ try {
+ return PotionEffectType.getById(Integer.parseInt(nameOrId));
+ } catch (NumberFormatException e) {
+ return PotionEffectType.getByName(nameOrId.toUpperCase());
+ }
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/entity_effect_command.java b/src/main/java/com/zivilon/admintools/commands/entity_effect_command.java
new file mode 100644
index 0000000..24990b2
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/entity_effect_command.java
@@ -0,0 +1,116 @@
+package com.zivilon.admintools.commands;
+
+import me.dpohvar.powernbt.api.NBTCompound;
+import me.dpohvar.powernbt.api.NBTList;
+import me.dpohvar.powernbt.utils.EntityUtils;
+import me.dpohvar.powernbt.utils.NBTParser;
+import me.dpohvar.powernbt.utils.NBTUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.potion.PotionEffect;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+public class entity_effect_command implements CommandExecutor {
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(ChatColor.RED + "Only players can use this command.");
+ return true;
+ }
+ if (!sender.hasPermission("admintools.entity_effect")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ Player player = (Player) sender;
+
+ if (args.length < 5) {
+ player.sendMessage(ChatColor.RED + "Usage: /command ");
+ return true;
+ }
+
+ PotionEffectType effectType = PotionEffectType.getByName(args[0].toUpperCase());
+ if (effectType == null) {
+ player.sendMessage(ChatColor.RED + "Invalid effect type.");
+ return true;
+ }
+
+ int radius;
+ try {
+ radius = Integer.parseInt(args[1]);
+ } catch (NumberFormatException e) {
+ player.sendMessage(ChatColor.RED + "Invalid radius.");
+ return true;
+ }
+
+ int duration;
+ int amplifier;
+
+ try {
+ duration = Integer.parseInt(args[3]) * 20; // Convert seconds to game ticks
+ amplifier = Integer.parseInt(args[4]) - 1; // Subtract 1 because amplifiers are zero-indexed (0 is level 1)
+ } catch (NumberFormatException e) {
+ player.sendMessage(ChatColor.RED + "Invalid duration or amplifier.");
+ return true;
+ }
+
+ List includeTargets = new ArrayList<>();
+ Set excludeTargets = new HashSet<>();
+
+ List targets = Arrays.asList(args[2].split(","));
+ for (String target : targets) {
+ if (target.startsWith("!")) {
+ // If it starts with "!", it's an exclusion, so remove the "!" and add it to the excludeTargets
+ excludeTargets.add(target.substring(1).toLowerCase()); // Convert to lower case for consistency
+ } else {
+ // Otherwise, it's an inclusion
+ includeTargets.add(target.toLowerCase()); // Convert to lower case for consistency
+ }
+ }
+
+ Location loc = player.getLocation();
+ World world = loc.getWorld();
+ if (world == null) {
+ return false;
+ }
+
+ List nearbyEntities = loc.getWorld().getEntitiesByClass(Entity.class).stream()
+ .filter(e -> e.getLocation().distance(loc) <= radius)
+ .collect(Collectors.toList());
+ for (Entity entity : nearbyEntities) {
+ String entityType = entity.getType().toString().toLowerCase(); // Get the entity type as a string in lower case
+ // Check if this entity type is excluded
+ if (excludeTargets.contains(entityType.toLowerCase())) { // Ensure checking against lower case
+ continue; // Skip this entity as it's excluded
+ }
+
+ // Check if "all" is in the includeTargets or if this specific type is included
+ if (includeTargets.contains("all") || includeTargets.contains(entityType)) {
+ // Apply the potion effect if entity is a LivingEntity
+ if (entity instanceof LivingEntity) {
+ LivingEntity livingEntity = (LivingEntity) entity;
+ livingEntity.addPotionEffect(new PotionEffect(effectType, duration, amplifier));
+ }
+ }
+ }
+
+ player.sendMessage(ChatColor.GREEN + "Effect applied.");
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/region_teleport_command.java b/src/main/java/com/zivilon/admintools/commands/region_teleport_command.java
new file mode 100644
index 0000000..5de3ca5
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/region_teleport_command.java
@@ -0,0 +1,78 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Location;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.Location;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
+import com.sk89q.worldguard.protection.managers.RegionManager;
+import com.sk89q.worldguard.protection.regions.ProtectedRegion;
+
+import com.zivilon.admintools.AdminTools;
+
+public class region_teleport_command implements CommandExecutor {
+
+ private final AdminTools plugin;
+ private WorldGuardPlugin worldGuardPlugin;
+
+ public region_teleport_command(AdminTools plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ if (!sender.hasPermission("admintools.region_tp")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+
+ if (args.length != 4) {
+ sender.sendMessage("Usage: /region_tp ");
+ return true;
+ }
+
+ Plugin plugin = Bukkit.getServer().getPluginManager().getPlugin("WorldGuard");
+ if (plugin instanceof WorldGuardPlugin) {
+ worldGuardPlugin = (WorldGuardPlugin) plugin;
+ }
+
+ World dim100World = Bukkit.getWorld("DIM100");
+ if (dim100World == null) {
+ plugin.getLogger().warning("World DIM100 not found! Ensure the world name is correct.");
+ return true;
+ }
+
+ int x, y, z;
+ try {
+ x = Integer.parseInt(args[1]);
+ y = Integer.parseInt(args[2]);
+ z = Integer.parseInt(args[3]);
+ } catch (NumberFormatException e){
+ sender.sendMessage("The coordinates must be integers!");
+ return true;
+ }
+
+ RegionManager regionManager = worldGuardPlugin.getRegionManager(dim100World);
+ Location location = new Location(dim100World, (double) x, (double) y, (double) z);
+
+ String[] regionNames = args[0].split(","); // Split region names by comma
+
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ for (String regionName : regionNames) {
+ ProtectedRegion region = regionManager.getRegion(regionName);
+ if (region != null && region.contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ())) {
+ player.teleport(location);
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/set_login_location_command.java b/src/main/java/com/zivilon/admintools/commands/set_login_location_command.java
new file mode 100644
index 0000000..ed12eae
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/set_login_location_command.java
@@ -0,0 +1,76 @@
+package com.zivilon.admintools.commands;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class set_login_location_command implements CommandExecutor, Listener {
+ // Map to store player names and their login locations.
+ private Map login_locations = new HashMap<>();
+
+ public set_login_location_command() {
+ Bukkit.getPluginManager().registerEvents(this, Bukkit.getPluginManager().getPlugin("AdminTools"));
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission("admintools.set_login_location")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+ if (command.getName().equalsIgnoreCase("set_login_location")) {
+ if (args.length < 4) {
+ sender.sendMessage("Usage: /set_login_location ");
+ return true;
+ }
+
+ String playerName = args[0];
+ World world = Bukkit.getWorld(args[1]);
+ if (world == null) {
+ sender.sendMessage("World not found: " + args[1]);
+ return true;
+ }
+
+ double x;
+ double y;
+ double z;
+ try {
+ x = Double.parseDouble(args[2]);
+ y = Double.parseDouble(args[3]);
+ z = Double.parseDouble(args[4]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage("Coordinates must be numbers.");
+ return true;
+ }
+
+ Location location = new Location(world, x, y, z);
+
+ login_locations.put(playerName, location);
+ sender.sendMessage("Login location set for " + playerName);
+ return true;
+ }
+
+ return false;
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+
+ if (login_locations.containsKey(player.getName())) {
+ player.teleport(login_locations.get(player.getName()));
+ login_locations.remove(player.getName());
+ }
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/world_setblock_command.java b/src/main/java/com/zivilon/admintools/commands/world_setblock_command.java
new file mode 100644
index 0000000..0fcbe07
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/world_setblock_command.java
@@ -0,0 +1,115 @@
+package com.zivilon.admintools.commands;
+
+import java.util.Objects;
+import me.dpohvar.powernbt.utils.NBTBlockUtils;
+import me.dpohvar.powernbt.utils.NBTParser;
+import me.dpohvar.powernbt.utils.NBTUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+
+public class world_setblock_command implements CommandExecutor {
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission("admintools.world_setblock")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+ int x, y, z;
+ if (args.length < 5) {
+ sender.sendMessage("Usage: /wsetblock [data] [oldBlockHandling] [dataTag]");
+ return false;
+ }
+
+ boolean debug_flag = false;
+ boolean silent_flag = false;
+ int argument_offset = 0; // This offset helps us handle the arguments correctly
+
+ // Iterate over flags
+ for (; argument_offset < args.length; argument_offset++) {
+ if (args[argument_offset].startsWith("-")) {
+ debug_flag |= args[argument_offset].contains("d");
+ silent_flag |= args[argument_offset].contains("s");
+ } else {
+ break;
+ }
+ }
+
+ if (args.length - argument_offset < 5) {
+ if (debug_flag) sender.sendMessage("Failed at args.length - argument_offset < 5 with args.length " + args.length + " and argument_offset " + argument_offset);
+ sender.sendMessage(ChatColor.RED + "Usage: /wsetblock [-s] [data] [oldBlockHandling] [dataTag]");
+ return false;
+ }
+
+ World world = Bukkit.getWorld(args[0 + argument_offset]);
+ try {
+ x = Integer.parseInt(args[1 + argument_offset]);
+ y = Integer.parseInt(args[2 + argument_offset]);
+ z = Integer.parseInt(args[3 + argument_offset]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(ChatColor.RED + "Coordinates need to be numbers.");
+ return true;
+ }
+ if (world == null) {
+ sender.sendMessage(ChatColor.RED + String.format("There is no such world with name %s.", new Object[] { args[1 + argument_offset] }));
+ return true;
+ }
+ Material material = Material.matchMaterial(args[4 + argument_offset]);
+ if (material == null) {
+ sender.sendMessage(ChatColor.RED + String.format("There is no such block with ID/name %s.", new Object[] { args[4 + argument_offset] }));
+ return true;
+ }
+ int data = 0;
+ if (args.length > (5 + argument_offset))
+ try {
+ data = Integer.parseInt(args[5 + argument_offset]);
+ if (data < 0 || data > 15) {
+ sender.sendMessage(ChatColor.RED + "Data must be between 0 and 15.");
+ return true;
+ }
+ } catch (NumberFormatException e) {
+ sender.sendMessage(ChatColor.RED + "Data must to be a numbers.");
+ return true;
+ }
+ Block block = world.getBlockAt(x, y, z);
+ Object handle = NBTUtils.nbtUtils.createTagCompound();
+ boolean hasNBT = false;
+ if (args.length >= (8 + argument_offset))
+ try {
+ StringBuilder builder = new StringBuilder();
+ for (int i = (7 + argument_offset); i < args.length; i++)
+ builder.append(args[i]).append(" ");
+ handle = NBTParser.parser("tag", builder.toString()).parse();
+ hasNBT = true;
+ } catch (Exception e) {
+ sender.sendMessage(ChatColor.RED + String.format("Data tag parsing failed: %s", new Object[] { e.getMessage() }));
+ return true;
+ }
+ if (args.length >= (7 + argument_offset)) {
+ String handleMethod = args[6 + argument_offset];
+ if (Objects.equals(handleMethod, "destroy")) {
+ block.setTypeId(0, true);
+ } else if (Objects.equals(handleMethod, "keep") && !block.isEmpty()) {
+ if (!silent_flag) sender.sendMessage(ChatColor.RED + "The block couldn't be placed");
+ return true;
+ }
+ }
+ if (!block.setTypeIdAndData(material.getId(), (byte)data, true)) {
+ if (!silent_flag) sender.sendMessage(ChatColor.RED + "The block couldn't be placed");
+ return true;
+ }
+ if (hasNBT)
+ try {
+ NBTBlockUtils.nbtBlockUtils.setTag(block, handle);
+ } catch (Exception e) {
+ sender.sendMessage(ChatColor.RED + String.format("Data tag parsing failed: %s", new Object[] { e.getMessage() }));
+ return true;
+ }
+ if (!silent_flag) sender.sendMessage(ChatColor.GREEN + "Block placed");
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/commands/world_summon_command.java b/src/main/java/com/zivilon/admintools/commands/world_summon_command.java
new file mode 100644
index 0000000..01bcd4c
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/commands/world_summon_command.java
@@ -0,0 +1,102 @@
+package com.zivilon.admintools.commands;
+
+import me.dpohvar.powernbt.api.NBTCompound;
+import me.dpohvar.powernbt.api.NBTList;
+import me.dpohvar.powernbt.utils.EntityUtils;
+import me.dpohvar.powernbt.utils.NBTParser;
+import me.dpohvar.powernbt.utils.NBTUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Entity;
+
+import java.util.Arrays;
+
+public class world_summon_command implements CommandExecutor {
+
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission("admintools.world_summon")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+ double x, y, z;
+ if (args.length < 5) {
+ sender.sendMessage("Usage: /wsummon [NBT]");
+ return false;
+
+ }
+
+ boolean debug_flag = false;
+ boolean silent_flag = false;
+ int argument_offset = 0; // This offset helps us handle the arguments correctly
+
+ // Iterate over flags
+ for (; argument_offset < args.length; argument_offset++) {
+ if (args[argument_offset].startsWith("-")) {
+ debug_flag |= args[argument_offset].contains("d");
+ silent_flag |= args[argument_offset].contains("s");
+ } else {
+ break;
+ }
+ }
+
+ if (args.length - argument_offset < 5) {
+ if (debug_flag) sender.sendMessage("Failed at args.length - argument_offset < 5 with args.length " + args.length + " and argument_offset " + argument_offset);
+ sender.sendMessage(ChatColor.RED + "Usage: /wsummon [-s] [NBT]");
+ return false;
+ }
+
+ World world = Bukkit.getWorld(args[0 + argument_offset]);
+
+ try {
+ x = Double.parseDouble(args[1 + argument_offset]);
+ y = Double.parseDouble(args[2 + argument_offset]);
+ z = Double.parseDouble(args[3 + argument_offset]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(ChatColor.RED + "Coordinates need to be numbers.");
+ return true;
+ }
+
+ if (world == null) {
+ sender.sendMessage(ChatColor.RED + String.format("There is no such world with name %s.", args[1 + argument_offset]));
+ return true;
+ }
+
+ if (!world.isChunkLoaded((int)x >> 4, (int)z >> 4))
+ world.loadChunk((int)x >> 4, (int)z >> 4);
+
+ Object handle = NBTUtils.nbtUtils.createTagCompound();
+
+ if (args.length >= (6 + argument_offset)) {
+ try {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 5; i < (args.length - argument_offset); i++)
+ builder.append(args[i + argument_offset]).append(" ");
+
+ handle = NBTParser.parser("tag", builder.toString()).parse();
+ } catch (IllegalArgumentException e) {
+ sender.sendMessage(ChatColor.RED + String.format("Data tag parsing failed: %s", args[5 + argument_offset]));
+ return true;
+ }
+ }
+
+ NBTCompound nbtCompound = NBTCompound.forNBT(handle);
+ nbtCompound.put("id", args[4 + argument_offset]);
+
+ nbtCompound.put("Pos", new NBTList(Arrays.asList(x, y, z)));
+
+ Entity entity = EntityUtils.entityUtils.spawnEntity(nbtCompound.getHandle(), world);
+
+ if (entity != null) {
+ if (!silent_flag) sender.sendMessage(ChatColor.GREEN + "Object successfully summoned");
+ } else {
+ sender.sendMessage(ChatColor.RED + "Unable to summon object.");
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/com/zivilon/admintools/listeners/ranged_immunity_listener.java b/src/main/java/com/zivilon/admintools/listeners/ranged_immunity_listener.java
new file mode 100644
index 0000000..467329c
--- /dev/null
+++ b/src/main/java/com/zivilon/admintools/listeners/ranged_immunity_listener.java
@@ -0,0 +1,47 @@
+package com.zivilon.admintools.listeners;
+
+import me.dpohvar.powernbt.api.NBTCompound;
+import me.dpohvar.powernbt.api.NBTManager;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Projectile;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+
+import com.zivilon.admintools.AdminTools;
+
+public class ranged_immunity_listener implements Listener {
+
+ private final AdminTools plugin;
+
+ public ranged_immunity_listener(AdminTools plugin) {
+ this.plugin = plugin;
+ }
+
+ // DEPRECATED
+ // Use the DamageModifiers plugin instead
+ // It lets you create immunities and damage multipliers to all damage types
+
+ @EventHandler
+ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
+ Entity damager = event.getDamager();
+ Entity entity = event.getEntity();
+
+ // Check if damage source is a projectile
+ if (!(damager instanceof Projectile)) {
+ return;
+ }
+
+ // Obtain an instance of NBTManager
+ NBTManager nbtManager = me.dpohvar.powernbt.PowerNBT.getApi();
+
+ // Get NBT data of the entity
+ NBTCompound nbtData = nbtManager.read(entity);
+ NBTCompound forgeData = (NBTCompound) nbtData.get("ForgeData");
+
+ // Check if the entity has RangedImmune = 1
+ if (forgeData != null && forgeData.getByte("RangedImmune") == 1) {
+ event.setCancelled(true);
+ }
+ }
+}
diff --git a/src/main/resources/chunkloaders.yml b/src/main/resources/chunkloaders.yml
new file mode 100644
index 0000000..6694142
--- /dev/null
+++ b/src/main/resources/chunkloaders.yml
@@ -0,0 +1,11 @@
+chunkloaders:
+ chunkloader1:
+ world: "world"
+ x: 100
+ y: 64
+ z: 200
+ chunkloader2:
+ world: "world_nether"
+ x: -100
+ y: 64
+ z: -200
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..e69de29
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..71f2d59
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,42 @@
+main: com.zivilon.admintools.AdminTools
+name: AdminTools
+author: Shinare
+version: 1.3
+depend: [WorldGuard]
+load: POSTWORLD
+commands:
+ clean_entities:
+ description: "Removes entities of the specified type within the given radius"
+ count_units:
+ description: "Counts the hired units of a specified player"
+ chunkloader:
+ description: "Main command for creating chunk loaders"
+ aliases: [chl]
+ block_swap:
+ description: "Sets an area of blocks client-side only to the specified player"
+ usage: "Usage: /block_swap "
+ wsummon:
+ description: "Usage: /wsummon [-d -s] [entity] []"
+ wsetblock:
+ description: "Usage: /wsetblock [-d -s] [dataValue] [oldBlockHandling] [dataTag]]"
+ set_login_location:
+ description: "Sets player's login location for when they log in again. Needs to be during current server session, is not persistent over restarts."
+ usage: "Usage: /set_login_location [dataValue] [oldBlockHandling] [dataTag]]"
+ area_message:
+ description: "Usage: /area_message [-d -s] "
+ areaeffect:
+ description: "Usage: /areaeffect "
+ effect:
+ description: "Applies an effect to a player with optional silence and debug flags."
+ usage: "/ [-d -s] [seconds] [amplifier]"
+ check_players:
+ description: "Runs a command depending on if players are in specified WorldGuard regions."
+ usage: "Usage: /check_players "
+ region_tp:
+ description: "Teleports all players within given WorldGuard regions to coordinates."
+ usage: "Usage: /region_tp "
+ aliases: [region_teleport, rtp, rgtp]
+ entityeffect:
+ description: "Applies given potion effect to all listed entity types nearby."
+ usage: "Usage: /entityeffect "
+
diff --git a/src/main/resources/unit_names.yml b/src/main/resources/unit_names.yml
new file mode 100644
index 0000000..d84cb43
--- /dev/null
+++ b/src/main/resources/unit_names.yml
@@ -0,0 +1,3 @@
+EntityNames:
+ lotr.NearHaradrimWarrior: 'Coast Southron Warrior'
+ lotr.SomeOtherEntity: 'Friendly name'