diff --git a/core/src/main/java/de/drolpi/gamecore/api/feature/def/AbstractCounterProgressFeature.java b/core/src/main/java/de/drolpi/gamecore/api/feature/def/AbstractCounterProgressFeature.java index 291ebe1..60a9b68 100644 --- a/core/src/main/java/de/drolpi/gamecore/api/feature/def/AbstractCounterProgressFeature.java +++ b/core/src/main/java/de/drolpi/gamecore/api/feature/def/AbstractCounterProgressFeature.java @@ -2,23 +2,17 @@ import com.google.inject.Inject; import de.drolpi.gamecore.api.counter.Counter; -import de.drolpi.gamecore.api.counter.HandlerType; import de.drolpi.gamecore.api.player.GamePlayer; import de.drolpi.gamecore.api.event.GameJoinEvent; -import de.drolpi.gamecore.api.feature.AbstractFeature; import de.drolpi.gamecore.api.game.Game; import de.drolpi.gamecore.api.phase.Phase; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; -import java.util.function.Consumer; - public abstract class AbstractCounterProgressFeature extends AbstractCounterHandlerFeature { private final Game game; - private boolean countUp; - @Inject public AbstractCounterProgressFeature(Game game, Phase phase) { super(phase); @@ -28,7 +22,6 @@ public AbstractCounterProgressFeature(Game game, Phase phase) { @Override public void enable() { super.enable(); - this.countUp = this.counterFeature.stopCount() > this.counterFeature.startCount(); } @EventHandler @@ -39,7 +32,7 @@ public void handle(GameJoinEvent event) { return; } - this.setStart(player, counter); + this.reset(player, counter); } @Override @@ -57,7 +50,7 @@ protected void tick(Counter counter) { @Override protected void cancel(Counter counter) { for (final GamePlayer player : this.game.allPlayers()) { - this.setStart(player.player(), counter); + this.reset(player.player(), counter); } } @@ -67,16 +60,20 @@ protected void finish(Counter counter) { } protected float progress(Counter counter) { - return counter.currentCount() / (this.startCount(counter) + 0.0F); + return (float) (counter.currentCount() - this.lowerBound(counter)) / (this.upperBound(counter) - this.lowerBound(counter)); + } + + protected long upperBound(Counter counter) { + return Math.max(counter.startCount(), counter.stopCount()); } - protected long startCount(Counter counter) { - return this.countUp ? counter.stopCount() : counter.startCount(); + protected long lowerBound(Counter counter) { + return Math.min(counter.startCount(), counter.stopCount()); } - protected void setStart(Player player, Counter counter) { - this.set(player, (int) this.startCount(counter), this.countUp ? 0 : 1); + protected void reset(Player player, Counter counter) { + this.set(player, counter.startCount(), counter.startCount() > counter.stopCount() ? 1F : 0F); } - protected abstract void set(Player player, int count, float progress); + protected abstract void set(Player player, long count, float progress); } diff --git a/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarCounterFeature.java b/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarCounterFeature.java index af491d7..b2f4912 100644 --- a/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarCounterFeature.java +++ b/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarCounterFeature.java @@ -1,55 +1,77 @@ package de.drolpi.gamecore.api.feature.def; +import com.google.gson.annotations.Expose; import com.google.inject.Inject; import de.drolpi.gamecore.api.counter.Counter; import de.drolpi.gamecore.api.game.Game; import de.drolpi.gamecore.api.phase.Phase; -import org.bukkit.boss.BossBar; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.entity.Player; public class BossBarCounterFeature extends AbstractCounterProgressFeature { private final BossBarFeature bossBarFeature; - private BossBar bossBar; + @Expose + private final String replaceBossBarId = "counter"; + private final Component component; + @Expose + private BossBar.Color color = BossBar.Color.RED; + @Expose + private BossBar.Overlay overlay = BossBar.Overlay.PROGRESS; @Inject public BossBarCounterFeature(Game game, Phase phase) { super(game, phase); this.bossBarFeature = phase.feature(BossBarFeature.class); + this.component = Component.translatable(phase.key() + "counter_bossbar"); } @Override public void enable() { super.enable(); - this.bossBar = this.bossBarFeature.bossBar(); } @Override - public void disable() { - super.disable(); - this.bossBar = null; + protected void start(Counter counter) { + super.start(counter); + if (!this.bossBarFeature.isRegistered(replaceBossBarId)) { + this.bossBarFeature.register(this.replaceBossBarId, this.color, this.overlay); + } + this.bossBarFeature.setColor(this.replaceBossBarId, this.color); + this.bossBarFeature.setOverlay(this.replaceBossBarId, this.overlay); } @Override - protected void start(Counter counter) { - this.bossBar.setVisible(true); + protected void cancel(Counter counter) { + this.resetName(); } @Override - protected void cancel(Counter counter) { - super.cancel(counter); - this.bossBar.setTitle(this.bossBarFeature.message()); - if (!this.bossBarFeature.message().isBlank()) { - return; - } - this.bossBar.setVisible(false); + protected void finish(Counter counter) { + this.resetName(); + } + + private void resetName() { + this.bossBarFeature.resetName(this.replaceBossBarId); + } + + @Override + protected void tick(Counter counter) { + this.set(null, counter.currentCount(), super.progress(counter)); } @Override - protected void set(Player player, int count, float progress) { - //TODO: Lang - this.bossBar.setTitle("" + count); - this.bossBar.setProgress(progress); + protected void set(Player player, long count, float progress) { + if (!this.bossBarFeature.isRegistered(replaceBossBarId)) { + this.bossBarFeature.register(this.replaceBossBarId, this.color, this.overlay); + this.bossBarFeature.setColor(this.replaceBossBarId, this.color); + this.bossBarFeature.setOverlay(this.replaceBossBarId, this.overlay); + } + this.bossBarFeature.setName(this.replaceBossBarId, component); + this.bossBarFeature.setResolvers(this.replaceBossBarId, Placeholder.component("count", Component.text(count))); + this.bossBarFeature.setProgress(this.replaceBossBarId, progress); } } diff --git a/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarFeature.java b/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarFeature.java index ca21c0c..7f95059 100644 --- a/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarFeature.java +++ b/core/src/main/java/de/drolpi/gamecore/api/feature/def/BossBarFeature.java @@ -2,90 +2,192 @@ import com.google.gson.annotations.Expose; import com.google.inject.Inject; +import de.drolpi.gamecore.api.phase.Phase; import de.drolpi.gamecore.api.player.GamePlayer; -import de.drolpi.gamecore.GamePlugin; import de.drolpi.gamecore.api.event.GameJoinEvent; import de.drolpi.gamecore.api.event.GamePostLeaveEvent; import de.drolpi.gamecore.api.feature.AbstractFeature; import de.drolpi.gamecore.api.game.Game; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.boss.BossBar; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import org.bukkit.event.EventHandler; +import java.util.*; + public class BossBarFeature extends AbstractFeature { - private final GamePlugin plugin; private final Game game; - //TODO: Lang - @Expose - private String message = ""; - @Expose - private BarColor color = BarColor.BLUE; @Expose - private BarStyle style = BarStyle.SEGMENTED_20; + private final List bossBarInfos; + + private final Map bossBars; + + private final Phase phase; - private BossBar bossBar; @Inject - public BossBarFeature(GamePlugin plugin, Game game) { - this.plugin = plugin; + public BossBarFeature(Game game, Phase phase) { this.game = game; + this.bossBars = new HashMap<>(); + this.bossBarInfos = new ArrayList<>(); + this.phase = phase; } @Override public void enable() { - this.bossBar = this.plugin.getServer().createBossBar(this.message, this.color, this.style); - if (this.message.isBlank()) { - this.bossBar.setVisible(false); - } - - for (GamePlayer gamePlayer : this.game.players()) { - this.bossBar.addPlayer(gamePlayer.player()); + for (BossBarInfo info : this.bossBarInfos) { + this.showForAll(info.id); } } @Override public void disable() { - this.bossBar.removeAll(); + for (BossBarInfo info : this.bossBarInfos) { + this.hideForAll(info.id); + } + } + + public void register(String id, BossBar.Color color, BossBar.Overlay overlay) { + this.bossBarInfos.add(new BossBarInfo(id, color, overlay)); + this.generateContainer(id); + this.showForAll(id); } @EventHandler public void handle(GameJoinEvent event) { - this.bossBar.addPlayer(event.gamePlayer().player()); + for (BossBarInfo info : this.bossBarInfos) { + BossBarContainer container = this.getContainer(info.id); + if (container.hidden) + continue; + event.gamePlayer().showBossBar(info.id, container.bossBar, container.resolvers); + } } @EventHandler public void handle(GamePostLeaveEvent event) { - this.bossBar.removePlayer(event.gamePlayer().player()); + + } + + private void showForAll(String id) { + BossBarContainer container = this.getContainer(id); + for (GamePlayer gamePlayer : this.game.players()) { + gamePlayer.showBossBar(id, container.bossBar); + } + } + + private void hideForAll(String id) { + BossBarContainer container = this.getContainer(id); + for (GamePlayer gamePlayer : this.game.players()) { + gamePlayer.hideBossBar(id, container.bossBar); + } + } + + public boolean hidden(String id) { + return this.getContainer(id).hidden; + } + + public void setHidden(String id, boolean hidden) { + this.getContainer(id).hidden = hidden; + if (hidden) { + hideForAll(id); + return; + } + showForAll(id); + } + + public boolean isRegistered(String id) { + return this.getInfo(id) != null; + } + + public BossBar.Color color(String id) { + return this.getInfo(id).color; + } + + public BossBar.Overlay overlay(String id) { + return this.getInfo(id).overlay; + } + + public float progress(String id) { + return this.getContainer(id).bossBar.progress(); + } + + public void setProgress(String id, float progress) { + this.getContainer(id).bossBar.progress(progress); } - public BossBar bossBar() { - return this.bossBar; + public void setColor(String id, BossBar.Color color) { + this.getInfo(id).color = color; + this.getContainer(id).bossBar.color(color); } - public String message() { - return this.message; + public void setOverlay(String id, BossBar.Overlay overlay) { + this.getInfo(id).overlay = overlay; + this.getContainer(id).bossBar.overlay(overlay); } - public BarColor color() { - return this.color; + public void setName(String id, Component name) { + this.getContainer(id).bossBar.name(name); } - public BarStyle style() { - return this.style; + public void setResolvers(String id, TagResolver... resolvers) { + this.getContainer(id).resolvers = resolvers; } - public void setMessage(String message) { - this.message = message; + public void resetName(String id) { + this.getContainer(id).bossBar.name(BossBarContainer.name(this.phase.key(), id)); } - public void setColor(BarColor color) { - this.color = color; + public BossBarInfo getInfo(String id) { + Optional bossBarInfo = this.bossBarInfos.stream().filter((info) -> info.id.equals(id)).findFirst(); + return bossBarInfo.orElse(null); } - public void setStyle(BarStyle style) { - this.style = style; + private BossBarContainer getContainer(String id) { + BossBarContainer container = this.bossBars.get(id); + if (container != null) return container; + return this.generateContainer(id); + + } + + private BossBarContainer generateContainer(String id) { + System.out.println("Generating container"); + BossBarInfo info = this.getInfo(id); + System.out.println("for info: "+info); + BossBarContainer container = new BossBarContainer(info, this.phase.key()); + this.bossBars.put(id, container); + return container; + } + + private static class BossBarInfo { + + @Expose + private final String id; + @Expose + private BossBar.Color color; + @Expose + private BossBar.Overlay overlay; + + private BossBarInfo(String id, BossBar.Color color, BossBar.Overlay overlay) { + this.id = id; + this.color = color; + this.overlay = overlay; + } + } + + private static class BossBarContainer { + + private final BossBar bossBar; + private TagResolver[] resolvers; + private boolean hidden = false; + + private BossBarContainer(BossBarInfo info, String phaseId) { + this.bossBar = BossBar.bossBar(BossBarContainer.name(phaseId, info.id), 1.0F, info.color, info.overlay); + } + + private static Component name(String phaseId, String bossBarId) { + return Component.translatable(phaseId + "bossbar." + bossBarId); + } } } diff --git a/core/src/main/java/de/drolpi/gamecore/api/feature/def/LevelCounterFeature.java b/core/src/main/java/de/drolpi/gamecore/api/feature/def/LevelCounterFeature.java index 19e89f1..06fdbe2 100644 --- a/core/src/main/java/de/drolpi/gamecore/api/feature/def/LevelCounterFeature.java +++ b/core/src/main/java/de/drolpi/gamecore/api/feature/def/LevelCounterFeature.java @@ -18,8 +18,8 @@ public LevelCounterFeature(Game game, Phase phase) { } @Override - protected void set(Player player, int count, float progress) { - player.setLevel(count); + protected void set(Player player, long count, float progress) { + player.setLevel((int) count); if (!this.levelProgress) return; diff --git a/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayer.java b/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayer.java index a603fdb..0b7d9bc 100644 --- a/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayer.java +++ b/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayer.java @@ -1,5 +1,6 @@ package de.drolpi.gamecore.api.player; +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; @@ -18,5 +19,9 @@ public interface GamePlayer { void showTitle(Title title, TagResolver... resolvers); + void showBossBar(String bossBarId, BossBar headBossBar, TagResolver... resolvers); + + void hideBossBar(String bossBarId, BossBar headBossBar); + void playSound(Sound sound); } diff --git a/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayerImpl.java b/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayerImpl.java index 8a68ff6..f677bcc 100644 --- a/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayerImpl.java +++ b/core/src/main/java/de/drolpi/gamecore/api/player/GamePlayerImpl.java @@ -3,16 +3,15 @@ import de.drolpi.gamecore.api.game.AbstractGame; import de.drolpi.gamecore.api.game.GameControllerImpl; import de.drolpi.gamecore.components.localization.adventure.MiniMessageComponentRenderer; +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.kyori.adventure.text.renderer.TranslatableComponentRenderer; import net.kyori.adventure.title.Title; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; -import java.util.Locale; -import java.util.Optional; -import java.util.Set; +import java.util.*; final class GamePlayerImpl extends PreGamePlayerImpl implements GamePlayer { @@ -20,16 +19,20 @@ final class GamePlayerImpl extends PreGamePlayerImpl implements GamePlayer { private final Locale locale = Locale.GERMAN; private final GameControllerImpl gameController; + private final Map shownBossBars; + GamePlayerImpl(Player player, GameControllerImpl gameController) { super(player.getUniqueId()); this.player = player; this.gameController = gameController; + this.shownBossBars = new HashMap<>(); } GamePlayerImpl(PreGamePlayerImpl gamePlayer, Player player, GameControllerImpl gameController) { super(gamePlayer.uniqueId); this.player = player; this.gameController = gameController; + this.shownBossBars = new HashMap<>(); } @Override @@ -64,8 +67,58 @@ public void showTitle(Title title, TagResolver... resolvers) { this.player.showTitle(result); } + @Override + public void showBossBar(String bossBarId, BossBar headBossBar, TagResolver... resolvers) { + Set game = this.gameController.abstractGames(this, true); + Optional optional = game.stream().findFirst(); + if (optional.isEmpty()) { + throw new RuntimeException(); + } + + MiniMessageComponentRenderer renderer = optional.get().renderer(); + Component name = renderer.render(headBossBar.name(), this.locale, resolvers); + BossBar result = BossBar.bossBar(name, headBossBar.progress(), headBossBar.color(), headBossBar.overlay()); + BossBarCopyListener copyListener = new BossBarCopyListener(result, renderer, locale, resolvers); + headBossBar.addListener(copyListener); + this.shownBossBars.put(bossBarId, copyListener); + this.player.showBossBar(result); + } + + @Override + public void hideBossBar(String bossBarId, BossBar headBossBar) { + BossBarCopyListener listener = this.shownBossBars.get(bossBarId); + if (listener == null) return; + headBossBar.removeListener(listener); + this.shownBossBars.remove(bossBarId); + this.player.hideBossBar(listener.copy()); + } + @Override public void playSound(Sound sound) { this.player.playSound(sound); } + + private record BossBarCopyListener(BossBar copy, MiniMessageComponentRenderer renderer, Locale locale, + TagResolver... resolvers) implements BossBar.Listener { + + @Override + public void bossBarNameChanged(@NotNull BossBar bossBar, @NotNull Component oldName, @NotNull Component newName) { + this.copy.name(this.renderer.render(newName, this.locale, this.resolvers)); + } + + @Override + public void bossBarProgressChanged(@NotNull BossBar bossBar, float oldProgress, float newProgress) { + this.copy.progress(newProgress); + } + + @Override + public void bossBarColorChanged(@NotNull BossBar bossBar, BossBar.@NotNull Color oldColor, BossBar.@NotNull Color newColor) { + this.copy.color(newColor); + } + + @Override + public void bossBarOverlayChanged(@NotNull BossBar bossBar, BossBar.@NotNull Overlay oldOverlay, BossBar.@NotNull Overlay newOverlay) { + this.copy.overlay(newOverlay); + } + } } diff --git a/core/src/main/java/de/drolpi/gamecore/api/player/PreGamePlayerImpl.java b/core/src/main/java/de/drolpi/gamecore/api/player/PreGamePlayerImpl.java index ff9abb7..e1c8cf0 100644 --- a/core/src/main/java/de/drolpi/gamecore/api/player/PreGamePlayerImpl.java +++ b/core/src/main/java/de/drolpi/gamecore/api/player/PreGamePlayerImpl.java @@ -1,5 +1,6 @@ package de.drolpi.gamecore.api.player; +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; @@ -36,6 +37,16 @@ public void showTitle(Title title, TagResolver... resolvers) { throw new RuntimeException(); } + @Override + public void showBossBar(String bossBarId, BossBar headBossBar, TagResolver... resolvers) { + throw new RuntimeException(); + } + + @Override + public void hideBossBar(String bossBarId, BossBar headBossBar) { + throw new RuntimeException(); + } + @Override public void playSound(Sound sound) { throw new RuntimeException(); diff --git a/game-skywars/src/main/java/de/drolpi/skywars/SkyWarsGame.java b/game-skywars/src/main/java/de/drolpi/skywars/SkyWarsGame.java index 9939ef3..0f8432d 100644 --- a/game-skywars/src/main/java/de/drolpi/skywars/SkyWarsGame.java +++ b/game-skywars/src/main/java/de/drolpi/skywars/SkyWarsGame.java @@ -21,7 +21,7 @@ import de.drolpi.gamecore.api.phase.def.StartingPhase; import de.drolpi.gamecore.components.team.config.Team; import de.drolpi.gamecore.components.team.config.TeamColor; -import org.bukkit.boss.BarColor; +import net.kyori.adventure.bossbar.BossBar; @GameInfo(name = "SkyWarsGame", description = "The SkyWars game", version = "1.0.0-SNAPSHOT", authors = {"dasdrolpi"}) public final class SkyWarsGame extends AbstractGame { @@ -68,9 +68,7 @@ public void create() { protectionPhase.createFeature(SpectatorFeature.class); protectionPhase.createFeature(SpectatorSpawnFeature.class); - //TODO: fix - BossBarFeature bossBarFeature = protectionPhase.createFeature(BossBarFeature.class); - bossBarFeature.setColor(BarColor.GREEN); + protectionPhase.createFeature(BossBarFeature.class); protectionPhase.createFeature(BossBarCounterFeature.class); WinDetectionFeature protectionWinDetectionFeature = protectionPhase.createFeature(WinDetectionFeature.class); diff --git a/game-skywars/src/main/resources/SkyWarsGame_de.json b/game-skywars/src/main/resources/SkyWarsGame_de.json index c9020d5..2a5119a 100644 --- a/game-skywars/src/main/resources/SkyWarsGame_de.json +++ b/game-skywars/src/main/resources/SkyWarsGame_de.json @@ -16,6 +16,8 @@ "starting.counter_finish_subtitle": "", "protection.counter_tick_message": "Die Schutzzeit endet in ", "protection.counter_finish_message": "Die Schutzzeit ist nun vorbei", + "protection.bossbar.counter": "Der Schutzzeit-Countdown läuft noch nicht.", + "protection.counter_bossbar": "Die Schutzzeit dauert noch Sekunden", "ingame.counter_tick_message": "Das Spiel endet in ", "ingame.counter_finish_message": "Das Spiel endet nun", "ingame.death_private": "Du bist gestorben",