Compare commits

..

No commits in common. "fa8d320da9a52998277f4bd4008ee174ec1280d1" and "a10607092b98625805780fee582add851d8c8af8" have entirely different histories.

20 changed files with 72 additions and 39 deletions

View File

@ -38,6 +38,7 @@ import java.util.stream.Collectors;
public class Main extends JavaPlugin { public class Main extends JavaPlugin {
private GameManager gameManager = null; private GameManager gameManager = null;
private Flag flag;
@Override @Override
public void onEnable() { public void onEnable() {
@ -52,7 +53,7 @@ public class Main extends JavaPlugin {
this.gameManager = new GameManager(worldBorderApi); this.gameManager = new GameManager(worldBorderApi);
registerTeams(); //Skipped in reloadConfig if gameManager is not created yet registerTeams(); //Skipped in reloadConfig if gameManager is not created yet
loadPlayerStats(); //Skipped in reloadConfig if gameManager is not created yet loadPlayerStats(); //Skipped in reloadConfig if gameManager is not created yet
Flag flag = new Flag(this, gameManager); flag = new Flag(this, gameManager);
new CommandManager(this, gameManager, flag, worldBorderApi); new CommandManager(this, gameManager, flag, worldBorderApi);
//Ensuring immediate respawn is on in all worlds //Ensuring immediate respawn is on in all worlds
enableImmediateRespawn(); enableImmediateRespawn();
@ -162,4 +163,4 @@ public class Main extends JavaPlugin {
scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 1, java.util.concurrent.TimeUnit.MINUTES); scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 1, java.util.concurrent.TimeUnit.MINUTES);
} }
} }

View File

