Compare commits

..

No commits in common. "9563e9641f150e61614c210bc61f8b64aa6371da" and "4af509eb5fdf7f073bf6cd281e4dfec042b71716" have entirely different histories.

16 changed files with 42 additions and 214 deletions

View File

@ -6,7 +6,7 @@ import com.alttd.ctf.config.GameConfig;
import com.alttd.ctf.config.Messages;
import com.alttd.ctf.events.InventoryItemInteractionEvent;
import com.alttd.ctf.events.OnPlayerDeath;
import com.alttd.ctf.events.OnPlayerOnlineStatus;
import com.alttd.ctf.events.OnPlayerJoin;
import com.alttd.ctf.events.SnowballEvent;
import com.alttd.ctf.flag.Flag;
import com.alttd.ctf.flag.FlagTryCaptureEvent;
@ -87,9 +87,9 @@ public class Main extends JavaPlugin {
PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new SnowballEvent(gameManager), this);
pluginManager.registerEvents(new FlagTryCaptureEvent(flag), this);
pluginManager.registerEvents(new OnPlayerDeath(gameManager, worldBorderApi, this, flag), this);
pluginManager.registerEvents(new OnPlayerDeath(gameManager, worldBorderApi, this), this);
pluginManager.registerEvents(new InventoryItemInteractionEvent(), this);
pluginManager.registerEvents(new OnPlayerOnlineStatus(gameManager, flag), this);
pluginManager.registerEvents(new OnPlayerJoin(gameManager, flag), this);
pluginManager.registerEvents(new GUIListener(), this);
}

View File

