diff --git a/README.md b/README.md index cec96494d..1e56fe2ab 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Flexible BedWars plugin formerly coded as a replacement for BedwarsRel. -Supported versions: \[1.8.8 - 1.21\]. Recommended version: \[1.20.6\] +Supported versions: \[1.8.8 - 1.21.1\]. Recommended version: \[1.21.1\] ## Support If you need any help, you can contact us on [Discord](https://discord.gg/4xB54Ts). Please make sure to look into older messages. There are many question already answered. It is really anoying to repeat the same thing over and over. diff --git a/plugin/bukkit/src/main/java/org/screamingsandals/bedwars/bukkit/region/LegacyRegion.java b/plugin/bukkit/src/main/java/org/screamingsandals/bedwars/bukkit/region/LegacyRegion.java index 5fcbe90f0..c31fb7c9d 100644 --- a/plugin/bukkit/src/main/java/org/screamingsandals/bedwars/bukkit/region/LegacyRegion.java +++ b/plugin/bukkit/src/main/java/org/screamingsandals/bedwars/bukkit/region/LegacyRegion.java @@ -156,7 +156,7 @@ public void regen() { var feedState = bBlockFeed.getState(); headState.setType(brokenBlockTypes.get(blockHead)); - feedState.setType(brokenBlockTypes.get(blockFeed)); + feedState.setType(brokenBlockTypes.getOrDefault(blockFeed, brokenBlockTypes.get(blockHead))); headState.setRawData((byte) 0x0); feedState.setRawData((byte) 0x8); feedState.update(true, false); diff --git a/plugin/common/src/main/java/org/screamingsandals/bedwars/config/MainConfig.java b/plugin/common/src/main/java/org/screamingsandals/bedwars/config/MainConfig.java index 8661c429a..7ad4e6b57 100644 --- a/plugin/common/src/main/java/org/screamingsandals/bedwars/config/MainConfig.java +++ b/plugin/common/src/main/java/org/screamingsandals/bedwars/config/MainConfig.java @@ -673,6 +673,11 @@ public void load() { .key("player-destroy-bed").defValue(() -> List.of("/example {player} {score}")) .key("player-kill").defValue(() -> List.of("/example {player} 10")) .key("player-final-kill").defValue(() -> List.of("/example {player} 10")) + .key("player-game-start").defValue(() -> List.of("/example {player} 10")) + .key("player-early-leave").defValue(() -> List.of("/example {player} {death} 10")) + .key("team-win").defValue(() -> List.of("/example {team} 10")) + .key("player-team-win").defValue(() -> List.of("/example {team} {death} 10")) + .key("game-start").defValue(() -> List.of("/example Hello World!")) .back() .section("lore") .key("generate-automatically").defValue(true) diff --git a/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameCycleImpl.java b/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameCycleImpl.java index e07429cfd..11db7631a 100644 --- a/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameCycleImpl.java +++ b/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameCycleImpl.java @@ -22,6 +22,7 @@ import lombok.RequiredArgsConstructor; import org.screamingsandals.bedwars.api.config.GameConfigurationContainer; import org.screamingsandals.bedwars.api.events.TargetInvalidationReason; +import org.screamingsandals.bedwars.api.game.Game; import org.screamingsandals.bedwars.api.game.GameCycle; import org.screamingsandals.bedwars.api.game.GameStatus; import org.screamingsandals.bedwars.boss.BossBarImpl; @@ -221,6 +222,11 @@ private void tickRunningGame(GameChangedStatusEventImpl statusE, GameTickEventIm var endingEvent = new GameEndingEventImpl(game, winner); EventManager.fire(endingEvent); + + game.dispatchRewardCommands("team-win", null, 0, winner, null, null); + for (var member : winner.getTeamMembers()) { + game.dispatchRewardCommands("player-team-win", null, 0, winner, winner.getPlayers().stream().anyMatch(p -> p.getUniqueId().equals(member.getUuid())), member); + } } EventManager.fire(statusE); Debug.info(game.getName() + ": game is ending"); @@ -263,7 +269,7 @@ private void handlePlayerWin(BedWarsPlayer player, TeamImpl winner, String time, } if (MainConfig.getInstance().node("rewards", "enabled").getBoolean()) { - game.dispatchPlayerWinReward(player); + game.dispatchPlayerWinReward(player, winner); } } @@ -422,6 +428,11 @@ private void prepareGame(GameChangedStatusEventImpl statusE, GameTickEventImpl t if (configurationContainer.getOrDefault(GameConfigurationContainer.ENABLE_BELOW_NAME_HEALTH_INDICATOR, false)) { game.startHealthIndicator(); } + + for (var player : players) { + game.dispatchRewardCommands("player-game-start", player, 0, game.getPlayerTeam(player), null, null); + } + game.dispatchRewardCommands("game-start", null, 0); } // show records diff --git a/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameImpl.java b/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameImpl.java index 78078a98b..961b6f5be 100644 --- a/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameImpl.java +++ b/plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameImpl.java @@ -719,6 +719,10 @@ public void internalLeavePlayer(BedWarsPlayer gamePlayer) { } } } + + if (status == GameStatus.RUNNING) { + dispatchRewardCommands("player-early-leave", gamePlayer, 0, team, gamePlayer.isSpectator(), null); + } } if (PlayerStatisticManager.isEnabled()) { @@ -1768,7 +1772,11 @@ public List getItemSpawners() { return List.copyOf(spawners); } - public void dispatchRewardCommands(String type, Player player, int score) { + public void dispatchRewardCommands(@NotNull String type, @Nullable Player player, int score) { + dispatchRewardCommands(type, player, score, null, null, null); + } + + public void dispatchRewardCommands(@NotNull String type, @Nullable Player player, int score, @Nullable TeamImpl team, @Nullable Boolean deathStatus, TeamImpl.@Nullable Member member) { if (!MainConfig.getInstance().node("rewards", "enabled").getBoolean()) { return; } @@ -1777,12 +1785,33 @@ public void dispatchRewardCommands(String type, Player player, int score) { .stream() .map(ConfigurationNode::getString) .filter(Objects::nonNull) - .map(s -> s - .replace("{player}", player.getName()) - .replace("{score}", Integer.toString(score)) - ) + .map(command -> { + if (command.startsWith("/example ")) { + return null; // Skip example commands + } + + if (player != null) { + command = command.replace("{player}", player.getName()); + command = command.replace("{playerUuid}", player.getUniqueId().toString()); + } + if (member != null) { + command = command.replace("{player}", member.getName()); + command = command.replace("{playerUuid}", member.getUuid().toString()); + } + command = command.replace("{game}", name); + command = command.replace("{score}", Integer.toString(score)); + if (team != null) { + command = command.replace("{team}", team.getName()); + } + if (deathStatus != null) { + command = command.replace("{death}", deathStatus ? "true" : "false"); + } + + return command; + }) + .filter(Objects::nonNull) .map(s -> s.startsWith("/") ? s.substring(1) : s) - .forEach(player::tryToDispatchCommand); + .forEach(Server.getConsoleSender()::tryToDispatchCommand); } @Override @@ -2009,19 +2038,19 @@ public void showPlayerCountdown(int countdown) { } } - protected void dispatchPlayerWinReward(Player player) { + protected void dispatchPlayerWinReward(@NotNull Player player, @NotNull TeamImpl winningTeam) { if (PlayerStatisticManager.isEnabled()) { var statistic = PlayerStatisticManager.getInstance().getStatistic(player); - dispatchRewardCommands("player-win-run-immediately", player, statistic.getScore()); + dispatchRewardCommands("player-win-run-immediately", player, statistic.getScore(), winningTeam, null, null); } else { - dispatchRewardCommands("player-win-run-immediately", player, 0); + dispatchRewardCommands("player-win-run-immediately", player, 0, winningTeam, null, null); } Tasker.runDelayed(DefaultThreads.GLOBAL_THREAD, () -> { if (PlayerStatisticManager.isEnabled()) { var statistic = PlayerStatisticManager.getInstance().getStatistic(player); - dispatchRewardCommands("player-win", player, statistic.getScore()); + dispatchRewardCommands("player-win", player, statistic.getScore(), winningTeam, null, null); } else { - dispatchRewardCommands("player-win", player, 0); + dispatchRewardCommands("player-win", player, 0, winningTeam, null, null); } }, (2 + postGameWaiting) * 20L, TaskerTime.TICKS); } @@ -2135,6 +2164,7 @@ protected void spawnTeamPlayerOnGameStart(BedWarsPlayer player, TeamImpl team) { ) ); }); + team.getTeamMembers().add(new TeamImpl.Member(player.getUniqueId(), player.getName())); } protected void spawnSpectatorOnGameStart(BedWarsPlayer player) { diff --git a/plugin/common/src/main/java/org/screamingsandals/bedwars/game/TeamImpl.java b/plugin/common/src/main/java/org/screamingsandals/bedwars/game/TeamImpl.java index 7e1c6c3aa..95e51c94d 100644 --- a/plugin/common/src/main/java/org/screamingsandals/bedwars/game/TeamImpl.java +++ b/plugin/common/src/main/java/org/screamingsandals/bedwars/game/TeamImpl.java @@ -19,8 +19,10 @@ package org.screamingsandals.bedwars.game; +import lombok.Data; import lombok.Getter; import lombok.Setter; +import org.jetbrains.annotations.NotNull; import org.screamingsandals.bedwars.api.Team; import org.screamingsandals.bedwars.api.config.GameConfigurationContainer; import org.screamingsandals.bedwars.api.game.target.Target; @@ -49,6 +51,7 @@ import java.util.List; import java.util.Objects; import java.util.Random; +import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -66,6 +69,7 @@ public class TeamImpl implements Team { private final List chests = new ArrayList<>(); private boolean started; private final List players = new ArrayList<>(); + private final List teamMembers = new ArrayList<>(); private Hologram hologram; private Hologram protectHologram; private final Random randomSpawn = new Random(); @@ -175,6 +179,7 @@ public void destroy() { chests.clear(); players.clear(); + teamMembers.clear(); started = false; forced = false; } @@ -235,4 +240,10 @@ public boolean isDead() { public Location getRandomSpawn() { return teamSpawns.get(randomSpawn.nextInt(teamSpawns.size())); } + + @Data + public static class Member { + private final @NotNull UUID uuid; + private final @NotNull String name; + } } diff --git a/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/PlayerListener.java b/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/PlayerListener.java index 25c3e73ce..ce909cadd 100644 --- a/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/PlayerListener.java +++ b/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/PlayerListener.java @@ -197,12 +197,24 @@ public void onPlayerDeath(PlayerDeathEvent event) { var gKiller = killer.as(BedWarsPlayer.class); if (gKiller.getGame() == game) { if (!onlyOnBedDestroy || !isBed) { - game.dispatchRewardCommands("player-kill", killer, - game.getConfigurationContainer().getOrDefault(GameConfigurationContainer.STATISTICS_SCORES_KILL, 10)); + game.dispatchRewardCommands( + "player-kill", + killer, + game.getConfigurationContainer().getOrDefault(GameConfigurationContainer.STATISTICS_SCORES_KILL, 10), + game.getPlayerTeam(gKiller), + null, + null + ); } if (!isBed) { - game.dispatchRewardCommands("player-final-kill", killer, - game.getConfigurationContainer().getOrDefault(GameConfigurationContainer.STATISTICS_SCORES_FINAL_KILL, 10)); + game.dispatchRewardCommands( + "player-final-kill", + killer, + game.getConfigurationContainer().getOrDefault(GameConfigurationContainer.STATISTICS_SCORES_FINAL_KILL, 10), + game.getPlayerTeam(gKiller), + null, + null + ); } if (team.isDead()) { SpawnEffects.spawnEffect(game, gVictim, "game-effects.teamkill"); @@ -1325,7 +1337,7 @@ public void onMove(PlayerMoveEvent event) { @OnEvent public void onPlaceLiquid(PlayerBucketEvent event) { - if (event.cancelled() || event.action() != PlayerBucketEvent.Action.EMPTY) { + if (event.cancelled()) { return; } @@ -1333,18 +1345,44 @@ public void onPlaceLiquid(PlayerBucketEvent event) { if (PlayerManagerImpl.getInstance().isPlayerInGame(player)) { var gPlayer = player.as(BedWarsPlayer.class); var game = gPlayer.getGame(); - var loc = event.blockClicked().location(); - - loc.add(event.blockFace().getDirection().normalize()); + var loc = event.blockClicked().location().add(event.blockFace().getDirection().normalize()); var block = loc.getBlock(); if (game.getStatus() == GameStatus.RUNNING) { - if (block.block().isAir() || game.getRegion().isLocationModifiedDuringGame(block.location())) { - game.getRegion().addBuiltDuringGame(block.location()); - Debug.info(player.getName() + " placed liquid"); + if (game.getRegion().isLocationModifiedDuringGame(block.location())) { + return; + } + + if (event.action() == PlayerBucketEvent.Action.EMPTY) { + if (Server.isVersion(1, 13) && event.bucket().is("minecraft:water_bucket") && event.blockClicked().block().getBoolean("waterlogged") != null) { + block = event.blockClicked(); + game.getRegion().putOriginalBlock(block.location(), block.blockSnapshot()); + game.getRegion().addBuiltDuringGame(block.location()); + Debug.info(player.getName() + " placed liquid"); + } else if (block.block().isAir()) { + game.getRegion().addBuiltDuringGame(block.location()); + Debug.info(player.getName() + " placed liquid"); + } else { + event.cancelled(true); + Debug.info(player.getName() + " placed liquid, cancelling"); + } } else { - event.cancelled(true); - Debug.info(player.getName() + " placed liquid, cancelling"); + if ( + BedWarsPlugin.isBreakableBlock(block.block()) + || ( + Server.isVersion(1, 13) + && event.bucket().is("minecraft:water_bucket") + && event.blockClicked().block().getBoolean("waterlogged") != null + && BedWarsPlugin.isBreakableBlock(Block.of("minecraft:water")) // Require breakable water + ) + ) { + game.getRegion().putOriginalBlock(block.location(), block.blockSnapshot()); + game.getRegion().addBuiltDuringGame(block.location()); + Debug.info(player.getName() + " broken liquid"); + } else { + event.cancelled(true); + Debug.info(player.getName() + " broken liquid, cancelling"); + } } } else if (game.getStatus() != GameStatus.DISABLED) { event.cancelled(true); @@ -1428,4 +1466,25 @@ public void onItemMerge(ItemMergeEvent event) { } } } + + @OnEvent + public void onSpectatorTeleported(PlayerTeleportEvent event) { + if (event.cancelled()) { + return; + } + + if (event.cause() != PlayerTeleportEvent.TeleportCause.SPECTATE) { + return; + } + + var game = PlayerManagerImpl.getInstance().getGameOfPlayer(event.player()); + + if (game.isEmpty()) { + return; + } + + if (!ArenaUtils.isInArea(event.newLocation(), game.get().getPos1(), game.get().getPos2())) { + event.cancelled(true); + } + } } diff --git a/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/TargetInvalidatedListener.java b/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/TargetInvalidatedListener.java index c4d942f1b..f0b276c00 100644 --- a/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/TargetInvalidatedListener.java +++ b/plugin/common/src/main/java/org/screamingsandals/bedwars/listener/TargetInvalidatedListener.java @@ -159,7 +159,10 @@ public void onTargetInvalidated(PostTargetInvalidatedEventImpl event) { game.dispatchRewardCommands( "player-destroy-bed", initiator, - game.getConfigurationContainer().getOrDefault(GameConfigurationContainer.STATISTICS_SCORES_BED_DESTROY, 25) + game.getConfigurationContainer().getOrDefault(GameConfigurationContainer.STATISTICS_SCORES_BED_DESTROY, 25), + game.getTeamOfPlayer(initiator), + null, + null ); } }