@ -3,10 +3,16 @@ package com.alttd.ctf.commands.subcommands;
import com.alttd.ctf.commands.SubCommand; import com.alttd.ctf.commands.SubCommand;
import com.alttd.ctf.config.Messages; import com.alttd.ctf.config.Messages;
import com.alttd.ctf.game.GameManager; import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.team.Team;
import lombok.AllArgsConstructor; 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.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List; import java.util.List;
import java.util.Optional;
@AllArgsConstructor @AllArgsConstructor
public class SkipPhase extends SubCommand { public class SkipPhase extends SubCommand {

View File

@ -4,6 +4,7 @@ import com.alttd.ctf.Main;
import com.alttd.ctf.game.GamePhase; import com.alttd.ctf.game.GamePhase;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.time.Duration; import java.time.Duration;

View File

@ -195,7 +195,7 @@ public class Flag implements Runnable {
}); });
} }
private final LinkedList<Location> particleTrail = new LinkedList<>(); LinkedList<Location> particleTrail = new LinkedList<>();
private void spawnTrail() { private void spawnTrail() {
TeamColor color = winningTeam.getColor(); TeamColor color = winningTeam.getColor();
@ -324,13 +324,12 @@ public class Flag implements Runnable {
} }
Team winningTeam = teamLongEntry.getKey(); Team winningTeam = teamLongEntry.getKey();
teamFlagPointCount.putIfAbsent(winningTeam.getId(), 0); teamCounts.forEach((team, count) -> {
teamFlagPointCount.entrySet().forEach(entry -> { teamFlagPointCount.merge(team.getId(), team.equals(winningTeam) ? 1 : -1, (oldValue, delta) -> {
if (entry.getKey().equals(winningTeam.getId())) { int updatedValue = oldValue + delta;
entry.setValue(entry.getValue() + 1); log.debug("Set count to {} for team {}", updatedValue, team.getId());
} else { return Math.max(updatedValue, 0);
entry.setValue(Math.max(0, entry.getValue() - 1)); });
}
}); });
nearbyPlayers.forEach(teamPlayer -> teamPlayer.increaseStat(Stat.TIME_SPEND_CAPTURING_FLAG)); nearbyPlayers.forEach(teamPlayer -> teamPlayer.increaseStat(Stat.TIME_SPEND_CAPTURING_FLAG));
return true; return true;

View File

@ -9,6 +9,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.util.Optional; import java.util.Optional;

View File

@ -15,6 +15,7 @@ import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@Slf4j @Slf4j
@ -75,6 +76,7 @@ public class RunningGame implements Runnable {
private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) { private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) {
//Remaining time for this phase //Remaining time for this phase
Duration duration = phaseDurations.get(currentPhase).minus(Duration.between(phaseStartTime, Instant.now())); 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 ((duration.toMinutes() > 1 && (duration.toMinutes() % 15 == 0 || duration.toMinutes() <= 5)) && duration.toSecondsPart() < 2) {
if (lastMinuteBroadcast == duration.toMinutes()) { if (lastMinuteBroadcast == duration.toMinutes()) {
return; return;

View File

@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Optional; import java.util.Optional;
@Slf4j @Slf4j

View File

@ -71,17 +71,18 @@ public class EndedPhase implements GamePhaseExecutor {
return messages; return messages;
} else if (topTeams.size() > 1) { // Draw scenario, multiple teams have the same top score } 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>")); messages.add(miniMessage.deserialize("<yellow>It's a draw! Top teams:</yellow>"));
topTeams.forEach(team -> messages.add( topTeams.forEach(team -> {
miniMessage.deserialize("<team> had <score> captures.", messages.add(miniMessage.deserialize("<team> had <score> captures.",
Placeholder.component("team", team.getName()), Placeholder.component("team", team.getName()),
Placeholder.parsed("score", String.valueOf(highestScore))))); Placeholder.parsed("score", String.valueOf(highestScore))));
});
addOtherTeamsScore(wins, highestScore, messages); addOtherTeamsScore(wins, highestScore, messages);
return messages; return messages;
} else { // Single winner } else { // Single winner
Team winner = topTeams.getFirst(); Team winner = topTeams.getFirst();
messages.add(miniMessage.deserialize("<green><team> has won with <score> captures!</green>", messages.add(miniMessage.deserialize("<green><team> has won with <score> captures!</green>",
Placeholder.component("team", winner.getName()), Placeholder.component("team", winner.getName()),
Placeholder.parsed("score", String.valueOf(highestScore)))); Placeholder.parsed("score", String.valueOf(highestScore))));
if (wins.size() <= 1) { if (wins.size() <= 1) {
return messages; return messages;
} }
@ -96,8 +97,8 @@ public class EndedPhase implements GamePhaseExecutor {
wins.entrySet().stream() wins.entrySet().stream()
.filter(entry -> entry.getValue() < winningScore) .filter(entry -> entry.getValue() < winningScore)
.forEach(entry -> messages.add(miniMessage.deserialize("<yellow><team> had <score> captures.</yellow>", .forEach(entry -> messages.add(miniMessage.deserialize("<yellow><team> had <score> captures.</yellow>",
Placeholder.component("team", entry.getKey().getName()), Placeholder.component("team", entry.getKey().getName()),
Placeholder.parsed("score", String.valueOf(entry.getValue()))))); Placeholder.parsed("score", String.valueOf(entry.getValue())))));
} }
@Override @Override

View File

@ -36,13 +36,14 @@ public class GatheringPhase implements GamePhaseExecutor {
log.error("Unable to update world border due to missing Flag"); log.error("Unable to update world border due to missing Flag");
return; return;
} }
gameManager.getTeams() gameManager.getTeams().forEach(team -> {
.forEach(team -> team.getPlayers().forEach(teamPlayer -> { team.getPlayers().forEach(teamPlayer -> {
Player player = Bukkit.getPlayer(teamPlayer.getUuid()); Player player = Bukkit.getPlayer(teamPlayer.getUuid());
if (player == null || !player.isOnline()) { if (player == null || !player.isOnline()) {
return; return;
} }
teamPlayer.resetWorldBorder(player, worldBorderApi, nextPhase, flag.getFlagLocation()); teamPlayer.resetWorldBorder(player, worldBorderApi, nextPhase, flag.getFlagLocation());
})); });
});
} }
} }

