Compare commits

...
12 Commits
Author SHA1 Message Date
auto 4953cec215 Make game logic adjustments and improve async command handling
Added permission checks for players bypassing game actions and refined block event handling based on game phase. Introduced asynchronous handling for permission commands to improve server performance. Updated constructors and dependencies to streamline game phase management.
2025-03-06 19:47:28 +01:00
auto 92f9e732a1 Remove redundant code and add victory reward commands
Removed unused methods and logging, such as `kickFromVoiceIfNeeded` and unnecessary permission checks. Added a feature to grant temporary permissions to winning players using LuckPerms. Updated the build number to reflect the changes.
2025-03-01 22:40:37 +01:00
auto 95b54d1a03 Prevent same-team players from being knocked back by flags.
Added a check to ensure players on the same team as the flag carrier are not affected by knockback when near the flag. Updated the build number to reflect the new changes.
2025-03-01 20:17:41 +01:00
auto 05a63b9a52 Prevent snowball throw if player hasn't selected a class
Added
2025-03-01 20:04:48 +01:00
auto 137e5a5125 Remove unused log, add null check, and update player teleport.
Removed a redundant logging statement from `OtherGameEvents`. Added a null check for shooter class in `SnowballEvent` to avoid potential issues. Enhanced player handling in `OnPlayerOnlineStatus` by teleporting players to their team’s spawn location if applicable.
2025-03-01 20:03:40 +01:00
auto 3c5842a92c Implement shield mechanics and enhance game end reset logic
Added shield blocking, cooldown, and breaking mechanics with sound and particle effects. Improved game reset functionality to properly remove players from teams at the end. Updated capture material and refactored imports for cleaner structure.
2025-03-01 19:29:46 +01:00
auto f5bb1564ae Increase spawn proximity threshold for class change checks.
Previously, players needed to be within 5 blocks of their spawn to switch classes. This threshold has been increased to 10 blocks, providing a better balance between gameplay flexibility and restrictions.
2025-03-01 18:29:09 +01:00
auto fa8d320da9 Refactor and optimize redundant code across the project
Removed unused imports and variables to streamline the codebase. Consolidated lambda expressions and improved formatting for better readability. Simplified methods by removing unnecessary parameters and redundant logic.
2025-03-01 01:22:13 +01:00
auto 816c429346 Remove leftover debug logging in broadcastNextPhaseStartTime
The debug log statement was unnecessary and likely left in by mistake. This change cleans up the code by removing it, ensuring the method only contains relevant functionality.
2025-03-01 01:17:58 +01:00
auto afbd1a9f09 Todo removed from tank class since the shield is strong enough now 2025-03-01 01:16:39 +01:00
auto 5430af2149 Remove completed TODO comments
Cleaned up obsolete TODO comments related to powdered snow mechanics and mage behavior.
2025-03-01 01:16:07 +01:00
auto ce7297afb8 Refactor flag point update logic for winning team.
Fixed the logic for updating flag point. Ensures correct handling of winning and losing teams by directly iterating through entries. This way points are reduced if a team is no longer "winning".
2025-03-01 01:15:48 +01:00
26 changed files with 184 additions and 107 deletions
+7 -8
View File
@@ -4,13 +4,11 @@ import com.alttd.ctf.commands.CommandManager;
import com.alttd.ctf.config.Config;
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.SnowballEvent;
import com.alttd.ctf.events.*;
import com.alttd.ctf.flag.Flag;
import com.alttd.ctf.flag.FlagTryCaptureEvent;
import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.game.phases.EndedPhase;
import com.alttd.ctf.gui.ClassSelectionGUI;
import com.alttd.ctf.gui.GUIInventory;
import com.alttd.ctf.gui.GUIListener;
@@ -38,10 +36,10 @@ import java.util.stream.Collectors;
public class Main extends JavaPlugin {
private GameManager gameManager = null;
private Flag flag;
@Override
public void onEnable() {
PlayerStat.main = this;
GUIInventory.setMain(this); // sorry
ClassSelectionGUI.setMain(this); // sorry
Package pkg = Main.class.getPackage();
@@ -50,10 +48,10 @@ public class Main extends JavaPlugin {
reloadConfigs();
WorldBorderApi worldBorderApi = worldBorder();
this.gameManager = new GameManager(worldBorderApi);
this.gameManager = new GameManager(this, worldBorderApi);
registerTeams(); //Skipped in reloadConfig if gameManager is not created yet
loadPlayerStats(); //Skipped in reloadConfig if gameManager is not created yet
flag = new Flag(this, gameManager);
Flag flag = new Flag(this, gameManager);
new CommandManager(this, gameManager, flag, worldBorderApi);
//Ensuring immediate respawn is on in all worlds
enableImmediateRespawn();
@@ -95,6 +93,7 @@ public class Main extends JavaPlugin {
private void registerEvents(Flag flag, WorldBorderApi worldBorderApi) {
PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new SnowballEvent(gameManager), this);
pluginManager.registerEvents(new OtherGameEvents(gameManager), this);
pluginManager.registerEvents(new FlagTryCaptureEvent(flag), this);
pluginManager.registerEvents(new OnPlayerDeath(gameManager, worldBorderApi, this, flag), this);
pluginManager.registerEvents(new InventoryItemInteractionEvent(), this);
@@ -163,4 +162,4 @@ public class Main extends JavaPlugin {
scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 1, java.util.concurrent.TimeUnit.MINUTES);
}
}
}
@@ -48,7 +48,7 @@ public class SelectClass extends SubCommand {
TeamPlayer teamPlayer = optionalTeamPlayer.get();
if (!teamPlayer.isDead()
&& !gamePhase.equals(GamePhase.CLASS_SELECTION)
&& teamPlayer.getTeam().getSpawnLocation().distance(player.getLocation()) > 5) {
&& teamPlayer.getTeam().getSpawnLocation().distance(player.getLocation()) > 10) {
commandSender.sendRichMessage("<red>You have to be near your spawn to change classes.</red>");
return 0;
}
@@ -3,16 +3,10 @@ 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 {
@@ -4,7 +4,6 @@ import com.alttd.ctf.Main;
import com.alttd.ctf.game.GamePhase;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
@@ -91,7 +90,7 @@ public class GameConfig extends AbstractConfig {
public static double CAPTURE_RADIUS = 5;
public static int CAPTURE_SCORE = 50;
public static double TURN_IN_RADIUS = 3;
public static @NotNull Material MATERIAL = Material.RED_BANNER;
public static @NotNull Material MATERIAL = Material.BLACK_BANNER;
@SuppressWarnings("unused")
private static void load() {
@@ -40,8 +40,12 @@ public class OnPlayerOnlineStatus implements Listener {
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
resetPlayer(player);
handleRunningGame(player);
if (!player.hasPermission("ctf.bypass")) {
handleRunningGame(player);
}
handleDiscordLink(player);
gameManager.getTeamPlayer(player).ifPresent(teamPlayer ->
player.teleportAsync(teamPlayer.getTeam().getSpawnLocation()));
}
private void handleRunningGame(Player player) {
@@ -1,6 +1,7 @@
package com.alttd.ctf.events;
import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.stats.Stat;
import com.alttd.ctf.team.TeamPlayer;
import lombok.extern.slf4j.Slf4j;
@@ -12,6 +13,7 @@ import org.bukkit.entity.ThrownPotion;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -29,7 +31,8 @@ public class OtherGameEvents implements Listener {
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
if (gameManager.getGamePhase().isEmpty()) {
Optional<GamePhase> gamePhase = gameManager.getGamePhase();
if (gamePhase.isEmpty() || gamePhase.get() == GamePhase.ENDED) {
return;
}
if (!Tag.SNOW.isTagged(event.getBlock().getType())) {
@@ -41,8 +44,9 @@ public class OtherGameEvents implements Listener {
}
@EventHandler
public void onBlockPlace(BlockBreakEvent event) {
if (gameManager.getGamePhase().isEmpty()) {
public void onBlockPlace(BlockPlaceEvent event) {
Optional<GamePhase> gamePhase = gameManager.getGamePhase();
if (gamePhase.isEmpty() || gamePhase.get() == GamePhase.ENDED) {
return;
}
if (!Tag.SNOW.isTagged(event.getBlock().getType())) {
@@ -9,6 +9,8 @@ import com.alttd.ctf.team.TeamPlayer;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Snowball;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -18,7 +20,11 @@ import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.time.Instant;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Optional;
import java.util.UUID;
@Slf4j
public class SnowballEvent implements Listener {
@@ -42,7 +48,8 @@ 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
if (blockedAttack(hitPlayer, shooter, snowball)) {
playBlockSounds(hitPlayer, shooter);
return;
}
GameClass shooterClass = shooterTeamPlayer.getGameClass();
@@ -57,13 +64,35 @@ public class SnowballEvent implements Listener {
}
log.debug("{} health was set to {} because of a snowball thrown by {}",
hitPlayer.getName(), Math.max(newHealth, 0), shooter.getName());
applyDamageEffects(hitPlayer, shooter);
});
}
private void playBlockSounds(Player hitPlayer, Player shooter) {
hitPlayer.playSound(hitPlayer.getLocation(), Sound.ITEM_SHIELD_BLOCK, 1.0f, 1.5f);
shooter.playSound(shooter.getLocation(), Sound.ITEM_SHIELD_BLOCK, 1.0f, 1.5f);
}
private void applyDamageEffects(Player hitPlayer, Player shooter) {
hitPlayer.getWorld().playSound(hitPlayer.getLocation(), Sound.ENTITY_PLAYER_HURT, 1.0f, 1.0f);
hitPlayer.getWorld().spawnParticle(
Particle.DAMAGE_INDICATOR,
hitPlayer.getLocation().add(0, 1, 0), 10, 0.5, 0.5, 0.5, 0.1
);
shooter.playSound(shooter.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.5f);
}
@EventHandler
public void onSnowballThrown(ProjectileLaunchEvent event) {
handleSnowballThrown(event, (shooter, shooterTeamPlayer, snowball) -> {
GameClass shooterClass = shooterTeamPlayer.getGameClass();
if (shooterClass == null) {
shooter.sendRichMessage("<red>You appear to not have selected a class, please do so by going to spawn and using /ctf selectclass</red>");
event.setCancelled(true);
return;
}
shooter.setCooldown(Material.SNOWBALL, shooterClass.getThrowTickSpeed());
shooterTeamPlayer.increaseStat(Stat.SNOWBALLS_THROWN);
if (shooterClass instanceof Mage mage) {
@@ -72,10 +101,22 @@ public class SnowballEvent implements Listener {
});
}
private boolean blockedAttack(@NotNull Player hitPlayer, @NotNull Snowball snowball) {
private final HashMap<UUID, LinkedList<Instant>> lastTankHits = new HashMap<>();
private boolean blockedAttack(@NotNull Player hitPlayer, @NotNull Player shooter, @NotNull Snowball snowball) {
if (!hitPlayer.isBlocking()) {
return false;
}
if (reachedMaxHits(hitPlayer)) {
hitPlayer.setCooldown(Material.SHIELD, 40);
if (hitPlayer.getInventory().getItemInMainHand().getType().equals(Material.SHIELD)) {
hitPlayer.swingMainHand();
} else if (hitPlayer.getInventory().getItemInOffHand().getType().equals(Material.SHIELD)) {
hitPlayer.swingOffHand();
}
applyBlockBrokenEffects(hitPlayer, shooter);
return false;
}
Location playerLocation = hitPlayer.getLocation();
Vector playerFacing = playerLocation.getDirection().normalize();
Location snowballLocation = snowball.getLocation();
@@ -86,6 +127,37 @@ public class SnowballEvent implements Listener {
return !(Math.toDegrees(angle) > 80); //Blocked if the angle was <= 80
}
private void applyBlockBrokenEffects(@NotNull Player hitPlayer, @NotNull Player shooter) {
hitPlayer.getWorld().playSound(hitPlayer.getLocation(), Sound.ITEM_SHIELD_BREAK, 1.0f, 1.0f);
Location shieldLocation = hitPlayer.getLocation()
.add(hitPlayer.getLocation().getDirection().normalize().multiply(0.5))
.add(0, 0.5, 0);
hitPlayer.getWorld().spawnParticle(
Particle.CRIT,
shieldLocation, 10, 0.5, 0.5, 0.5, 0.1
);
shooter.playSound(shooter.getLocation(), Sound.ITEM_SHIELD_BREAK, 1.0f, 1.5f);
}
private boolean reachedMaxHits(@NotNull Player hitPlayer) {
boolean reachedMaxHits = false;
Instant now = Instant.now();
LinkedList<Instant> lastHits = lastTankHits.getOrDefault(hitPlayer.getUniqueId(), new LinkedList<>());
Instant cutoffTime = now.minusMillis(300);
while (!lastHits.isEmpty() && lastHits.peek().isBefore(cutoffTime)) {
lastHits.poll();
}
lastHits.addLast(now);
if (lastHits.size() >= 3) {
lastHits.clear();
reachedMaxHits = true;
}
lastTankHits.put(hitPlayer.getUniqueId(), lastHits);
return reachedMaxHits;
}
private void handleSnowballThrown(ProjectileLaunchEvent event, SnowballThrownConsumer consumer) {
Optional<GamePhase> optionalGamePhase = gameManager.getGamePhase();
if (optionalGamePhase.isEmpty()) {
+16 -7
View File
@@ -81,10 +81,18 @@ public class Flag implements Runnable {
if (flagCarrier != null) {
return;
}
Team team = teamPlayer.getTeam();
flagLocation.getNearbyPlayers(5).forEach(nearbyPlayer -> {
if (nearbyPlayer.getUniqueId().equals(player.getUniqueId())) {
return;
}
Optional<TeamPlayer> nearByTeamPlayer = gameManager.getTeamPlayer(nearbyPlayer);
if (nearByTeamPlayer.isEmpty()) {
return;
} else if (nearByTeamPlayer.get().getTeam().equals(team)) {
return;
}
Vector direction = nearbyPlayer.getLocation().toVector().subtract(flagLocation.toVector()).normalize();
direction.setY(0.2);
nearbyPlayer.setVelocity(direction.multiply(5));
@@ -195,7 +203,7 @@ public class Flag implements Runnable {
});
}
LinkedList<Location> particleTrail = new LinkedList<>();
private final LinkedList<Location> particleTrail = new LinkedList<>();
private void spawnTrail() {
TeamColor color = winningTeam.getColor();
@@ -324,12 +332,13 @@ public class Flag implements Runnable {
}
Team winningTeam = teamLongEntry.getKey();
teamCounts.forEach((team, count) -> {
teamFlagPointCount.merge(team.getId(), team.equals(winningTeam) ? 1 : -1, (oldValue, delta) -> {
int updatedValue = oldValue + delta;
log.debug("Set count to {} for team {}", updatedValue, team.getId());
return Math.max(updatedValue, 0);
});
teamFlagPointCount.putIfAbsent(winningTeam.getId(), 0);
teamFlagPointCount.entrySet().forEach(entry -> {
if (entry.getKey().equals(winningTeam.getId())) {
entry.setValue(entry.getValue() + 1);
} else {
entry.setValue(Math.max(0, entry.getValue() - 1));
}
});
nearbyPlayers.forEach(teamPlayer -> teamPlayer.increaseStat(Stat.TIME_SPEND_CAPTURING_FLAG));
return true;
@@ -9,7 +9,6 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.util.Optional;
@@ -1,5 +1,6 @@
package com.alttd.ctf.game;
import com.alttd.ctf.Main;
import com.alttd.ctf.flag.Flag;
import com.alttd.ctf.game.phases.ClassSelectionPhase;
import com.alttd.ctf.game.phases.CombatPhase;
@@ -27,12 +28,12 @@ public class GameManager {
private final HashMap<Integer, Team> teams = new HashMap<>();
private final HashMap<UUID, PlayerStat> playerStats = new HashMap<>();
public GameManager(WorldBorderApi worldBorderApi) {
public GameManager(Main main, WorldBorderApi worldBorderApi) {
phases = new HashMap<>();
phases.put(GamePhase.CLASS_SELECTION, new ClassSelectionPhase(this, FighterCreator::createFighter, worldBorderApi));
phases.put(GamePhase.GATHERING, new GatheringPhase(this, worldBorderApi));
phases.put(GamePhase.COMBAT, new CombatPhase());
phases.put(GamePhase.ENDED, new EndedPhase());
phases.put(GamePhase.ENDED, new EndedPhase(main, this));
}
public Optional<GamePhase> getGamePhase() {
@@ -15,7 +15,6 @@ import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
@Slf4j
@@ -76,7 +75,6 @@ public class RunningGame implements Runnable {
private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) {
//Remaining time for this phase
Duration duration = phaseDurations.get(currentPhase).minus(Duration.between(phaseStartTime, Instant.now()));
log.debug(duration.toString());//TODO remove debug
if ((duration.toMinutes() > 1 && (duration.toMinutes() % 15 == 0 || duration.toMinutes() <= 5)) && duration.toSecondsPart() < 2) {
if (lastMinuteBroadcast == duration.toMinutes()) {
return;
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@Slf4j
@@ -1,7 +1,9 @@
package com.alttd.ctf.game.phases;
import com.alttd.ctf.Main;
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.game.GamePhaseExecutor;
import com.alttd.ctf.team.Team;
@@ -12,9 +14,11 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.command.ConsoleCommandSender;
import java.util.ArrayList;
import java.util.HashMap;
@@ -25,6 +29,13 @@ import java.util.Map;
public class EndedPhase implements GamePhaseExecutor {
private final MiniMessage miniMessage = MiniMessage.miniMessage();
private final Main main;
private final GameManager gameManager;
public EndedPhase(Main main, GameManager gameManager) {
this.main = main;
this.gameManager = gameManager;
}
@Override
public void start(Flag flag) {
@@ -51,8 +62,8 @@ public class EndedPhase implements GamePhaseExecutor {
player.setHealth(20);
});
flag.resetAll();
gameManager.getTeams().forEach(team -> Bukkit.getOnlinePlayers().forEach(team::removePlayer));
}).start();
// TODO reset world (coreprotect) to prep for next round
}
private List<Component> getWinnerMessages(HashMap<Team, Integer> wins) {
@@ -71,18 +82,29 @@ public class EndedPhase implements GamePhaseExecutor {
return messages;
} else if (topTeams.size() > 1) { // Draw scenario, multiple teams have the same top score
messages.add(miniMessage.deserialize("<yellow>It's a draw! Top teams:</yellow>"));
topTeams.forEach(team -> {
messages.add(miniMessage.deserialize("<team> had <score> captures.",
Placeholder.component("team", team.getName()),
Placeholder.parsed("score", String.valueOf(highestScore))));
});
topTeams.forEach(team -> messages.add(
miniMessage.deserialize("<team> had <score> captures.",
Placeholder.component("team", team.getName()),
Placeholder.parsed("score", String.valueOf(highestScore)))));
addOtherTeamsScore(wins, highestScore, messages);
return messages;
} else { // Single winner
Team winner = topTeams.getFirst();
messages.add(miniMessage.deserialize("<green><team> has won with <score> captures!</green>",
Placeholder.component("team", winner.getName()),
Placeholder.parsed("score", String.valueOf(highestScore))));
Placeholder.component("team", winner.getName()),
Placeholder.parsed("score", String.valueOf(highestScore))));
ConsoleCommandSender consoleSender = Bukkit.getConsoleSender();
Bukkit.getScheduler().runTaskAsynchronously(main, () -> {
winner.getPlayers().forEach(teamPlayer -> {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(teamPlayer.getUuid());
String name = offlinePlayer.getName();
if (name == null) {
return;
}
Bukkit.dispatchCommand(consoleSender, String.format("lp user %s permission settemp ctf.victory.%s true 14d", name, winner.getId()));
});
});
if (wins.size() <= 1) {
return messages;
}
@@ -97,8 +119,8 @@ public class EndedPhase implements GamePhaseExecutor {
wins.entrySet().stream()
.filter(entry -> entry.getValue() < winningScore)
.forEach(entry -> messages.add(miniMessage.deserialize("<yellow><team> had <score> captures.</yellow>",
Placeholder.component("team", entry.getKey().getName()),
Placeholder.parsed("score", String.valueOf(entry.getValue())))));
Placeholder.component("team", entry.getKey().getName()),
Placeholder.parsed("score", String.valueOf(entry.getValue())))));
}
@Override
@@ -36,14 +36,13 @@ public class GatheringPhase implements GamePhaseExecutor {
log.error("Unable to update world border due to missing Flag");
return;
}
gameManager.getTeams().forEach(team -> {
team.getPlayers().forEach(teamPlayer -> {
Player player = Bukkit.getPlayer(teamPlayer.getUuid());
if (player == null || !player.isOnline()) {
return;
}
teamPlayer.resetWorldBorder(player, worldBorderApi, nextPhase, flag.getFlagLocation());
});
});
gameManager.getTeams()
.forEach(team -> team.getPlayers().forEach(teamPlayer -> {
Player player = Bukkit.getPlayer(teamPlayer.getUuid());
if (player == null || !player.isOnline()) {
return;
}
teamPlayer.resetWorldBorder(player, worldBorderApi, nextPhase, flag.getFlagLocation());
}));
}
}
@@ -25,8 +25,6 @@ import java.util.List;
@Slf4j
public abstract class GameClass {
//TODO simple class that does powedered snow
//TODO mage uses up more snowballs shot gun style immediately spawn them when thrown 5 sec or so cooldown? mayb 3
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final List<Material> armor;
@@ -12,9 +12,7 @@ public class GameClassRetrieval {
public static HashMap<Integer, List<GameClass>> getGameClassesForAllTeams(GameManager gameManager) {
final HashMap<Integer, List<GameClass>> gameClasses = new HashMap<>();
gameManager.getTeams().forEach(team -> {
gameClasses.put(team.getId(), getGameClassesForTeam(team));
});
gameManager.getTeams().forEach(team -> gameClasses.put(team.getId(), getGameClassesForTeam(team)));
return gameClasses;
}
@@ -2,7 +2,6 @@ package com.alttd.ctf.game_class.creation;
import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.game_class.implementations.Engineer;
import com.alttd.ctf.game_class.implementations.Fighter;
import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.MiniMessage;
@@ -1,7 +1,6 @@
package com.alttd.ctf.game_class.creation;
import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.game_class.implementations.Fighter;
import com.alttd.ctf.game_class.implementations.Mage;
import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j;
@@ -10,8 +9,6 @@ import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
@@ -1,7 +1,6 @@
package com.alttd.ctf.game_class.creation;
import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.game_class.implementations.Fighter;
import com.alttd.ctf.game_class.implementations.Tank;
import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j;
@@ -22,7 +21,7 @@ public class TankCreator {
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
@Contract("_ -> new")
public static @NotNull GameClass createTank(@NotNull TeamColor teamColor) {//TODO add ability to become temp invulnerable (with some particle effects mayb?)
public static @NotNull GameClass createTank(@NotNull TeamColor teamColor) {
return new Tank(getArmor(), getTools(teamColor), getDisplayItem(teamColor),
30, 7, 4);
}
@@ -14,7 +14,6 @@ import org.jetbrains.annotations.Unmodifiable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
@Slf4j
public class TrapperCreator {
@@ -1,11 +1,9 @@
package com.alttd.ctf.game_class.implementations;
import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
-2
View File
@@ -2,8 +2,6 @@ package com.alttd.ctf.gui;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.Merchant;
import org.bukkit.inventory.MerchantInventory;
import java.util.HashMap;
import java.util.UUID;
@@ -1,5 +1,7 @@
package com.alttd.ctf.stats;
import com.alttd.ctf.Main;
import com.alttd.ctf.config.GameConfig;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
@@ -19,6 +21,9 @@ import java.util.UUID;
@RequiredArgsConstructor
@Getter
public final class PlayerStat {
@JsonIgnore
public static Main main;
@JsonIgnore
private boolean touched;
@JsonIgnore
@@ -48,7 +53,12 @@ public final class PlayerStat {
switch (stat) {
case COMPLETED_GAME -> {
if (!completedGame) {
Bukkit.dispatchCommand(commandSender, String.format("lp user %s permission settemp ctf.game.completed true 14d", inGameName));
Bukkit.getScheduler().runTask(main, () -> {
Bukkit.getScheduler().runTaskAsynchronously(main, () -> {
Bukkit.dispatchCommand(commandSender, String.format("lp user %s permission settemp ctf.game.completed true 14d", inGameName));
});
});
}
completedGame = true;
}
@@ -73,7 +83,10 @@ public final class PlayerStat {
}
Bukkit.broadcast(MiniMessage.miniMessage().deserialize("<red><player> will receive a consolation prize for being the first to die in powdered snow.</red>",
Placeholder.component("player",player.displayName())));
Bukkit.dispatchCommand(commandSender, String.format("lp user %s permission settemp ctf.game.first_powdered_snow_death true 14d", inGameName));
Bukkit.getScheduler().runTaskAsynchronously(main, () -> {
Bukkit.dispatchCommand(commandSender, String.format("lp user %s permission settemp ctf.game.first_powdered_snow_death true 14d", inGameName));
});
someoneDiedInPowderedSnow = true;
}
case DAMAGE_DONE, DAMAGE_HEALED -> throw new IllegalArgumentException(String.format("%s requires a number", stat.name()));
@@ -5,7 +5,6 @@ import com.alttd.ctf.game.GameManager;
import com.alttd.galaxy.discord.Bot;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -56,9 +55,7 @@ public class DiscordTeam {
}
Member nullableMember = guild.getMemberById(player.getDiscordID());
if (nullableMember == null) {
guild.retrieveMemberById(player.getDiscordID()).queue(member -> {
consumer.apply(role, member);
});
guild.retrieveMemberById(player.getDiscordID()).queue(member -> consumer.apply(role, member));
} else {
consumer.apply(role, nullableMember);
}
@@ -70,7 +67,7 @@ public class DiscordTeam {
log.info("Unable to remove team role from server owner");
return;
}
member.getGuild().removeRoleFromMember(member, role).queue(ignored -> kickFromVoiceIfNeeded(member));
member.getGuild().removeRoleFromMember(member, role).queue();
});
}
@@ -83,24 +80,8 @@ public class DiscordTeam {
gameManager.getTeams().forEach(otherTeam ->
member.getRoles().stream()
.filter(otherRole -> otherRole.getIdLong() == otherTeam.getDiscordRole())
.forEach(otherRole -> {
member.getGuild().removeRoleFromMember(member, otherRole).queue();
}));
member.getGuild().addRoleToMember(member, role).queue(ignored -> kickFromVoiceIfNeeded(member));
.forEach(otherRole -> member.getGuild().removeRoleFromMember(member, otherRole).queue()));
member.getGuild().addRoleToMember(member, role).queue();
});
}
private void kickFromVoiceIfNeeded(@NotNull Member member) {
GuildVoiceState voiceState = member.getVoiceState();
if (voiceState == null || !voiceState.inAudioChannel()) {
return;
}
AudioChannel channel = voiceState.getChannel();
if (channel == null) {
return;
}
if (!member.hasPermission(channel, Permission.VOICE_CONNECT)) {
member.getGuild().kickVoiceMember(member).queue();
}
}
}
@@ -2,8 +2,6 @@ package com.alttd.ctf.team;
import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.game.GamePhase;
import io.papermc.paper.scoreboard.numbers.NumberFormat;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.*;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
@@ -44,17 +42,17 @@ public class TeamScoreboard {
}
protected void setScore(int newScore) {
Objective objective = getOrCreateObjective("teamScores", "<gold>CTF score</gold>");
Objective objective = getOrCreateObjective();
Score score = objective.getScore(team.getLegacyTeamColor() +
PlainTextComponentSerializer.plainText().serialize(team.getName()));
score.setScore(newScore);
}
private static Objective getOrCreateObjective(String internalName, String displayName) {
Objective objective = scoreboard.getObjective(internalName);
private static Objective getOrCreateObjective() {
Objective objective = scoreboard.getObjective("teamScores");
if (objective == null) {
objective = scoreboard.registerNewObjective(internalName, Criteria.DUMMY,
MiniMessage.miniMessage().deserialize(displayName));
objective = scoreboard.registerNewObjective("teamScores", Criteria.DUMMY,
MiniMessage.miniMessage().deserialize("<gold>CTF score</gold>"));
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
}
return objective;
@@ -64,11 +62,11 @@ public class TeamScoreboard {
private static PhaseScore phaseScore = null;
private static void updateTime(GamePhase gamePhase, Duration duration) {
if (phaseScore == null) {
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective("teamScores", "<gold>CTF score</gold>")
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective()
.getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName())));
} else if (phaseScore.gamePhase() != gamePhase) {
phaseScore.score.resetScore();
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective("teamScores", "<gold>CTF score</gold>")
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective()
.getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName())));
}
phaseScore.score.setScore(duration.toMinutesPart() == 0 ? duration.toSecondsPart() : duration.toMinutesPart());
+2 -2
View File
@@ -1,3 +1,3 @@
#Sat Mar 01 00:39:55 CET 2025
buildNumber=91
#Sun Mar 02 00:42:30 CET 2025
buildNumber=112
version=0.1