@ -35,7 +35,6 @@ public class CommandManager implements CommandExecutor, TabExecutor {
subCommands = Arrays.asList(
new ChangeTeam(gameManager),
new SkipPhase(gameManager),
new Start(gameManager, flag),
new CreateTeam(main, gameManager),
new SelectClass(gameManager, worldBorderApi),

View File

@ -1,46 +0,0 @@
package com.alttd.ctf.commands.subcommands;
import com.alttd.ctf.commands.SubCommand;
import com.alttd.ctf.config.Messages;
import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.team.Team;
import lombok.AllArgsConstructor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Optional;
@AllArgsConstructor
public class SkipPhase extends SubCommand {
private final GameManager gameManager;
@Override
public int onCommand(CommandSender commandSender, String[] args) {
if (!gameManager.skipPhase()) {
commandSender.sendRichMessage("<red>The phase was not skipped because there is no running game or there is no next phase</red>");
return 0;
}
commandSender.sendRichMessage("<green>The current phase was skipped!</green>");
return 0;
}
@Override
public String getName() {
return "skipphase";
}
@Override
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
return List.of();
}
@Override
public String getHelpMessage() {
return Messages.HELP.SKIP_PHASE;
}
}

View File

@ -86,8 +86,7 @@ public class GameConfig extends AbstractConfig {
public static double y = 0;
public static double z = 0;
public static double CAPTURE_RADIUS = 5;
public static int CAPTURE_SCORE = 50;
public static double TURN_IN_RADIUS = 3;
public static int WINNING_SCORE = 50;
@SuppressWarnings("unused")
private static void load() {
@ -96,8 +95,7 @@ public class GameConfig extends AbstractConfig {
y = config.getDouble(prefix, "y", y);
z = config.getDouble(prefix, "z", z);
CAPTURE_RADIUS = config.getDouble(prefix, "capture-radius", CAPTURE_RADIUS);
CAPTURE_SCORE = config.getInt(prefix, "capture-score", CAPTURE_SCORE);
TURN_IN_RADIUS = config.getDouble(prefix, "turn-in-radius", TURN_IN_RADIUS);
WINNING_SCORE = config.getInt(prefix, "winning-score", WINNING_SCORE);
}
}

View File

@ -27,7 +27,6 @@ public class Messages extends AbstractConfig {
public static String CREATE_TEAM = "<green>Create a team: <gold>/ctf createteam <team_name> <hex_color></gold></green>";
public static String START = "<green>Start a new game: <gold>/ctf start <time_in_minutes></gold></green>";
public static String SELECT_CLASS = "<green>Open class selection: <gold>/ctf selectclass</gold></green>";
public static String SKIP_PHASE = "<green>Skip the current phase: <gold>/ctf skipphase</gold></green>";
@SuppressWarnings("unused")
private static void load() {
@ -38,7 +37,6 @@ public class Messages extends AbstractConfig {
CREATE_TEAM = config.getString(prefix, "create-team", CREATE_TEAM);
START = config.getString(prefix, "start", START);
SELECT_CLASS = config.getString(prefix, "select-class", SELECT_CLASS);
SKIP_PHASE = config.getString(prefix, "skip-phase", SKIP_PHASE);
}
}

View File

@ -1,15 +1,13 @@
package com.alttd.ctf.events;
import com.alttd.ctf.Main;
import com.alttd.ctf.config.Config;
import com.alttd.ctf.config.GameConfig;
import com.alttd.ctf.flag.Flag;
import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.team.TeamPlayer;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -25,13 +23,11 @@ public class OnPlayerDeath implements Listener {
private final GameManager gameManager;
private final WorldBorderApi worldBorderApi;
private final Main main;
private final Flag flag;
public OnPlayerDeath(GameManager gameManager, WorldBorderApi worldBorderApi, Main main, Flag flag) {
public OnPlayerDeath(GameManager gameManager, WorldBorderApi worldBorderApi, Main main) {
this.gameManager = gameManager;
this.worldBorderApi = worldBorderApi;
this.main = main;
this.flag = flag;
}
@EventHandler
@ -39,12 +35,11 @@ public class OnPlayerDeath implements Listener {
if (gameManager.getGamePhase().isEmpty()) {
return;
}
event.deathMessage(Component.empty());
event.deathMessage(null);
event.setShouldDropExperience(false);
Player player = event.getPlayer();
player.getInventory().clear();
player.updateInventory();
flag.handleCarrierDeathOrDisconnect(player);
}
@EventHandler
@ -61,9 +56,6 @@ public class OnPlayerDeath implements Listener {
}
TeamPlayer teamPlayer = optionalTeamPlayer.get();
event.setRespawnLocation(player.getWorld().getSpawnLocation());
player.sendRichMessage("<red>You died</red><nl><green>You will respawn in <seconds> seconds.</green>",
Placeholder.component("nl", Component.newline()),
Placeholder.parsed("seconds", String.valueOf(GameConfig.RESPAWN.TIME)));
Bukkit.getScheduler().runTaskLater(main, () -> teamPlayer.getGameClass().apply(teamPlayer, worldBorderApi, gamePhase.get(), true), GameConfig.RESPAWN.TIME * 20L);//10 x 20 ticks aka 10 seconds
}

View File

@ -12,19 +12,17 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
import java.util.Optional;
@Slf4j
public class OnPlayerOnlineStatus implements Listener {
public class OnPlayerJoin implements Listener {
private final GameManager gameManager;
private final Flag flag;
public OnPlayerOnlineStatus(GameManager gameManager, Flag flag) {
public OnPlayerJoin(GameManager gameManager, Flag flag) {
this.gameManager = gameManager;
this.flag = flag;
}
@ -66,9 +64,4 @@ public class OnPlayerOnlineStatus implements Listener {
player.teleportAsync(teamPlayer.getTeam().getSpawnLocation());
}
@EventHandler
public void onPlayerJoin(@NotNull PlayerQuitEvent event) {
flag.handleCarrierDeathOrDisconnect(event.getPlayer());
}
}

View File

@ -5,7 +5,6 @@ import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.team.TeamPlayer;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Snowball;
import org.bukkit.event.EventHandler;
@ -13,8 +12,6 @@ import org.bukkit.event.Listener;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
@ -29,7 +26,7 @@ public class SnowballEvent implements Listener {
@FunctionalInterface
private interface SnowballHitConsumer {
void apply(Player hitPlayer, Player shooter, TeamPlayer shooterTeamPlayer, Snowball snowball);
void apply(Player hitPlayer, Player shooter, TeamPlayer shooterTeamPlayer);
}
@FunctionalInterface
@ -39,10 +36,7 @@ public class SnowballEvent implements Listener {
@EventHandler
public void onSnowballHit(EntityDamageByEntityEvent event) {
handleSnowballHit(event, (hitPlayer, shooter, shooterTeamPlayer, snowball) -> {
if (blockedAttack(hitPlayer, snowball)) { //Disable damage when it is blocked
return;
}
handleSnowballHit(event, (hitPlayer, shooter, shooterTeamPlayer) -> {
GameClass shooterClass = shooterTeamPlayer.getGameClass();
shooter.setCooldown(Material.SNOWBALL, shooterClass.getThrowTickSpeed());
@ -61,20 +55,6 @@ public class SnowballEvent implements Listener {
});
}
private boolean blockedAttack(@NotNull Player hitPlayer, @NotNull Snowball snowball) {
if (!hitPlayer.isBlocking()) {
return false;
}
Location playerLocation = hitPlayer.getLocation();
Vector playerFacing = playerLocation.getDirection().normalize();
Location snowballLocation = snowball.getLocation();
Vector impactDirection = snowballLocation.toVector().subtract(playerLocation.toVector()).normalize();
double angle = playerFacing.angle(impactDirection);
return !(Math.toDegrees(angle) > 80); //Blocked if the angle was <= 80
}
private void handleSnowballThrown(ProjectileLaunchEvent event, SnowballThrownConsumer consumer) {
Optional<GamePhase> optionalGamePhase = gameManager.getGamePhase();
if (optionalGamePhase.isEmpty()) {
@ -141,6 +121,6 @@ public class SnowballEvent implements Listener {
log.debug("The shooter hit a member of their own team");
return;
}
consumer.apply(hitPlayer, shooter, teamPlayerHit.get(), snowball);
consumer.apply(hitPlayer, shooter, teamPlayerHit.get());
}
}

View File

@ -12,7 +12,6 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.kyori.adventure.title.Title;
import org.bukkit.*;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
@ -29,8 +28,6 @@ import java.util.stream.Collectors;
@Slf4j
public class Flag implements Runnable {
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final HashMap<Integer, Integer> teamFlagPointCount = new HashMap<>();
private final ItemStack flagItem = new ItemStack(Material.BLACK_BANNER);
private final BossBar bossBar = createBossBar();
@ -87,54 +84,23 @@ public class Flag implements Runnable {
)));
flagCarrier = player;
teamFlagPointCount.clear();
winningTeam = null;
lastWinningTeamId = -1;
bossBar.setProgress(0);
}
public void spawnFlag() {
Bukkit.getScheduler().runTask(main, () -> flagLocation.getBlock().setType(flagItem.getType()));
}
private void spawnFlagParticleRing() {
Location center = flagLocation.clone();
World world = center.getWorld();
double radius = 0.7;
double gap = 0.2;
double circumference = 2 * Math.PI * radius;
int particleCount = (int) (circumference / gap);
Particle particle = Particle.DUST;
TeamColor color = winningTeam.getColor();
// Generate particle positions
for (double heightOffset = 0; heightOffset < 2; heightOffset += 0.5) {
center.setY(center.getY() + 0.5);
for (int i = 0; i < particleCount; i++) {
double angle = 2 * Math.PI * i / particleCount;
double x = center.getX() + radius * Math.cos(angle);
double z = center.getZ() + radius * Math.sin(angle);
double y = center.getY();
world.spawnParticle(particle, x, y, z, 1, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(color.r(), color.g(), color.b()), 1));
}
}
}
@Override
public void run() {
if (flagCarrier != null) {
checkFlagCarrier();
return;
}
if (winningTeam != null) {
spawnFlagParticleRing();
return;
}
if (flagLocation == null) {
log.warn("Tried to run Flag without a flag location, spawn it first");
return;
}
spawnParticlesOnSquareBorder(flagLocation, GameConfig.FLAG.CAPTURE_RADIUS);
spawnParticlesOnSquareBorder(flagLocation.getWorld(), flagLocation);
if (!updateScoreBasedOnNearbyPlayers().join()) {
return; //Score didn't change
}
@ -152,9 +118,9 @@ public class Flag implements Runnable {
}
}
private void spawnParticlesOnSquareBorder(Location center, double size) {
private void spawnParticlesOnSquareBorder(World world, Location center) {
double size = 10;
double step = 0.2;
World world = center.getWorld();
Location finalCenter = center.clone().add(0, 0.5, 0);
Bukkit.getScheduler().runTask(main, () -> {
// Top and Bottom (Z varies, X constant)
@ -175,7 +141,7 @@ public class Flag implements Runnable {
private void spawnTrail() {
TeamColor color = winningTeam.getColor();
particleTrail.forEach(location -> location.getWorld().spawnParticle(Particle.DUST, location, 3, 0, 0, 0,
particleTrail.forEach(location -> location.getWorld().spawnParticle(Particle.DUST, location, 1, 0, 0, 0,
new Particle.DustOptions(Color.fromRGB(color.r(), color.g(), color.b()), 1)));
if (particleTrail.size() > 15) {
particleTrail.removeFirst();
@ -190,15 +156,18 @@ public class Flag implements Runnable {
return;
}
double distance = winningTeam.getFlagTurnInLocation().distance(flagCarrier.getLocation());
if (distance > GameConfig.FLAG.TURN_IN_RADIUS) {
if (distance > 2) {
Location location = flagCarrier.getLocation();
location.setY(location.getY() + 1);
particleTrail.add(location);
spawnTrail();
spawnParticlesOnSquareBorder(winningTeam.getWorldBorderCenter(), GameConfig.FLAG.TURN_IN_RADIUS);
//TODO spawn some particles or something so a trail is made for specific classes to follow?
return;
}
notifyAboutCapture();
//TODO better message? mayb with a text thing on the screen?
Bukkit.broadcast(MiniMessage.miniMessage().deserialize("<player> captured the flag for <team>!",
Placeholder.component("player", flagCarrier.displayName()),
Placeholder.component("team", winningTeam.getName())));
spawnFlag();
wins.merge(winningTeam.getId(), 1, Integer::sum);
winningTeam = null;
@ -214,30 +183,13 @@ public class Flag implements Runnable {
particleTrail.clear();
}
private void notifyAboutCapture() {
Bukkit.broadcast(miniMessage.deserialize("<player> captured the flag for <team>!",
Placeholder.component("player", flagCarrier.displayName()),
Placeholder.component("team", winningTeam.getName())));
Title capturingTeamTitle = Title.title(miniMessage.deserialize("<green><team> captured the flag!</green>",
Placeholder.component("team", winningTeam.getName())),
miniMessage.deserialize("<green>protect <player> while they bring it to your base.</green>",
Placeholder.component("player", flagCarrier.displayName())));
Title huntingTeamTitle = Title.title(miniMessage.deserialize("<red><team> captured the flag!</red>",
Placeholder.component("team", winningTeam.getName())),
miniMessage.deserialize("<red>kill <player> before they bring it to their base.</red>",
Placeholder.component("player", flagCarrier.displayName())));
Bukkit.getOnlinePlayers().forEach(player ->
gameManager.getTeam(player.getUniqueId()).ifPresent(team ->
player.showTitle(team.getId() == winningTeam.getId() ? capturingTeamTitle : huntingTeamTitle)));
}
private Optional<Team> winnerExists() {
Optional<Map.Entry<Integer, Integer>> max = teamFlagPointCount.entrySet().stream()
.max(Map.Entry.comparingByValue());
if (max.isEmpty()) {
return Optional.empty();
}
if (max.get().getValue() < GameConfig.FLAG.CAPTURE_SCORE) {
if (max.get().getValue() < GameConfig.FLAG.WINNING_SCORE) {
return Optional.empty();
}
return gameManager.getTeam(max.get().getKey());
@ -263,7 +215,7 @@ public class Flag implements Runnable {
/**
* Updates the score of teams based on the nearby players within a specified range.
* This method identifies nearby players around the current location within a CAPTURE_RADIUS-block radius,
* This method identifies nearby players around the current location within a 10-block radius,
* determines their respective teams, and calculates the team with the maximum number of players
* in proximity. If there is a tie for the maximum count, the method exits without updating scores.
* If a single team has the highest number of nearby players, scores are updated accordingly:
@ -331,7 +283,7 @@ public class Flag implements Runnable {
bossBar.setTitle(String.format("Team %s is capturing the flag", PlainTextComponentSerializer.plainText().serialize(team.get().getName())));
lastWinningTeamId = highestKey;
}
bossBar.setProgress(Math.min(GameConfig.FLAG.CAPTURE_SCORE, teamFlagPointCount.get(highestKey)) / (double) GameConfig.FLAG.CAPTURE_SCORE);
bossBar.setProgress(Math.min(GameConfig.FLAG.WINNING_SCORE, teamFlagPointCount.get(highestKey)) / (double) GameConfig.FLAG.WINNING_SCORE);
bossBar.setVisible(teamFlagPointCount.get(highestKey) > 0);
}
@ -359,21 +311,4 @@ public class Flag implements Runnable {
wins.clear();
lastWinningTeamId = -1;
}
public void handleCarrierDeathOrDisconnect(Player player) {
if (flagCarrier == null) {
return;
}
if (!flagCarrier.getUniqueId().equals(player.getUniqueId())) {
return;
}
flagCarrier = null;
particleTrail.clear();
spawnFlag();
gameManager.getTeam(player.getUniqueId())
.ifPresentOrElse(team -> Bukkit.broadcast(MiniMessage.miniMessage()
.deserialize("<red><team>'s flag carrier died! The flag has respawned",
Placeholder.component("team", team.getName()))),
() -> log.warn("A flag carrier died who was not part of a team"));
}
}

View File

@ -77,7 +77,7 @@ public class GameManager {
executorService.shutdown();
executorService = Executors.newSingleThreadScheduledExecutor();
}
runningGame = new RunningGame(this, duration, flag, executorService);
runningGame = new RunningGame(this, duration, flag);
executorService.scheduleAtFixedRate(runningGame, 0, 1, TimeUnit.SECONDS);
}
@ -99,11 +99,4 @@ public class GameManager {
.max()
.orElse(0);
}
public boolean skipPhase() {
if (runningGame == null) {
return false;
}
return runningGame.skipCurrentPhase();
}
}

View File

@ -13,7 +13,6 @@ import javax.annotation.Nullable;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.concurrent.ScheduledExecutorService;
@Slf4j
public class RunningGame implements Runnable {
@ -21,16 +20,14 @@ public class RunningGame implements Runnable {
private final HashMap<GamePhase, Duration> phaseDurations = GameConfig.PHASES.getGAME_PHASE_DURATION();
private final GameManager gameManager;
private final Flag flag;
private final ScheduledExecutorService executorService;
@Getter
private GamePhase currentPhase = GamePhase.values()[0];
private Instant phaseStartTime = null;
private int lastMinuteBroadcast = 0;
public RunningGame(GameManager gameManager, Duration gameDuration, Flag flag, ScheduledExecutorService executorService) {
public RunningGame(GameManager gameManager, Duration gameDuration, Flag flag) {
this.gameManager = gameManager;
this.flag = flag;
this.executorService = executorService;
phaseDurations.put(GamePhase.COMBAT, gameDuration);
}
@ -40,16 +37,16 @@ public class RunningGame implements Runnable {
GamePhase nextPhase = (currentPhase.ordinal() + 1 < GamePhase.values().length) ? GamePhase.values()[currentPhase.ordinal() + 1] : null;
if (phaseStartTime == null) {
phaseStartTime = Instant.now();
nextPhaseActions(null, currentPhase);
nextPhaseActions(null, currentPhase, nextPhase);
}
if (nextPhase != null && Duration.between(phaseStartTime, Instant.now()).compareTo(phaseDurations.get(currentPhase)) >= 0) {
nextPhaseActions(currentPhase, nextPhase);
if (Duration.between(phaseStartTime, Instant.now()).compareTo(phaseDurations.get(currentPhase)) >= 0) {
GamePhase previousPhase = currentPhase;
currentPhase = GamePhase.values()[currentPhase.ordinal() + 1]; //TODO fix this running out of bounds
nextPhaseActions(previousPhase, currentPhase, nextPhase);
phaseStartTime = Instant.now();
} else if (nextPhase != null) {
broadcastNextPhaseStartTime(currentPhase, nextPhase);
} else {
executorService.shutdown();
}
} catch (Exception e) {
log.error("Unexpected error in running game", e);
@ -57,13 +54,15 @@ public class RunningGame implements Runnable {
}
}
private void nextPhaseActions(@Nullable GamePhase previousPhase, @NotNull GamePhase phase) {
private void nextPhaseActions(@Nullable GamePhase previousPhase, @NotNull GamePhase phase, @Nullable GamePhase nextPhase) {
//TODO command to go to next phase
this.currentPhase = phase;
if (previousPhase != null) {
gameManager.getPhaseExecutor(previousPhase).end(phase);
}
gameManager.getPhaseExecutor(phase).start(flag);
if (nextPhase != null) {
broadcastNextPhaseStartTime(phase, nextPhase);
}
}
private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) {//TODO check how this works/what it should do
@ -87,18 +86,9 @@ public class RunningGame implements Runnable {
}
}
public boolean skipCurrentPhase() {
GamePhase nextPhase = (currentPhase.ordinal() + 1 < GamePhase.values().length) ? GamePhase.values()[currentPhase.ordinal() + 1] : null;
if (nextPhase == null) {
log.warn("Tried to skip phase {} but there is no next phase", currentPhase);
return false;
}
nextPhaseActions(currentPhase, nextPhase);
return true;
}
public void end() {
//TODO say the phase ended early?
nextPhaseActions(currentPhase, GamePhase.ENDED);
currentPhase = GamePhase.ENDED;
nextPhaseActions(null, currentPhase, null);
}
}

View File

@ -103,7 +103,7 @@ public abstract class GameClass {
ItemStack itemStack = new ItemStack(material);
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta instanceof LeatherArmorMeta leatherArmorMeta) {
leatherArmorMeta.setColor(Color.fromRGB(r, g, b));
leatherArmorMeta.setColor(Color.fromBGR(r, g, b));
itemStack.setItemMeta(leatherArmorMeta);
}
return itemStack;

View File

@ -57,7 +57,6 @@ public class EngineerCreator {
ItemMeta meta = shovel.getItemMeta();
meta.itemName(miniMessage.deserialize(String.format("<color:%s>Snow excavator</color>", teamColor.hex())));
meta.addEnchant(Enchantment.EFFICIENCY, 4, false);
meta.setUnbreakable(true);
shovel.setItemMeta(meta);
return shovel;
}

View File

@ -56,7 +56,6 @@ public class FighterCreator {
ItemMeta meta = shovel.getItemMeta();
meta.itemName(miniMessage.deserialize(String.format("<color:%s>Snow shovel</color>", teamColor.hex())));
meta.addEnchant(Enchantment.EFFICIENCY, 1, false);
meta.setUnbreakable(true);
shovel.setItemMeta(meta);
return shovel;
}

View File

@ -43,7 +43,6 @@ public class TankCreator {
itemMeta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE);
itemMeta.itemName(MiniMessage.miniMessage().deserialize(
String.format("<color:%s>Shield</color>", teamColor.hex())));
itemMeta.setUnbreakable(true);
shield.setItemMeta(itemMeta);
return shield;
}
@ -52,7 +51,6 @@ public class TankCreator {
ItemStack shovel = new ItemStack(Material.WOODEN_SHOVEL);
ItemMeta meta = shovel.getItemMeta();
meta.itemName(miniMessage.deserialize(String.format("<color:%s>Snow shovel</color>", teamColor.hex())));
meta.setUnbreakable(true);
shovel.setItemMeta(meta);
return shovel;
}

View File

@ -1,3 +1,3 @@
#Tue Feb 11 21:41:29 CET 2025
buildNumber=37
#Sat Feb 08 23:31:55 CET 2025
buildNumber=33
version=0.1