diff --git a/api-internal/pom.xml b/api-internal/pom.xml
index 49cc600b..aa108e74 100644
--- a/api-internal/pom.xml
+++ b/api-internal/pom.xml
@@ -21,6 +21,12 @@
gson
2.11.0
+
+ org.jetbrains
+ annotations
+ 24.0.0
+ compile
+
diff --git a/api-internal/src/main/java/at/pavlov/internal/Hook.java b/api-internal/src/main/java/at/pavlov/internal/Hook.java
index 9d492071..b44afc95 100644
--- a/api-internal/src/main/java/at/pavlov/internal/Hook.java
+++ b/api-internal/src/main/java/at/pavlov/internal/Hook.java
@@ -9,7 +9,7 @@ default boolean active() {
}
void onEnable();
- void onDisable();
+ default void onDisable() {}
Class extends Hook>> getTypeClass();
default @NotNull String enabledMessage() {
diff --git a/api-internal/src/main/java/at/pavlov/internal/HookManager.java b/api-internal/src/main/java/at/pavlov/internal/HookManager.java
index fb2d17c6..d278dcb4 100644
--- a/api-internal/src/main/java/at/pavlov/internal/HookManager.java
+++ b/api-internal/src/main/java/at/pavlov/internal/HookManager.java
@@ -1,10 +1,12 @@
package at.pavlov.internal;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Consumer;
public class HookManager {
private final Map>, Hook>> hooks = new HashMap<>();
@@ -30,7 +32,7 @@ public boolean isRegistered(@NotNull Class extends Hook>> type) {
return false;
}
- public > @NotNull T getHook(@NotNull Class type) {
+ public > @Nullable T getHook(@NotNull Class type) {
Hook> hook = this.hooks.get(type);
if (hook != null) {
return type.cast(hook);
@@ -42,7 +44,21 @@ public boolean isRegistered(@NotNull Class extends Hook>> type) {
}
}
- throw new IllegalArgumentException("No registered hook of type " + type.getName() + "!");
+ return null;
+ }
+
+ public > void processIfPresent(@NotNull Class type, Consumer consumer) {
+ T hook = getHook(type);
+ if (hook == null || !hook.active()) {
+ return;
+ }
+
+ C hookContent = hook.hook();
+ if (hookContent == null) {
+ return;
+ }
+
+ consumer.accept(hookContent);
}
/**
diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml
index 75debaa4..380c9a96 100644
--- a/cannons-bukkit/pom.xml
+++ b/cannons-bukkit/pom.xml
@@ -65,6 +65,10 @@
true
+
+ glaremasters repo
+ https://repo.glaremasters.me/repository/towny/
+
@@ -149,6 +153,12 @@
2.11.6
provided
+
+ com.palmergames.bukkit.towny
+ towny
+ 0.101.1.0
+ provided
+
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/Aiming.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/Aiming.java
index 0ca1f5e0..9de780a8 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/Aiming.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/Aiming.java
@@ -18,10 +18,13 @@
import at.pavlov.cannons.event.CannonLinkAimingEvent;
import at.pavlov.cannons.event.CannonTargetEvent;
import at.pavlov.cannons.event.CannonUseEvent;
+import at.pavlov.cannons.hooks.towny.TownyHook;
import at.pavlov.cannons.projectile.Projectile;
import at.pavlov.cannons.scheduler.FakeBlockHandler;
import at.pavlov.cannons.utils.CannonsUtil;
import at.pavlov.cannons.utils.SoundUtils;
+import com.palmergames.bukkit.towny.object.Resident;
+import com.palmergames.bukkit.towny.utils.CombatUtil;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -37,11 +40,11 @@
import org.bukkit.util.Vector;
import java.text.DecimalFormat;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
@@ -651,7 +654,7 @@ private void findSuitableTarget(Cannon cannon, Map targets) {
return;
}
- ArrayList possibleTargets = new ArrayList<>();
+ LinkedList possibleTargets = new LinkedList<>();
for (Target t : targets.values()) {
TargetType type = t.targetType();
@@ -667,6 +670,26 @@ private void findSuitableTarget(Cannon cannon, Map targets) {
if (cannon.isWhitelisted(t.uniqueId())) continue;
//Player
if (type == TargetType.PLAYER) {
+
+ final boolean[] skip = new boolean[1];
+ Cannons.getPlugin().getHookManager().processIfPresent(TownyHook.class, townyApi -> {
+ Resident ownerResident = townyApi.getResident(cannon.getOwner());
+ if (ownerResident == null) {
+ return;
+ }
+
+ Resident residentTarget = townyApi.getResident(t.uniqueId());
+ if (residentTarget == null) {
+ return;
+ }
+
+ if (CombatUtil.isAlly(residentTarget, ownerResident)) {
+ skip[0] = true;
+ }
+ });
+
+ if (skip[0]) continue;
+
// get solution
handlePossibleTarget(cannon, t, possibleTargets);
continue;
@@ -674,6 +697,7 @@ private void findSuitableTarget(Cannon cannon, Map targets) {
Cannon tCannon = CannonManager.getCannon(t.uniqueId());
if (tCannon == null) continue;
+ if (cannon.isWhitelisted(tCannon.getOwner())) continue;
//Cannons & Other have same handling
//check if the owner is whitelisted
if (type == TargetType.CANNON || type == TargetType.OTHER) {
@@ -697,7 +721,7 @@ private void findSuitableTarget(Cannon cannon, Map targets) {
}
}
- private void handlePossibleTarget(Cannon cannon, Target t, ArrayList possibleTargets) {
+ private void handlePossibleTarget(Cannon cannon, Target t, List possibleTargets) {
if (canFindTargetSolution(cannon, t)) {
possibleTargets.add(t);
}
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java
index c05cf266..5b41f839 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java
@@ -18,6 +18,7 @@
import at.pavlov.cannons.hooks.VaultHook;
import at.pavlov.cannons.hooks.movecraft.type.MaxCannonsProperty;
import at.pavlov.cannons.hooks.movecraftcombat.MovecraftCombatHook;
+import at.pavlov.cannons.hooks.towny.TownyHook;
import at.pavlov.cannons.listener.*;
import at.pavlov.cannons.projectile.Projectile;
import at.pavlov.cannons.projectile.ProjectileManager;
@@ -206,6 +207,10 @@ public void onEnable()
PlaceholderAPIHook placeholderAPIHook = new PlaceholderAPIHook(this);
hookManager.registerHook(placeholderAPIHook);
+ logDebug("Loading TownyHook");
+ TownyHook townyHook = new TownyHook(this);
+ hookManager.registerHook(townyHook);
+
logDebug("Time to enable hooks: " + new DecimalFormat("0.00").format(System.currentTimeMillis() - startTime) + "ms");
startTime = System.nanoTime();
@@ -306,10 +311,7 @@ public void onEnable()
" You don't need to add Movecraft-Cannons anymore as Movecraft support is now embedded," +
" we suggest you stop using it as in the future it might stop work properly.");
- if (hookManager.isRegistered(MovecraftCombatHook.class)) {
-
- }
- movecraftHook.onDisable();
+ movecraftHook.onDisable();
}, 1L);
}
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/config/Config.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/config/Config.java
index 3c7df816..35a3c449 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/config/Config.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/config/Config.java
@@ -5,6 +5,7 @@
import at.pavlov.cannons.builders.ParticleBuilder;
import at.pavlov.cannons.cannon.CannonManager;
import at.pavlov.cannons.container.ItemHolder;
+import at.pavlov.cannons.hooks.towny.TownyAllowCannon;
import at.pavlov.cannons.utils.ArmorCalculationUtil;
import at.pavlov.cannons.utils.CannonsUtil;
import at.pavlov.cannons.utils.FileUtils;
@@ -39,6 +40,9 @@
//movecraft
private boolean movecraftEnabled;
private boolean movecraftCannonEnabled;
+
+ private boolean townyEnabled;
+ private TownyAllowCannon townyAllowedPlayers;
//endregion
//build limits
@@ -133,6 +137,9 @@ public void loadConfig() {
setMovecraftEnabled(config.getBoolean("hooks.movecraft.enabled", true));
setMovecraftCannonEnabled(config.getBoolean("hooks.movecraftCombat.enabled", true));
+ setTownyEnabled(config.getBoolean("hooks.towny.enabled", true));
+ setTownyAllowedPlayers(TownyAllowCannon.fromConfig(config, "hooks.towny"));
+
setRelayExplosionEvent(config.getBoolean("general.relayExplosionEvent", false));
setClaimEdgeLength(config.getInt("general.claimEdgeLength", 60));
ArmorCalculationUtil.setMagicValue(config.getDouble("general.armorEffectiveness", 0.04));
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/event/CannonUseEvent.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/event/CannonUseEvent.java
index cc763eb4..35c8f507 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/event/CannonUseEvent.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/event/CannonUseEvent.java
@@ -2,43 +2,28 @@
import at.pavlov.cannons.Enum.InteractAction;
import at.pavlov.cannons.cannon.Cannon;
+import lombok.Getter;
+import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.UUID;
-public class CannonUseEvent extends Event
-{
+@Getter
+public class CannonUseEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Cannon cannon;
private final UUID player;
private final InteractAction action;
private boolean cancelled;
- public CannonUseEvent(Cannon cannon, UUID player, InteractAction action)
- {
+ public CannonUseEvent(Cannon cannon, UUID player, InteractAction action) {
this.cannon = cannon;
this.player = player;
this.action = action;
this.cancelled = false;
}
- public Cannon getCannon() {
- return cannon;
- }
-
- public UUID getPlayer() {
- return player;
- }
-
- public InteractAction getAction() {
- return action;
- }
-
- public boolean isCancelled() {
- return cancelled;
- }
-
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/VaultHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/VaultHook.java
index e155698a..6d23cc6f 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/VaultHook.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/VaultHook.java
@@ -34,9 +34,6 @@ public void onEnable() {
plugin.logInfo(ChatColor.GREEN + enabledMessage());
}
- @Override
- public void onDisable() { }
-
@Override
public Class extends Hook>> getTypeClass() {
return VaultHook.class;
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java
index 3667bcc2..00356e20 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java
@@ -43,13 +43,6 @@ public void onEnable() {
plugin.logInfo(ChatColor.GREEN + enabledMessage());
}
- @Override
- public void onDisable() {
- HandlerList.unregisterAll(new CraftDetectListener());
- HandlerList.unregisterAll(new TranslationListener());
- HandlerList.unregisterAll(new RotationListener());
- }
-
@Override
public Class extends Hook>> getTypeClass() {
return MovecraftHook.class;
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraftcombat/MovecraftCombatHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraftcombat/MovecraftCombatHook.java
index 7019053c..c8e8695c 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraftcombat/MovecraftCombatHook.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraftcombat/MovecraftCombatHook.java
@@ -29,11 +29,6 @@ public void onEnable() {
plugin.logInfo(ChatColor.GREEN + enabledMessage());
}
- @Override
- public void onDisable() {
- HandlerList.unregisterAll(new ProjectileImpactListener());
- }
-
@Override
public Class extends Hook>> getTypeClass() {
return MovecraftCombatHook.class;
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/papi/PlaceholderAPIHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/papi/PlaceholderAPIHook.java
index 1a831118..9708ec28 100644
--- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/papi/PlaceholderAPIHook.java
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/papi/PlaceholderAPIHook.java
@@ -29,11 +29,6 @@ public void onEnable() {
plugin.logInfo(ChatColor.GREEN + enabledMessage());
}
- @Override
- public void onDisable() {
-
- }
-
@Override
public boolean active() {
return working;
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyAllowCannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyAllowCannon.java
new file mode 100644
index 00000000..3a86b109
--- /dev/null
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyAllowCannon.java
@@ -0,0 +1,21 @@
+package at.pavlov.cannons.hooks.towny;
+
+import org.bukkit.configuration.file.FileConfiguration;
+
+import java.util.Locale;
+
+public enum TownyAllowCannon {
+ ALL,
+ TOWN,
+ ALLIES;
+
+ public static TownyAllowCannon fromConfig(FileConfiguration config, String key) {
+ String result = config.getString(key, "TOWN");
+
+ try {
+ return TownyAllowCannon.valueOf(result.toUpperCase(Locale.ROOT));
+ } catch (Exception ignored) {
+ return TOWN;
+ }
+ }
+}
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyHook.java
new file mode 100644
index 00000000..6448f407
--- /dev/null
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyHook.java
@@ -0,0 +1,38 @@
+package at.pavlov.cannons.hooks.towny;
+
+import at.pavlov.cannons.Cannons;
+import at.pavlov.cannons.hooks.BukkitHook;
+import at.pavlov.internal.Hook;
+import com.palmergames.bukkit.towny.TownyAPI;
+import lombok.SneakyThrows;
+import org.bukkit.plugin.PluginManager;
+
+public class TownyHook extends BukkitHook {
+
+ public TownyHook(Cannons plugin) {
+ super(plugin);
+ }
+
+ @SneakyThrows
+ @Override
+ public void onEnable() {
+
+ if (!plugin.getMyConfig().isTownyEnabled()) {
+ return;
+ }
+
+ PluginManager pluginManager = plugin.getServer().getPluginManager();
+ if (!pluginManager.isPluginEnabled("Towny")) {
+ plugin.logDebug("Towny not found or disabled");
+ return;
+ }
+
+ hook = TownyAPI.getInstance();
+ pluginManager.registerEvents(new TownyListeners(), plugin);
+ }
+
+ @Override
+ public Class extends Hook>> getTypeClass() {
+ return TownyHook.class;
+ }
+}
diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyListeners.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyListeners.java
new file mode 100644
index 00000000..4122e173
--- /dev/null
+++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/towny/TownyListeners.java
@@ -0,0 +1,84 @@
+package at.pavlov.cannons.hooks.towny;
+
+import at.pavlov.cannons.config.Config;
+import at.pavlov.cannons.event.CannonUseEvent;
+import com.palmergames.bukkit.towny.TownyAPI;
+import com.palmergames.bukkit.towny.object.Resident;
+import com.palmergames.bukkit.towny.object.Town;
+import com.palmergames.bukkit.towny.utils.CombatUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+
+import java.util.UUID;
+
+import static at.pavlov.cannons.Enum.InteractAction.adjustPlayer;
+import static at.pavlov.cannons.Enum.InteractAction.fireRightClickTigger;
+
+public class TownyListeners implements Listener {
+ private static final Config config = Config.getInstance();
+ private static final TownyAPI api = TownyAPI.getInstance();
+
+ @EventHandler
+ public void onAction(CannonUseEvent event) {
+ Location location = event.getCannon().getLocation();
+ TownyAllowCannon tac = config.getTownyAllowedPlayers();
+ if (tac == TownyAllowCannon.ALL) {
+ return;
+ }
+
+ Town town = api.getTown(location);
+ if (town == null) {
+ return;
+ }
+
+ UUID playerUUID = event.getPlayer();
+ if (playerUUID == null) {
+ return;
+ }
+
+ Player player = Bukkit.getPlayer(playerUUID);
+ if (player == null) {
+ event.setCancelled(true);
+ return;
+ }
+
+ if (player.hasPermission("cannons.admin.*")) {
+ return;
+ }
+
+ if (town.hasResident(playerUUID)) {
+ return;
+ }
+
+ // we already did town check,
+ // if it failed and tac is set to TOWN we are done here
+ if (tac == TownyAllowCannon.TOWN) {
+ event.setCancelled(true);
+ player.sendMessage("§4[Cannons] No permission to interact with this cannons. (TownyAllowCannon.TOWN)");
+ return;
+ }
+
+ Resident resident = api.getResident(playerUUID);
+ if (resident == null) { //this shouldn't happen tbh
+ return;
+ }
+
+ Town otherTown = resident.getTownOrNull();;
+ if (otherTown == null) {
+ event.setCancelled(true);
+ player.sendMessage("§4[Cannons] No permission to interact with this cannons. (No town)");
+ return;
+ }
+
+ if (CombatUtil.isAlly(town, otherTown)) {
+ return;
+ }
+
+ event.setCancelled(true);
+ player.sendMessage("§4[Cannons] No permission to interact with this cannons. (TownyAllowCannon.ALLY)");
+ }
+
+}
diff --git a/cannons-bukkit/src/main/resources/config.yml b/cannons-bukkit/src/main/resources/config.yml
index d6657686..f2a6fac2 100644
--- a/cannons-bukkit/src/main/resources/config.yml
+++ b/cannons-bukkit/src/main/resources/config.yml
@@ -21,6 +21,13 @@ hooks:
enabled: true
movecraftCombat:
enabled: true
+ towny:
+ enabled: true
+ # Possible values of allowedPlayers:
+ # ALL : all player can use cannons in a town.
+ # TOWN : all residents can use the cannons in a town.
+ # ALLIES : all residents and allies can use the cannons in a town.
+ allowedPlayers: TOWN
cannonLimits:
diff --git a/cannons-bukkit/src/main/resources/plugin.yml b/cannons-bukkit/src/main/resources/plugin.yml
index 14c3a02e..d065f0ab 100644
--- a/cannons-bukkit/src/main/resources/plugin.yml
+++ b/cannons-bukkit/src/main/resources/plugin.yml
@@ -3,7 +3,7 @@ main: at.pavlov.cannons.Cannons
api-version: 1.13
version: ${version}
depend: [WorldEdit]
-softdepend: [Vault, Movecraft, Movecraft-Combat, PlaceholderAPI]
+softdepend: [Vault, Movecraft, Movecraft-Combat, PlaceholderAPI, Towny]
authors: [DerPavlov, Vaan1310]
description: Fire block build cannons and smash your enemies
folia-supported: true