Skip to content

Commit d2e5109

Browse files
authored
Hook/movecraft/more tags (#53)
* Fix lowercase bug * Allow list as keys * Add MinCannons * Extract PropertyUtils * Add MaxMass & MinMass properties * Add excludeFromMass * Add useShipAngles * Add notify error for each property
1 parent dfbe700 commit d2e5109

17 files changed

Lines changed: 551 additions & 139 deletions

FEATURES.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ Fixes:
1818
Hooks:
1919
---------------
2020
- Vault hook to buy cannons (was there even before fork)
21-
- Movecraft-Cannons support is now integrated (Movecraft Combat hook + Movecraft hook)
22-
- [PlaceholderAPI](./PLACEHOLDERS.md) hook
21+
- [Movecraft](https://github.com/Intybyte/Cannons/wiki/Hooks-&-Integrations#movecraft): Movecraft-Cannons support is now integrated (Movecraft Combat hook + Movecraft hook)
22+
- [PlaceholderAPI](https://github.com/Intybyte/Cannons/wiki/Hooks-&-Integrations#placeholder-api) hook
2323

2424
Optimizations:
2525
---------------

cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import at.pavlov.cannons.exchange.ExchangeLoader;
1717
import at.pavlov.cannons.hooks.VaultHook;
1818
import at.pavlov.cannons.hooks.movecraft.MovecraftHook;
19-
import at.pavlov.cannons.hooks.movecraft.type.MaxCannonsProperty;
19+
import at.pavlov.cannons.hooks.movecraft.type.properties.CannonProperties;
2020
import at.pavlov.cannons.hooks.movecraftcombat.MovecraftCombatHook;
2121
import at.pavlov.cannons.hooks.papi.PlaceholderAPIHook;
2222
import at.pavlov.cannons.listener.BlockListener;
@@ -34,15 +34,12 @@
3434
import at.pavlov.cannons.utils.CannonSelector;
3535
import at.pavlov.cannons.utils.TimeUtils;
3636
import at.pavlov.internal.CLogger;
37-
import at.pavlov.internal.Hook;
3837
import at.pavlov.internal.HookManager;
3938
import at.pavlov.internal.Key;
4039
import at.pavlov.internal.ModrinthUpdateChecker;
4140
import at.pavlov.internal.key.registries.Registries;
4241
import at.pavlov.internal.projectile.definition.KeyedDefaultProjectile;
4342
import lombok.Getter;
44-
import org.bstats.bukkit.Metrics;
45-
import org.bstats.charts.AdvancedPie;
4643
import org.bukkit.Bukkit;
4744
import org.bukkit.ChatColor;
4845
import org.bukkit.Location;
@@ -59,8 +56,6 @@
5956
import java.sql.SQLException;
6057
import java.sql.Statement;
6158
import java.text.DecimalFormat;
62-
import java.util.HashMap;
63-
import java.util.Map;
6459
import java.util.UUID;
6560
import java.util.logging.Logger;
6661

@@ -127,7 +122,7 @@ public void onLoad() {
127122
if (config.isMovecraftEnabled()) {
128123
try {
129124
Class.forName("net.countercraft.movecraft.craft.type.property.Property");
130-
MaxCannonsProperty.register();
125+
CannonProperties.register();
131126
} catch (Exception ignored) {
132127
}
133128

@@ -481,4 +476,8 @@ public boolean isDebugMode() {
481476
public void setDebugMode(boolean debugMode) {
482477
this.debugMode = debugMode;
483478
}
479+
480+
public static NamespacedKey nsKey(String key) {
481+
return new NamespacedKey(getPlugin(), key);
482+
}
484483
}

cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
import at.pavlov.cannons.Cannons;
44
import at.pavlov.cannons.hooks.BukkitHook;
55
import at.pavlov.cannons.hooks.movecraft.listener.CraftDetectListener;
6+
import at.pavlov.cannons.hooks.movecraft.listener.ReleaseListener;
67
import at.pavlov.cannons.hooks.movecraft.listener.RotationListener;
78
import at.pavlov.cannons.hooks.movecraft.listener.SinkListener;
89
import at.pavlov.cannons.hooks.movecraft.listener.TranslationListener;
910
import at.pavlov.internal.Hook;
1011
import net.countercraft.movecraft.Movecraft;
1112
import org.bukkit.ChatColor;
12-
import org.bukkit.event.HandlerList;
1313
import org.bukkit.plugin.Plugin;
1414
import org.bukkit.plugin.PluginManager;
1515

@@ -42,6 +42,7 @@ public void onEnable() {
4242
pluginManager.registerEvents(new TranslationListener(), plugin);
4343
pluginManager.registerEvents(new RotationListener(), plugin);
4444
pluginManager.registerEvents(new SinkListener(), plugin);
45+
pluginManager.registerEvents(new ReleaseListener(), plugin);
4546
plugin.logInfo(ChatColor.GREEN + enabledMessage());
4647
}
4748

cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftUtils.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@
22

33
import at.pavlov.cannons.cannon.Cannon;
44
import at.pavlov.cannons.cannon.CannonManager;
5+
import lombok.AccessLevel;
6+
import lombok.NoArgsConstructor;
57
import net.countercraft.movecraft.MovecraftLocation;
68
import net.countercraft.movecraft.craft.Craft;
79
import net.countercraft.movecraft.craft.PilotedCraft;
810
import net.countercraft.movecraft.craft.SubCraft;
11+
import net.countercraft.movecraft.util.Pair;
912
import org.bukkit.Location;
13+
import org.jetbrains.annotations.NotNull;
1014

1115
import java.util.ArrayList;
1216
import java.util.List;
1317
import java.util.Set;
1418
import java.util.UUID;
1519

20+
import static net.countercraft.movecraft.craft.type.TypeData.NUMERIC_PREFIX;
21+
22+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
1623
public class MovecraftUtils {
1724

1825
public static Set<Cannon> getCannons(Craft craft) {
@@ -49,4 +56,32 @@ public static UUID getPlayerFromCraft(Craft craft) {
4956
// Return null if all else fails
5057
return null;
5158
}
59+
60+
public static @NotNull Pair<Boolean, ? extends Number> parseLimit(@NotNull Object input) {
61+
if (!(input instanceof String str)) {
62+
return new Pair<>(false, (double) input);
63+
}
64+
65+
if (!str.contains(NUMERIC_PREFIX)) {
66+
return new Pair<>(false, Double.valueOf(str));
67+
}
68+
69+
String[] parts = str.split(NUMERIC_PREFIX);
70+
int val = Integer.parseInt(parts[1]);
71+
return new Pair<>(true, val);
72+
}
73+
74+
public static @NotNull List<@NotNull String> parseKey(Object key) {
75+
if (key instanceof String string) {
76+
return List.of(string);
77+
} else if (key instanceof ArrayList<?> array) {
78+
if (array.get(0) instanceof String) {
79+
return (ArrayList<String>) array;
80+
}
81+
82+
throw new IllegalArgumentException("Invalid parsed key");
83+
} else {
84+
throw new IllegalArgumentException("Invalid parsed key");
85+
}
86+
}
5287
}
Lines changed: 76 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,111 @@
11
package at.pavlov.cannons.hooks.movecraft.listener;
22

33
import at.pavlov.cannons.Cannons;
4-
import at.pavlov.cannons.Enum.BreakCause;
54
import at.pavlov.cannons.cannon.Cannon;
6-
import at.pavlov.cannons.cannon.CannonManager;
5+
import at.pavlov.cannons.cannon.CannonDesign;
76
import at.pavlov.cannons.hooks.movecraft.MovecraftUtils;
8-
import at.pavlov.cannons.hooks.movecraft.type.MaxCannonsEntry;
7+
import at.pavlov.cannons.hooks.movecraft.type.CannonCheck;
8+
import at.pavlov.cannons.hooks.movecraft.type.properties.CannonProperties;
99
import net.countercraft.movecraft.craft.Craft;
1010
import net.countercraft.movecraft.craft.PlayerCraft;
1111
import net.countercraft.movecraft.craft.type.CraftType;
1212
import net.countercraft.movecraft.events.CraftDetectEvent;
13-
import net.countercraft.movecraft.events.CraftSinkEvent;
1413
import org.bukkit.event.EventHandler;
1514
import org.bukkit.event.Listener;
1615

1716
import java.util.HashMap;
18-
import java.util.HashSet;
1917
import java.util.Map;
18+
import java.util.Optional;
2019
import java.util.Set;
2120

22-
import static at.pavlov.cannons.hooks.movecraft.type.MaxCannonsProperty.MAX_CANNONS;
23-
2421
public class CraftDetectListener implements Listener {
25-
private static final Set<CraftType> notifyError = new HashSet<>();
26-
private static final Cannons cannon = Cannons.getPlugin();
22+
private static final Cannons cannonPlugin = Cannons.getPlugin();
2723

28-
@EventHandler
24+
@EventHandler(ignoreCancelled = true)
2925
public void onCraftDetect(CraftDetectEvent e) {
3026
Craft craft = e.getCraft();
3127
CraftType type = craft.getType();
32-
if (notifyError.contains(type))
33-
return;
34-
35-
if (!(craft instanceof PlayerCraft))
36-
return;
3728

38-
Set<?> maxCannons = getCannonProperty(type);
39-
if (maxCannons.isEmpty())
40-
return; // Return if empty set to improve performance
29+
if (!(craft instanceof PlayerCraft)) return;
4130

4231
// Sum up counts of each cannon design
4332
Set<Cannon> cannons = MovecraftUtils.getCannons(craft);
44-
Map<String, Integer> cannonCount = new HashMap<>();
45-
for (var cannon : cannons) {
46-
String design = cannon.getCannonDesign().getDesignName().toLowerCase();
47-
cannonCount.compute(design, (key, value) -> (value == null) ? 1 : value + 1);
33+
34+
if (cannons.isEmpty()) return;
35+
36+
if (checkMaxMin(e, type, cannons, craft)) return;
37+
38+
if (checkMass(e, cannons, type)) return;
39+
40+
boolean useShip = CannonProperties.USE_SHIP_ANGLES.get(type) == Boolean.TRUE;
41+
if (useShip) {
42+
cannons.forEach(it -> it.setOnShip(true));
43+
}
44+
}
45+
46+
private boolean checkMass(CraftDetectEvent e, Set<Cannon> cannons, CraftType type) {
47+
int cannonsMassCount = 0;
48+
Set<String> exclude = CannonProperties.EXCLUDE_FROM_MASS.get(type);
49+
for (Cannon cannon : cannons) {
50+
CannonDesign design = cannon.getCannonDesign();
51+
52+
if (!exclude.contains(design.getDesignID())) {
53+
cannonsMassCount += design.getMassOfCannon();
54+
}
55+
}
56+
57+
cannonPlugin.logDebug("MassCount " + cannonsMassCount);
58+
Integer maxMass = CannonProperties.MAX_MASS.get(type);
59+
if (maxMass != null && maxMass < cannonsMassCount) {
60+
e.setCancelled(true);
61+
e.setFailMessage(
62+
String.format(
63+
"Detection Failed! Too much cannon mass on board! %d > %d", cannonsMassCount, maxMass
64+
)
65+
);
66+
return true;
4867
}
49-
printCannonCount(cannonCount);
50-
51-
// Check designs against maxCannons
52-
int size = craft.getOrigBlockCount();
53-
for (var entry : maxCannons) {
54-
if (!(entry instanceof MaxCannonsEntry max))
55-
throw new IllegalStateException("maxCannons must be a set of MaxCannonsEntry.");
56-
57-
var cannonName = max.getName();
58-
var count = cannonCount.get(cannonName.toLowerCase());
59-
if (count == null)
60-
continue;
61-
62-
var result = max.detect(count, size);
63-
64-
result.ifPresent( error -> {
65-
e.setCancelled(true);
66-
e.setFailMessage("Detection Failed! You have too many cannons of the following type on this craft: "
67-
+ cannonName + ": " + error);
68-
});
68+
69+
Integer minMass = CannonProperties.MIN_MASS.get(type);
70+
if (minMass != null && minMass > cannonsMassCount) {
71+
e.setCancelled(true);
72+
e.setFailMessage(
73+
String.format(
74+
"Detection Failed! Not enough cannon mass on board! %d < %d", cannonsMassCount, minMass
75+
)
76+
);
77+
return true;
6978
}
79+
80+
return false;
7081
}
7182

72-
private void printCannonCount(Map<String, Integer> cannonCount) {
83+
private boolean checkMaxMin(CraftDetectEvent e, CraftType type, Set<Cannon> cannons, Craft craft) {
84+
Set<? extends CannonCheck> cannonMaxMinChecks = CannonProperties.MAX_CANNONS.get(type);
85+
cannonMaxMinChecks.addAll(CannonProperties.MIN_CANNONS.get(type));
86+
87+
if (cannonMaxMinChecks.isEmpty()) return false;
88+
89+
Map<String, Integer> cannonCount = new HashMap<>();
90+
for (Cannon cannon : cannons) {
91+
String design = cannon.getCannonDesign().getDesignID();
92+
cannonCount.compute(design, (key, value) -> (value == null) ? 1 : value + 1);
93+
}
94+
7395
for (var entry : cannonCount.entrySet()) {
74-
cannon.logDebug("Cannon found: " + entry.getKey() + " | " + entry.getValue());
96+
cannonPlugin.logDebug("Cannon found: " + entry.getKey() + " | " + entry.getValue());
7597
}
76-
}
7798

78-
private Set<MaxCannonsEntry> getCannonProperty(CraftType type) {
79-
try {
80-
Object objectProperty = type.getObjectProperty(MAX_CANNONS);
81-
if (objectProperty instanceof Set<?> property) {
82-
return (Set<MaxCannonsEntry>) property;
83-
} else {
84-
throw new IllegalStateException("maxCannons must be a set.");
85-
}
86-
} catch (Exception exception) {
87-
notifyError.add(type);
88-
cannon.logSevere(
89-
"Failed to get maxCannons property from craft " +
90-
type.getStringProperty(CraftType.NAME) +
91-
" maxCannons won't be applied. - Cause: " +
92-
exception.getMessage()
93-
);
94-
return Set.of();
99+
for (CannonCheck check : cannonMaxMinChecks) {
100+
Optional<String> result = check.check(craft, cannonCount);
101+
102+
if (result.isEmpty()) continue;
103+
104+
String error = result.get();
105+
e.setCancelled(true);
106+
e.setFailMessage("Detection Failed! " + error);
107+
return true;
95108
}
109+
return false;
96110
}
97111
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package at.pavlov.cannons.hooks.movecraft.listener;
2+
3+
import at.pavlov.cannons.hooks.movecraft.MovecraftUtils;
4+
import net.countercraft.movecraft.events.CraftReleaseEvent;
5+
import org.bukkit.event.EventHandler;
6+
import org.bukkit.event.EventPriority;
7+
import org.bukkit.event.Listener;
8+
9+
public class ReleaseListener implements Listener {
10+
11+
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
12+
public void onRelease(CraftReleaseEvent event) {
13+
MovecraftUtils.getCannons(event.getCraft()).forEach(it -> it.setOnShip(false));
14+
}
15+
}

cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/SinkListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
import at.pavlov.cannons.hooks.movecraft.MovecraftUtils;
77
import net.countercraft.movecraft.events.CraftSinkEvent;
88
import org.bukkit.event.EventHandler;
9+
import org.bukkit.event.EventPriority;
910
import org.bukkit.event.Listener;
1011

1112
import java.util.Set;
1213

1314
public class SinkListener implements Listener {
1415

15-
@EventHandler
16+
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
1617
public void onCraftSink(CraftSinkEvent event) {
1718
Set<Cannon> cannons = MovecraftUtils.getCannons(event.getCraft());
1819
cannons.forEach(cannon -> CannonManager.getInstance().removeCannon(cannon.getUID(), false, true, BreakCause.Explosion));
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package at.pavlov.cannons.hooks.movecraft.type;
2+
3+
import net.countercraft.movecraft.craft.Craft;
4+
5+
import java.util.Map;
6+
import java.util.Optional;
7+
8+
public interface CannonCheck {
9+
Optional<String> check(Craft craft, Map<String, Integer> cannonCountMap);
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package at.pavlov.cannons.hooks.movecraft.type;
2+
3+
import at.pavlov.cannons.Cannons;
4+
import lombok.AccessLevel;
5+
import lombok.NoArgsConstructor;
6+
import org.bukkit.NamespacedKey;
7+
8+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
9+
public class CraftKeys {
10+
public static final NamespacedKey MAX_CANNONS = Cannons.nsKey("max_cannons");
11+
public static final NamespacedKey MIN_CANNONS = Cannons.nsKey("min_cannons");
12+
13+
public static final NamespacedKey MAX_MASS = Cannons.nsKey("max_mass");
14+
public static final NamespacedKey MIN_MASS = Cannons.nsKey("min_mass");
15+
public static final NamespacedKey EXCLUDE_FROM_MASS = Cannons.nsKey("exclude_from_mass");
16+
17+
public static final NamespacedKey USE_SHIP_ANGLES = Cannons.nsKey("use_ship_angles");
18+
}

0 commit comments

Comments
 (0)