View File

@ -25,6 +25,8 @@ import java.util.List;
@Slf4j @Slf4j
public abstract class GameClass { 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 static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final List<Material> armor; private final List<Material> armor;

View File

@ -12,7 +12,9 @@ public class GameClassRetrieval {
public static HashMap<Integer, List<GameClass>> getGameClassesForAllTeams(GameManager gameManager) { public static HashMap<Integer, List<GameClass>> getGameClassesForAllTeams(GameManager gameManager) {
final HashMap<Integer, List<GameClass>> gameClasses = new HashMap<>(); 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; return gameClasses;
} }

View File

@ -2,6 +2,7 @@ package com.alttd.ctf.game_class.creation;
import com.alttd.ctf.game_class.GameClass; import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.game_class.implementations.Engineer; import com.alttd.ctf.game_class.implementations.Engineer;
import com.alttd.ctf.game_class.implementations.Fighter;
import com.alttd.ctf.team.TeamColor; import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;

View File

@ -1,6 +1,7 @@
package com.alttd.ctf.game_class.creation; package com.alttd.ctf.game_class.creation;
import com.alttd.ctf.game_class.GameClass; 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.game_class.implementations.Mage;
import com.alttd.ctf.team.TeamColor; import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -9,6 +10,8 @@ import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; 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.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.Unmodifiable;

View File

@ -1,6 +1,7 @@
package com.alttd.ctf.game_class.creation; package com.alttd.ctf.game_class.creation;
import com.alttd.ctf.game_class.GameClass; 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.game_class.implementations.Tank;
import com.alttd.ctf.team.TeamColor; import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -21,7 +22,7 @@ public class TankCreator {
private static final MiniMessage miniMessage = MiniMessage.miniMessage(); private static final MiniMessage miniMessage = MiniMessage.miniMessage();
@Contract("_ -> new") @Contract("_ -> new")
public static @NotNull GameClass createTank(@NotNull TeamColor teamColor) { public static @NotNull GameClass createTank(@NotNull TeamColor teamColor) {//TODO add ability to become temp invulnerable (with some particle effects mayb?)
return new Tank(getArmor(), getTools(teamColor), getDisplayItem(teamColor), return new Tank(getArmor(), getTools(teamColor), getDisplayItem(teamColor),
30, 7, 4); 30, 7, 4);
} }

View File

@ -14,6 +14,7 @@ import org.jetbrains.annotations.Unmodifiable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.IntStream;
@Slf4j @Slf4j
public class TrapperCreator { public class TrapperCreator {

View File

@ -1,9 +1,11 @@
package com.alttd.ctf.game_class.implementations; package com.alttd.ctf.game_class.implementations;
import com.alttd.ctf.game_class.GameClass; import com.alttd.ctf.game_class.GameClass;
import com.alttd.ctf.team.TeamColor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;

View File

@ -2,6 +2,8 @@ package com.alttd.ctf.gui;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.Merchant;
import org.bukkit.inventory.MerchantInventory;
import java.util.HashMap; import java.util.HashMap;
import java.util.UUID; import java.util.UUID;

View File

@ -56,7 +56,9 @@ public class DiscordTeam {
} }
Member nullableMember = guild.getMemberById(player.getDiscordID()); Member nullableMember = guild.getMemberById(player.getDiscordID());
if (nullableMember == null) { if (nullableMember == null) {
guild.retrieveMemberById(player.getDiscordID()).queue(member -> consumer.apply(role, member)); guild.retrieveMemberById(player.getDiscordID()).queue(member -> {
consumer.apply(role, member);
});
} else { } else {
consumer.apply(role, nullableMember); consumer.apply(role, nullableMember);
} }
@ -81,7 +83,9 @@ public class DiscordTeam {
gameManager.getTeams().forEach(otherTeam -> gameManager.getTeams().forEach(otherTeam ->
member.getRoles().stream() member.getRoles().stream()
.filter(otherRole -> otherRole.getIdLong() == otherTeam.getDiscordRole()) .filter(otherRole -> otherRole.getIdLong() == otherTeam.getDiscordRole())
.forEach(otherRole -> member.getGuild().removeRoleFromMember(member, otherRole).queue())); .forEach(otherRole -> {
member.getGuild().removeRoleFromMember(member, otherRole).queue();
}));
member.getGuild().addRoleToMember(member, role).queue(ignored -> kickFromVoiceIfNeeded(member)); member.getGuild().addRoleToMember(member, role).queue(ignored -> kickFromVoiceIfNeeded(member));
}); });
} }

