Integrate WorldBorderAPI and enhance game phase functionality

Added WorldBorderAPI dependency to manage player boundaries dynamically during game phases. Updated game phases, respawn mechanics, and class selection to utilize the WorldBorderAPI. Reworked related components to improve boundary handling, ensuring consistent gameplay flow and preparation for future enhancements.
This commit is contained in:
Teriuihi 2025-02-08 20:45:06 +01:00
parent e5077b40c5
commit be7b508667
20 changed files with 181 additions and 67 deletions

View File

@ -31,6 +31,8 @@ dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2")
// End JSON config dependencies
// WorldBorderAPI
compileOnly("com.github.yannicklamprecht:worldborderapi:1.210.0:dev")
}
tasks.test {

View File

@ -5,6 +5,10 @@ dependencyResolutionManagement {
mavenLocal()
mavenCentral()
maven("https://repo.destro.xyz/snapshots") // Altitude - Galaxy
maven { // WorldBorderAPI
name = "eldonexus"
url = uri("https://eldonexus.de/repository/maven-releases/")
}
}
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
}

View File

@ -15,11 +15,13 @@ import com.alttd.ctf.gui.GUIListener;
import com.alttd.ctf.json_config.JacksonConfig;
import com.alttd.ctf.json_config.JsonConfigManager;
import com.alttd.ctf.team.Team;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Bukkit;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
@ -40,10 +42,11 @@ public class Main extends JavaPlugin {
log.info("Plugin enabled, version {}", version);
reloadConfigs();
this.gameManager = new GameManager();
WorldBorderApi worldBorderApi = worldBorder();
this.gameManager = new GameManager(worldBorderApi);
registerTeams(); //Skipped in reloadConfig if gameManager is not created yet
flag = new Flag(this, gameManager);
CommandManager commandManager = new CommandManager(this, gameManager, flag);
new CommandManager(this, gameManager, flag, worldBorderApi);
//Ensuring immediate respawn is on in all worlds
log.info("Enabling immediate respawn for {}.", Config.FLAG.world);
World world = Bukkit.getWorld(Config.FLAG.world);
@ -52,7 +55,7 @@ public class Main extends JavaPlugin {
} else {
log.error("No valid flag world defined, unable to modify game rules");
}
registerEvents(flag);
registerEvents(flag, worldBorderApi);
}
public void reloadConfigs() {
@ -64,12 +67,23 @@ public class Main extends JavaPlugin {
}
}
private void registerEvents(Flag flag) {
private WorldBorderApi worldBorder() {
RegisteredServiceProvider<WorldBorderApi> worldBorderApiRegisteredServiceProvider = getServer().getServicesManager().getRegistration(WorldBorderApi.class);
if (worldBorderApiRegisteredServiceProvider == null) {
log.error("WorldBorder API not found, disabling plugin");
getServer().getPluginManager().disablePlugin(this);
return null;
}
return worldBorderApiRegisteredServiceProvider.getProvider();
}
private void registerEvents(Flag flag, WorldBorderApi worldBorderApi) {
PluginManager pluginManager = getServer().getPluginManager();
//TODO add event for player joining and clear their inv
pluginManager.registerEvents(new SnowballEvent(gameManager), this);
pluginManager.registerEvents(new FlagTryCaptureEvent(flag), this);
pluginManager.registerEvents(new OnPlayerDeath(gameManager), this);
pluginManager.registerEvents(new OnPlayerDeath(gameManager, worldBorderApi), this);
pluginManager.registerEvents(new InventoryItemInteractionEvent(), this);
pluginManager.registerEvents(new OnPlayerJoin(gameManager, flag), this);
pluginManager.registerEvents(new GUIListener(), this);

View File

@ -5,6 +5,7 @@ import com.alttd.ctf.commands.subcommands.*;
import com.alttd.ctf.config.Messages;
import com.alttd.ctf.flag.Flag;
import com.alttd.ctf.game.GameManager;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
@ -22,7 +23,7 @@ import java.util.stream.Collectors;
public class CommandManager implements CommandExecutor, TabExecutor {
private final List<SubCommand> subCommands;
public CommandManager(Main main, GameManager gameManager, Flag flag) {
public CommandManager(Main main, GameManager gameManager, Flag flag, WorldBorderApi worldBorderApi) {
PluginCommand command = main.getCommand("ctf");
if (command == null) {
subCommands = null;
@ -36,7 +37,7 @@ public class CommandManager implements CommandExecutor, TabExecutor {
new ChangeTeam(gameManager),
new Start(gameManager, flag),
new CreateTeam(main, gameManager),
new SelectClass(gameManager),
new SelectClass(gameManager, worldBorderApi),
new Reload(main)
);
}

View File

@ -10,6 +10,7 @@ import com.alttd.ctf.game_class.creation.FighterCreator;
import com.alttd.ctf.game_class.creation.TankCreator;
import com.alttd.ctf.gui.ClassSelectionGUI;
import com.alttd.ctf.team.TeamPlayer;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -22,9 +23,11 @@ public class SelectClass extends SubCommand {
private final GameManager gameManager;
private final HashMap<Integer, List<GameClass>> gameClasses;
private final WorldBorderApi worldBorderApi;
public SelectClass(GameManager gameManager) {
public SelectClass(GameManager gameManager, WorldBorderApi worldBorderApi) {
this.gameManager = gameManager;
this.worldBorderApi = worldBorderApi;
this.gameClasses = new HashMap<>();
gameManager.getTeams().forEach(team -> {
gameClasses.computeIfAbsent(team.getId(), teamId -> new ArrayList<>()).add(FighterCreator.createFighter(team.getColor()));
@ -55,7 +58,7 @@ public class SelectClass extends SubCommand {
commandSender.sendRichMessage("<red>You have to be near your spawn to change classes.</red>");
return 0;
}
new ClassSelectionGUI(gameClasses.get(teamPlayer.getTeam().getId()), teamPlayer)
new ClassSelectionGUI(gameClasses.get(teamPlayer.getTeam().getId()), teamPlayer, worldBorderApi, gamePhase)
.open(player);
return 0;
}

View File

@ -1,7 +1,10 @@
package com.alttd.ctf.events;
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 org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -10,12 +13,15 @@ import org.bukkit.event.player.PlayerRespawnEvent;
import java.util.Optional;
@Slf4j
public class OnPlayerDeath implements Listener {
private final GameManager gameManager;
private final WorldBorderApi worldBorderApi;
public OnPlayerDeath(GameManager gameManager) {
public OnPlayerDeath(GameManager gameManager, WorldBorderApi worldBorderApi) {
this.gameManager = gameManager;
this.worldBorderApi = worldBorderApi;
}
@EventHandler
@ -33,13 +39,18 @@ public class OnPlayerDeath implements Listener {
@EventHandler
public void onPlayerRespawn(PlayerRespawnEvent event) {
Player player = event.getPlayer();
Optional<GamePhase> gamePhase = gameManager.getGamePhase();
if (gamePhase.isEmpty()) {
log.warn("Player {} died while the game wasn't running", player.getName());
return;
}
Optional<TeamPlayer> optionalTeamPlayer = gameManager.getTeamPlayer(player.getUniqueId());
if (optionalTeamPlayer.isEmpty()) {
return;
}
TeamPlayer teamPlayer = optionalTeamPlayer.get();
event.setRespawnLocation(teamPlayer.getTeam().getSpawnLocation());
teamPlayer.getGameClass().apply(teamPlayer);
teamPlayer.getGameClass().apply(teamPlayer, worldBorderApi, gamePhase.get(), false);
}
}

View File

@ -6,6 +6,7 @@ import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.team.Team;
import com.alttd.ctf.team.TeamColor;
import com.alttd.ctf.team.TeamPlayer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.MiniMessage;
@ -30,7 +31,6 @@ import java.util.concurrent.Future;
import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
public class Flag implements Runnable {
private final HashMap<Integer, Integer> teamFlagPointCount = new HashMap<>();
@ -38,13 +38,24 @@ public class Flag implements Runnable {
private final BossBar bossBar = createBossBar();
private final HashMap<Integer, Integer> wins = new HashMap<>();
private int lastWinningTeamId = -1;
private Location flagLocation;
@Getter
private final Location flagLocation;
private Team winningTeam;
private Player flagCarrier;
private final Main main;
private final GameManager gameManager;
public Flag(Main main, GameManager gameManager) {
this.main = main;
this.gameManager = gameManager;
World world = Bukkit.getWorld(Config.FLAG.world);
if (world == null) {
throw new IllegalStateException(String.format("Tried to spawn flag in world [%s] that doesn't exist", Config.FLAG.world));
}
this.flagLocation = new Location(world, Config.FLAG.x, Config.FLAG.y, Config.FLAG.z);
}
private BossBar createBossBar() {
NamespacedKey namespacedKey = NamespacedKey.fromString("ctf_flag", main);
if (namespacedKey == null) {
@ -60,10 +71,6 @@ public class Flag implements Runnable {
return captureProgress;
}
protected Location getFlagLocation() {
return flagLocation;
}
public void addPlayer(Player player) {
bossBar.addPlayer(player);
}
@ -85,13 +92,6 @@ public class Flag implements Runnable {
}
public void spawnFlag() {
//TODO disable flag capture for a minute or so, and maybe have it slowly drop down?
World world = Bukkit.getWorld(Config.FLAG.world);
if (world == null) {
throw new IllegalStateException(String.format("Tried to spawn flag in world [%s] that doesn't exist", Config.FLAG.world));
}
this.flagLocation = new Location(world, Config.FLAG.x, Config.FLAG.y, Config.FLAG.z);
//Place block on main thread
Bukkit.getScheduler().runTask(main, () -> flagLocation.getBlock().setType(flagItem.getType()));
}
@ -126,18 +126,18 @@ public class Flag implements Runnable {
private void spawnParticlesOnSquareBorder(World world, Location center) {
double size = 10;
double step = 0.2;
center.add(0, 0.5, 0);
Location finalCenter = center.clone().add(0, 0.5, 0);
Bukkit.getScheduler().runTask(main, () -> {
// Top and Bottom (Z varies, X constant)
for (double z = -size; z <= size; z += step) {
world.spawnParticle(Particle.FLAME, center.getX() + size, center.getY(), center.getZ() + z, 1, 0, 0, 0, 0);
world.spawnParticle(Particle.FLAME, center.getX() - size, center.getY(), center.getZ() + z, 1, 0, 0, 0, 0);
world.spawnParticle(Particle.FLAME, finalCenter.getX() + size, finalCenter.getY(), finalCenter.getZ() + z, 1, 0, 0, 0, 0);
world.spawnParticle(Particle.FLAME, finalCenter.getX() - size, finalCenter.getY(), finalCenter.getZ() + z, 1, 0, 0, 0, 0);
}
// Left and Right (X varies, Z constant)
for (double x = -size; x <= size; x += step) {
world.spawnParticle(Particle.FLAME, center.getX() + x, center.getY(), center.getZ() + size, 1, 0, 0, 0, 0);
world.spawnParticle(Particle.FLAME, center.getX() + x, center.getY(), center.getZ() - size, 1, 0, 0, 0, 0);
world.spawnParticle(Particle.FLAME, finalCenter.getX() + x, finalCenter.getY(), finalCenter.getZ() + size, 1, 0, 0, 0, 0);
world.spawnParticle(Particle.FLAME, finalCenter.getX() + x, finalCenter.getY(), finalCenter.getZ() - size, 1, 0, 0, 0, 0);
}
});
}

View File

@ -8,6 +8,7 @@ import com.alttd.ctf.game.phases.GatheringPhase;
import com.alttd.ctf.game_class.creation.FighterCreator;
import com.alttd.ctf.team.Team;
import com.alttd.ctf.team.TeamPlayer;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@ -24,10 +25,10 @@ public class GameManager {
private RunningGame runningGame;
private final HashMap<Integer, Team> teams = new HashMap<>();
public GameManager() {
public GameManager(WorldBorderApi worldBorderApi) {
phases = new HashMap<>();
phases.put(GamePhase.CLASS_SELECTION, new ClassSelectionPhase(this, (FighterCreator::createFighter)));
phases.put(GamePhase.GATHERING, new GatheringPhase());
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());
}

View File

@ -6,14 +6,16 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
@Getter
public enum GamePhase {
CLASS_SELECTION(MiniMessage.miniMessage().deserialize("<green>Class selection phase</green>")),
GATHERING(MiniMessage.miniMessage().deserialize("<green>Gathering phase</green>")),
COMBAT(MiniMessage.miniMessage().deserialize("<green>Combat phase</green>")),
ENDED(MiniMessage.miniMessage().deserialize("<green>Game end phase</green>"));
CLASS_SELECTION(MiniMessage.miniMessage().deserialize("<green>Class selection phase</green>"), 25),
GATHERING(MiniMessage.miniMessage().deserialize("<green>Gathering phase</green>"), 50),
COMBAT(MiniMessage.miniMessage().deserialize("<green>Combat phase</green>"), 0),
ENDED(MiniMessage.miniMessage().deserialize("<green>Game end phase</green>"), 0);
private final Component displayName;
private final double worldBorderSize;
GamePhase(Component displayName) {
GamePhase(Component displayName, double worldBorderSize) {
this.displayName = displayName;
this.worldBorderSize = worldBorderSize;
}
}

View File

@ -6,5 +6,5 @@ public interface GamePhaseExecutor {
void start(Flag flag);
void end();
void end(GamePhase nextGamePhase);
}

View File

@ -52,7 +52,7 @@ public class RunningGame implements Runnable {
private void nextPhaseActions(@Nullable GamePhase previousPhase, @NotNull GamePhase phase, @Nullable GamePhase nextPhase) {
//TODO command to go to next phase
if (previousPhase != null) {
gameManager.getPhaseExecutor(previousPhase).end();
gameManager.getPhaseExecutor(previousPhase).end(phase);
}
gameManager.getPhaseExecutor(phase).start(flag);
if (nextPhase != null) {

View File

@ -2,16 +2,18 @@ package com.alttd.ctf.game.phases;
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.game_class.GameClass;
import com.alttd.ctf.team.Team;
import com.alttd.ctf.team.TeamColor;
import com.alttd.ctf.team.TeamPlayer;
import com.alttd.ctf.util.CircularIterator;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import lombok.extern.slf4j.Slf4j;
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.jetbrains.annotations.NotNull;
import java.util.Optional;
@ -21,20 +23,22 @@ public class ClassSelectionPhase implements GamePhaseExecutor {
private final GameManager gameManager;
private final DefaultClassCreator defaultClassCreator;
private final WorldBorderApi worldBorderApi;
@FunctionalInterface
public interface DefaultClassCreator {
@NotNull GameClass apply(TeamColor teamColor);
}
public ClassSelectionPhase(@NotNull GameManager gameManager, DefaultClassCreator defaultClassCreator) {
public ClassSelectionPhase(@NotNull GameManager gameManager, DefaultClassCreator defaultClassCreator,
@NotNull WorldBorderApi worldBorderApi) {
this.gameManager = gameManager;
this.defaultClassCreator = defaultClassCreator;
this.worldBorderApi = worldBorderApi;
}
@Override
public void start(Flag flag) {
teleportPlayersToStartingZone();
Bukkit.broadcast(MiniMessage.miniMessage().deserialize("<green>Select your class</green>"));
CircularIterator<Team> teamCircularIterator = new CircularIterator<>(gameManager.getTeams());
if (teamCircularIterator.hasNext()) {
@ -48,34 +52,36 @@ public class ClassSelectionPhase implements GamePhaseExecutor {
} else {
log.warn("No teams to add players to");
}
//TODO let players select classes
// They should always be able to do this when in their starting zone
// They should be locked into their starting zone until the next phase starts
// That phase should handle opening the zone
teleportPlayersToStartingZone();
}
private void teleportPlayersToStartingZone() {
Bukkit.getOnlinePlayers().forEach(player -> {
Optional<Team> team = gameManager.getTeam(player.getUniqueId());
if (team.isEmpty()) {
Optional<TeamPlayer> teamPlayer = gameManager.getTeamPlayer(player.getUniqueId());
if (teamPlayer.isEmpty()) {
log.warn("{} is not a team player when teleporting to starting zone", player.getName());
return;
}
Location spawnLocation = team.get().getSpawnLocation();
player.teleportAsync(spawnLocation);
Optional<GamePhase> gamePhase = gameManager.getGamePhase();
if (gamePhase.isEmpty()) {
log.warn("Game phase is empty when teleporting to starting zone");
return;
}
teamPlayer.get().respawn(player, worldBorderApi, gamePhase.get());
});
}
@Override
public void end() {
public void end(GamePhase nextPhase) {
gameManager.getTeams().forEach(team -> {
GameClass defaultClass = defaultClassCreator.apply(team.getColor());
team.getPlayers().forEach(player -> {
player.resetWorldBorder(Bukkit.getPlayer(player.getUuid()), worldBorderApi, nextPhase, team.getWorldBorderCenter());
if (player.getGameClass() != null) {
return;
}
defaultClass.apply(player);
defaultClass.apply(player, worldBorderApi, nextPhase, false);
});
});
//TODO expand world border so ppl can gather things but not get near the flag yet
}
}

View File

@ -1,6 +1,7 @@
package com.alttd.ctf.game.phases;
import com.alttd.ctf.flag.Flag;
import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.game.GamePhaseExecutor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
@ -28,7 +29,7 @@ public class CombatPhase implements GamePhaseExecutor {
}
@Override
public void end() {
public void end(GamePhase ignored) {
executorService.shutdown();
}
}

View File

@ -2,6 +2,7 @@ package com.alttd.ctf.game.phases;
import com.alttd.ctf.config.Config;
import com.alttd.ctf.flag.Flag;
import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.game.GamePhaseExecutor;
import com.alttd.ctf.team.Team;
import lombok.extern.slf4j.Slf4j;
@ -101,7 +102,7 @@ public class EndedPhase implements GamePhaseExecutor {
}
@Override
public void end() {
public void end(GamePhase ignored) {
}
}

View File

@ -1,20 +1,45 @@
package com.alttd.ctf.game.phases;
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.game_class.GameClass;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
@Slf4j
public class GatheringPhase implements GamePhaseExecutor {
private final GameManager gameManager;
private final WorldBorderApi worldBorderApi;
private Flag flag;
public GatheringPhase(GameManager gameManager, WorldBorderApi worldBorderApi) {
this.gameManager = gameManager;
this.worldBorderApi = worldBorderApi;
}
@Override
public void start(Flag flag) {
this.flag = flag;
Bukkit.broadcast(MiniMessage.miniMessage().deserialize("<green>Gather materials and prepare for combat!</green>"));
//TODO give everyone haste or something so they can mine faster till this game phase ends
// Let them store things at base during this phase, after only one class can do this?
}
@Override
public void end() {
//TODO Remove team area barrier
public void end(GamePhase nextPhase) {
if (flag == null) {
log.error("Unable to update world border due to missing Flag");
return;
}
gameManager.getTeams().forEach(team -> {
team.getPlayers().forEach(player -> {
player.resetWorldBorder(Bukkit.getPlayer(player.getUuid()), worldBorderApi, nextPhase, flag.getFlagLocation());
});
});
}
}

View File

@ -1,7 +1,9 @@
package com.alttd.ctf.game_class;
import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.team.TeamColor;
import com.alttd.ctf.team.TeamPlayer;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.Component;
@ -68,7 +70,7 @@ public abstract class GameClass {
displayItem.setItemMeta(itemMeta);
}
public void apply(TeamPlayer teamPlayer) {
public void apply(TeamPlayer teamPlayer, WorldBorderApi worldBorderApi, GamePhase gamePhase, boolean teleport) {
Player player = Bukkit.getPlayer(teamPlayer.getUuid());
if (player == null || !player.isOnline()) {
log.warn("Tried to give class to offline player {}", player == null ? teamPlayer.getUuid() : player.getName());
@ -91,7 +93,7 @@ public abstract class GameClass {
player.updateInventory();
teamPlayer.setGameClass(this);
player.sendRichMessage("You selected the <class_name> class", Placeholder.component("class_name", className));
player.teleportAsync(teamPlayer.getTeam().getSpawnLocation());
teamPlayer.respawn(player, worldBorderApi, gamePhase, teleport);
}
private void setArmor(Player player, int r, int g, int b) {

View File

@ -1,7 +1,9 @@
package com.alttd.ctf.gui;
import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.team.TeamPlayer;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryType;
@ -11,16 +13,17 @@ import java.util.List;
public class ClassSelectionGUI extends GUIInventory {
public ClassSelectionGUI(@NotNull List<GameClass> gameClasses, @NotNull TeamPlayer teamPlayer) {
public ClassSelectionGUI(@NotNull List<GameClass> gameClasses, @NotNull TeamPlayer teamPlayer,
@NotNull WorldBorderApi worldBorderApi, @NotNull GamePhase gamePhase) {
super(InventoryType.CHEST, teamPlayer.getTeam().getName().append(MiniMessage.miniMessage().deserialize(" - class selection")));
createClassSelection(gameClasses, teamPlayer);
createClassSelection(gameClasses, teamPlayer, worldBorderApi, gamePhase);
}
private void createClassSelection(@NotNull List<GameClass> gameClasses, @NotNull TeamPlayer teamPlayer) {
private void createClassSelection(@NotNull List<GameClass> gameClasses, @NotNull TeamPlayer teamPlayer, @NotNull WorldBorderApi worldBorderApi, @NotNull GamePhase gamePhase) {
int pos = (9 + (9 - gameClasses.size()) / 2);
for (GameClass gameClass : gameClasses) {
setItem(pos++, gameClass.getDisplayItem(), player -> {
gameClass.apply(teamPlayer);
gameClass.apply(teamPlayer, worldBorderApi, gamePhase, true);
player.closeInventory(InventoryCloseEvent.Reason.PLUGIN);
});
}

View File

@ -33,7 +33,7 @@ public class Team {
@JsonProperty("worldBorderCenter")
@NotNull
@Getter
private Location worldBorderCenter; //TODO https://github.com/yannicklamprecht/WorldBorderAPI/blob/main/how-to-use.md
private Location worldBorderCenter; // https://github.com/yannicklamprecht/WorldBorderAPI/blob/main/how-to-use.md
@JsonProperty("teamColor")
@NotNull
@Getter

View File

@ -1,12 +1,21 @@
package com.alttd.ctf.team;
import com.alttd.ctf.game.GamePhase;
import com.alttd.ctf.game_class.GameClass;
import com.github.yannicklamprecht.worldborder.api.IWorldBorder;
import com.github.yannicklamprecht.worldborder.api.Position;
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.UUID;
@Slf4j
@Getter
public class TeamPlayer {
@ -20,6 +29,35 @@ public class TeamPlayer {
this.team = team;
}
public void respawn(@NotNull Player player, @NotNull WorldBorderApi worldBorderApi, @NotNull GamePhase gamePhase) {
respawn(player, worldBorderApi, gamePhase, true);
}
public void respawn(Player player, WorldBorderApi worldBorderApi, GamePhase gamePhase, boolean teleport) {
Location spawnLocation = team.getSpawnLocation();
Location worldBorderCenter = team.getWorldBorderCenter();
if (!teleport) {
resetWorldBorder(player, worldBorderApi, gamePhase, worldBorderCenter);
return;
}
player.teleportAsync(spawnLocation).thenAcceptAsync(unused ->
resetWorldBorder(player, worldBorderApi, gamePhase, worldBorderCenter));
}
public void resetWorldBorder(Player player, WorldBorderApi worldBorderApi, GamePhase gamePhase, Location worldBorderCenter) {
log.info("Resetting world border for {}", player.getName());
double worldBorderSize = gamePhase.getWorldBorderSize();
log.info("Resetting world border to {} for {}", worldBorderSize, player.getName());
IWorldBorder worldBorder = worldBorderApi.getWorldBorder(player);
if (worldBorderSize <= 0) {
log.info("Resetting world border to global for {}", player.getName());
worldBorderApi.resetWorldBorderToGlobal(player);
return;
}
log.info("Resetting world border to {} for {}", worldBorderCenter.toString(), player.getName());
worldBorderApi.setBorder(player, worldBorderSize, worldBorderCenter);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {

View File

@ -1,3 +1,3 @@
#Sat Feb 08 00:30:51 CET 2025
buildNumber=11
#Sat Feb 08 20:41:32 CET 2025
buildNumber=18
version=0.1