View File

@ -2,6 +2,8 @@ package com.alttd.ctf.team;
import com.alttd.ctf.game.GameManager; import com.alttd.ctf.game.GameManager;
import com.alttd.ctf.game.GamePhase; 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.format.*;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
@ -42,17 +44,17 @@ public class TeamScoreboard {
} }
protected void setScore(int newScore) { protected void setScore(int newScore) {
Objective objective = getOrCreateObjective(); Objective objective = getOrCreateObjective("teamScores", "<gold>CTF score</gold>");
Score score = objective.getScore(team.getLegacyTeamColor() + Score score = objective.getScore(team.getLegacyTeamColor() +
PlainTextComponentSerializer.plainText().serialize(team.getName())); PlainTextComponentSerializer.plainText().serialize(team.getName()));
score.setScore(newScore); score.setScore(newScore);
} }
private static Objective getOrCreateObjective() { private static Objective getOrCreateObjective(String internalName, String displayName) {
Objective objective = scoreboard.getObjective("teamScores"); Objective objective = scoreboard.getObjective(internalName);
if (objective == null) { if (objective == null) {
objective = scoreboard.registerNewObjective("teamScores", Criteria.DUMMY, objective = scoreboard.registerNewObjective(internalName, Criteria.DUMMY,
MiniMessage.miniMessage().deserialize("<gold>CTF score</gold>")); MiniMessage.miniMessage().deserialize(displayName));
objective.setDisplaySlot(DisplaySlot.SIDEBAR); objective.setDisplaySlot(DisplaySlot.SIDEBAR);
} }
return objective; return objective;
@ -62,11 +64,11 @@ public class TeamScoreboard {
private static PhaseScore phaseScore = null; private static PhaseScore phaseScore = null;
private static void updateTime(GamePhase gamePhase, Duration duration) { private static void updateTime(GamePhase gamePhase, Duration duration) {
if (phaseScore == null) { if (phaseScore == null) {
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective() phaseScore = new PhaseScore(gamePhase, getOrCreateObjective("teamScores", "<gold>CTF score</gold>")
.getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName()))); .getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName())));
} else if (phaseScore.gamePhase() != gamePhase) { } else if (phaseScore.gamePhase() != gamePhase) {
phaseScore.score.resetScore(); phaseScore.score.resetScore();
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective() phaseScore = new PhaseScore(gamePhase, getOrCreateObjective("teamScores", "<gold>CTF score</gold>")
.getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName()))); .getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName())));
} }
phaseScore.score.setScore(duration.toMinutesPart() == 0 ? duration.toSecondsPart() : duration.toMinutesPart()); phaseScore.score.setScore(duration.toMinutesPart() == 0 ? duration.toSecondsPart() : duration.toMinutesPart());

View File

@ -1,3 +1,3 @@
#Sat Mar 01 01:12:24 CET 2025 #Sat Mar 01 00:39:55 CET 2025
buildNumber=95 buildNumber=91
version=0.1 version=0.1