diff --git a/README.md b/README.md index 2bdda5b..495ad20 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@

SharedStats

Share your health and food level with the players in your group.

+

+ Available on CurseForge + Available on Modrinth +

## Commands @@ -15,6 +19,7 @@ | `/sharedgroup start` | Start the game and stat synchronization | OP, group owner | | `/sharedgroup stop` | Stop an active game without deleting the group | Group owner | | `/sharedgroup players` | List the online players in your group | Group member | +| `/sharedgroup leaderboard` | Show the group's death leaderboard during a game | Group member | | `/sharedgroup version` | Display the plugin version | None | ## What remains to be done diff --git a/src/main/java/fr/korastrip/paperplugin/Utils.java b/src/main/java/fr/korastrip/paperplugin/Utils.java new file mode 100644 index 0000000..7717542 --- /dev/null +++ b/src/main/java/fr/korastrip/paperplugin/Utils.java @@ -0,0 +1,14 @@ +package fr.korastrip.paperplugin; + +import io.papermc.paper.util.Tick; + +import java.time.Duration; + +public class Utils +{ + + public static int toTick(int seconds) { + return Tick.tick().fromDuration(Duration.ofSeconds(seconds)); + } + +} diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/GroupCommand.java b/src/main/java/fr/korastrip/paperplugin/commands/group/GroupCommand.java index 4eec59f..f90d5f2 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/GroupCommand.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/GroupCommand.java @@ -23,8 +23,9 @@ public LiteralCommandNode create() { .then(new Stop(plugin).build()) .then(new Version(plugin).build()) .then(new Remove(plugin).build()) - .then(new Remove(plugin).build()) + .then(new Revoke(plugin).build()) .then(new Players(plugin).build()) + .then(new Stats(plugin).build()) .build(); } diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/GroupSubCommand.java b/src/main/java/fr/korastrip/paperplugin/commands/group/GroupSubCommand.java index f0c85e7..5e01e2d 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/GroupSubCommand.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/GroupSubCommand.java @@ -1,11 +1,17 @@ package fr.korastrip.paperplugin.commands.group; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import fr.korastrip.paperplugin.Config; import fr.korastrip.paperplugin.SharedStats; +import fr.korastrip.paperplugin.enums.ErrorMessage; import io.papermc.paper.command.brigadier.CommandSourceStack; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; public abstract class GroupSubCommand { + public record ContextResult(CommandSender sender, Entity entity) {} protected final SharedStats plugin; protected final String name; protected final String description; @@ -28,6 +34,21 @@ public String getDescription() { return description; } + public ContextResult getContext(CommandContext context) { + CommandSender sender = context.getSource().getSender(); + Entity executor = context.getSource().getExecutor(); + return new ContextResult(sender, executor); + } + + public int generateError(String message, CommandSender player, TagResolver... resolvers) { + player.sendRichMessage("" + message + "", resolvers); + return 0; + } + + public int generateError(ErrorMessage error, CommandSender player) { + return this.generateError(error.getMessage(), player); + } + public String getUsage() { return usage; } diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Create.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Create.java index a893a8e..2171b40 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Create.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Create.java @@ -4,11 +4,10 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; import fr.korastrip.paperplugin.model.SharedGroup; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.UUID; @@ -24,24 +23,22 @@ public LiteralArgumentBuilder build() { return Commands.literal(this.name) .requires(source -> source.getSender().isOp()) .executes(context -> { - CommandSender sender = context.getSource().getSender(); - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); SharedGroup group = this.plugin.getGroup(); - if (!(executor instanceof Player player)) { + if (!(ctx.entity() instanceof Player player)) { return Command.SINGLE_SUCCESS; } if(!group.getPlayersId().isEmpty()) { - sender.sendRichMessage("A group already exists. You cannot create another one."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.GROUP_ALREADY_EXISTS, ctx.sender()); } UUID playerUUID = player.getUniqueId(); group.addPlayer(playerUUID); group.setOwnerUuid(playerUUID); - sender.sendRichMessage("Your group has been created.\nInvite players with /sharedgroup invite [player]."); + ctx.sender().sendRichMessage("Your group has been created.\nInvite players with /sharedgroup invite [player]."); return Command.SINGLE_SUCCESS; }); } diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Help.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Help.java index 36a95d2..e7a0330 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Help.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Help.java @@ -7,8 +7,6 @@ import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.List; @@ -24,10 +22,9 @@ public LiteralArgumentBuilder build() { return Commands.literal("help").executes(context -> { - CommandSender sender = context.getSource().getSender(); - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); - if (!(executor instanceof Player)) { + if (!(ctx.entity() instanceof Player)) { return Command.SINGLE_SUCCESS; } @@ -39,10 +36,11 @@ public LiteralArgumentBuilder build() { new Start(plugin), new Stop(plugin), new Players(plugin), - new Version(plugin) + new Version(plugin), + new Stats(plugin) ); - commands.forEach(command -> sender.sendRichMessage(": ", Placeholder.unparsed("description", command.getDescription()), Placeholder.unparsed("usage", command.getUsage()))); + commands.forEach(command -> ctx.sender().sendRichMessage(": ", Placeholder.unparsed("description", command.getDescription()), Placeholder.unparsed("usage", command.getUsage()))); return Command.SINGLE_SUCCESS; }); diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Invite.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Invite.java index 33a28a9..837587e 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Invite.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Invite.java @@ -5,6 +5,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; import fr.korastrip.paperplugin.model.SharedGroup; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; @@ -12,8 +13,6 @@ import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.NoSuchElementException; @@ -30,27 +29,23 @@ public LiteralArgumentBuilder build() { return Commands.literal("invite") .then(Commands.argument("player", ArgumentTypes.player()) .executes(context -> { - CommandSender sender = context.getSource().getSender(); - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); SharedGroup group = this.plugin.getGroup(); - if (!(executor instanceof Player player)) { + if (!(ctx.entity() instanceof Player player)) { return Command.SINGLE_SUCCESS; } if (group.getPlayersId().isEmpty()) { - sender.sendRichMessage("There is no group. Create one with /sharedgroup create."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.NO_GROUP, ctx.sender()); } if (!player.getUniqueId().equals(group.getOwnerUuid())) { - sender.sendRichMessage("You cannot invite a player because you are not the owner."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.NOT_OWNER, ctx.sender()); } if (group.getIsPlaying()) { - sender.sendRichMessage("You cannot invite a player after the game has started."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.GAME_RUNNING, ctx.sender()); } final PlayerSelectorArgumentResolver resolver = context.getArgument("player", PlayerSelectorArgumentResolver.class); @@ -59,13 +54,11 @@ public LiteralArgumentBuilder build() { try { target = resolver.resolve(context.getSource()).getFirst(); } catch (CommandSyntaxException | NoSuchElementException e) { - sender.sendRichMessage("Player not found."); - return 0; + return this.generateError(ErrorMessage.PLAYER_NOT_FOUND, ctx.sender()); } if (group.getPlayersId().contains(target.getUniqueId())) { - sender.sendRichMessage("This player is already in the group."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.PLAYER_ALREADY_IN_GROUP, ctx.sender()); } group.addPlayer(target.getUniqueId()); @@ -73,7 +66,7 @@ public LiteralArgumentBuilder build() { TagResolver.Single playerName = Placeholder.component("player", target.displayName()); target.sendRichMessage("You have been added to the group. Wait for the owner to start the game."); - sender.sendRichMessage(" has been added to the group.", playerName); + ctx.sender().sendRichMessage(" has been added to the group.", playerName); return Command.SINGLE_SUCCESS; })) diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Players.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Players.java index b638154..5ffdcd8 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Players.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Players.java @@ -4,11 +4,11 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; import fr.korastrip.paperplugin.model.SharedGroup; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; public class Players extends GroupSubCommand { @@ -21,16 +21,15 @@ public Players(SharedStats plugin) { public LiteralArgumentBuilder build() { return Commands.literal("players").executes(context -> { - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); SharedGroup group = this.plugin.getGroup(); - if (!(executor instanceof Player player)) { + if (!(ctx.entity() instanceof Player player)) { return Command.SINGLE_SUCCESS; } if (!group.getPlayersId().contains(player.getUniqueId())) { - player.sendRichMessage("You do not have permission to use this command."); - return 0; + return this.generateError(ErrorMessage.NOT_IN_GROUP, player); } var players = group.getOnlinePlayers(); diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Remove.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Remove.java index 1a12351..5be8682 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Remove.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Remove.java @@ -3,17 +3,15 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import fr.korastrip.paperplugin.Config; import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; import fr.korastrip.paperplugin.model.SharedGroup; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; import io.papermc.paper.command.brigadier.argument.ArgumentTypes; import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.NoSuchElementException; @@ -29,27 +27,23 @@ public LiteralArgumentBuilder build() { return Commands.literal("remove") .then(Commands.argument("player", ArgumentTypes.player()) .executes(context -> { - CommandSender sender = context.getSource().getSender(); - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); SharedGroup group = this.plugin.getGroup(); - if (!(executor instanceof Player player)) { + if (!(ctx.entity() instanceof Player player)) { return Command.SINGLE_SUCCESS; } if (group.getPlayersId().isEmpty()) { - sender.sendRichMessage("There is no group. Create one with /sharedgroup create."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.NO_GROUP, ctx.sender()); } if (!group.getOwnerUuid().equals(player.getUniqueId())) { - sender.sendRichMessage("You do not have permission to use this command."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.NOT_OWNER, ctx.sender()); } if (group.getIsPlaying()) { - sender.sendRichMessage("You cannot remove a player during the game."); - return 0; + return this.generateError(ErrorMessage.GAME_RUNNING, ctx.sender()); } final PlayerSelectorArgumentResolver resolver = context.getArgument("player", PlayerSelectorArgumentResolver.class); @@ -58,22 +52,19 @@ public LiteralArgumentBuilder build() { try { target = resolver.resolve(context.getSource()).getFirst(); } catch (CommandSyntaxException | NoSuchElementException e) { - sender.sendRichMessage("Player not found."); - return 0; + return this.generateError(ErrorMessage.PLAYER_NOT_FOUND, ctx.sender()); } if (target.getUniqueId().equals(player.getUniqueId())) { - sender.sendRichMessage("You cannot remove yourself. Use /" + Config.PREFIX + " revoke instead."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.CANNOT_REMOVE_YOURSELF, ctx.sender()); } if (!group.getPlayersId().contains(target.getUniqueId())) { - sender.sendRichMessage("This player is not in the group."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.PLAYER_NOT_IN_GROUP, ctx.sender()); } group.removePlayer(target.getUniqueId()); - sender.sendRichMessage(" has been removed from your group.", Placeholder.component("player", target.displayName())); + ctx.sender().sendRichMessage(" has been removed from your group.", Placeholder.component("player", target.displayName())); target.sendRichMessage("You have been removed from the group by .", Placeholder.component("player", player.displayName())); return Command.SINGLE_SUCCESS; diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Revoke.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Revoke.java index 3532953..fc3a992 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Revoke.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Revoke.java @@ -4,10 +4,10 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; import fr.korastrip.paperplugin.model.SharedGroup; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; public class Revoke extends GroupSubCommand { @@ -21,16 +21,15 @@ public LiteralArgumentBuilder build() { return Commands.literal("revoke") .executes(context -> { - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); SharedGroup group = this.plugin.getGroup(); - if (!(executor instanceof Player player)) { + if (!(ctx.entity() instanceof Player player)) { return Command.SINGLE_SUCCESS; } if (!player.getUniqueId().equals(group.getOwnerUuid())) { - player.sendRichMessage("You do not have permission to use this command."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.NOT_OWNER, player); } group.getOnlinePlayers().forEach(p -> { diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Start.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Start.java index 1d68891..b37522e 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Start.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Start.java @@ -2,16 +2,13 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import fr.korastrip.paperplugin.Config; import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; import fr.korastrip.paperplugin.model.SharedGroup; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Sound; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.List; @@ -27,30 +24,26 @@ public Start(SharedStats plugin) { public LiteralArgumentBuilder build() { return Commands.literal("start").executes(context -> { - CommandSender sender = context.getSource().getSender(); - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); SharedGroup group = this.plugin.getGroup(); - if (!(executor instanceof Player player)) { + if (!(ctx.entity() instanceof Player player)) { return Command.SINGLE_SUCCESS; } if (!player.getUniqueId().equals(group.getOwnerUuid())) { - sender.sendRichMessage("You do not have permission to use this command."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.NOT_OWNER, ctx.sender()); } if (group.getIsPlaying()) { - sender.sendRichMessage("The game has already started. Stop it with / stop.", Placeholder.unparsed("prefix", Config.PREFIX)); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.GAME_RUNNING, ctx.sender()); } List players = group.getOnlinePlayers(); if (players.size() < 2) { - sender.sendRichMessage("You cannot start a game alone. Invite at least one player."); - return Command.SINGLE_SUCCESS; + return this.generateError(ErrorMessage.NOT_ENOUGH_PLAYERS, ctx.sender()); } group.setHealth(20.0); diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Stats.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Stats.java new file mode 100644 index 0000000..04c0bba --- /dev/null +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Stats.java @@ -0,0 +1,51 @@ +package fr.korastrip.paperplugin.commands.group.sub; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import fr.korastrip.paperplugin.SharedStats; +import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; +import fr.korastrip.paperplugin.model.SharedGroup; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.entity.Player; + +import java.util.Comparator; + +public class Stats extends GroupSubCommand { + + public Stats(SharedStats plugin) { + super(plugin, "leaderboard", "Get the group death leaderboards.", ""); + } + + @Override + public LiteralArgumentBuilder build() { + return Commands.literal("leaderboard").executes(context -> { + + ContextResult ctx = this.getContext(context); + SharedGroup group = this.plugin.getGroup(); + + if (!(ctx.entity() instanceof Player player)) { + return 0; + } + + if(!group.getPlayersId().contains(player.getUniqueId())) { + return this.generateError(ErrorMessage.NOT_IN_GROUP, player); + } + + if(!group.getIsPlaying()) { + return this.generateError(ErrorMessage.NO_GAME_RUNNING, player); + } + + var playerPerScore = group.getOnlinePlayers().stream().sorted(Comparator.comparingInt(group::getPlayerDeaths).reversed()).toList(); + + player.sendRichMessage("Group Leaderboard: \nYour team got death.", Placeholder.unparsed("totaldeath", String.valueOf(group.getDeadCount()))); + playerPerScore.forEach(p -> { + player.sendRichMessage(" got death", Placeholder.component("player", p.displayName()), Placeholder.unparsed("death", String.valueOf(group.getPlayerDeaths(p)))); + }); + + return Command.SINGLE_SUCCESS; + }); + } +} diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Stop.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Stop.java index 1cb5d8d..03729fd 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Stop.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Stop.java @@ -5,12 +5,11 @@ import fr.korastrip.paperplugin.Config; import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.commands.group.GroupSubCommand; +import fr.korastrip.paperplugin.enums.ErrorMessage; import fr.korastrip.paperplugin.model.SharedGroup; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; public class Stop extends GroupSubCommand { @@ -25,26 +24,22 @@ public LiteralArgumentBuilder build() { SharedGroup group = this.plugin.getGroup(); - CommandSender sender = context.getSource().getSender(); - Entity executor = context.getSource().getExecutor(); + ContextResult ctx = this.getContext(context); - if (!(executor instanceof Player player)) { + if (!(ctx.entity() instanceof Player player)) { return Command.SINGLE_SUCCESS; } if(!group.getPlayersId().contains(player.getUniqueId())) { - sender.sendRichMessage("You cannot interact with the group, you are not into"); - return 0; + return this.generateError(ErrorMessage.NOT_IN_GROUP, ctx.sender()); } if(!player.getUniqueId().equals(group.getOwnerUuid())) { - sender.sendRichMessage("Only owners can do this action"); - return 0; + return this.generateError(ErrorMessage.NOT_OWNER, ctx.sender()); } if(!group.getIsPlaying()) { - sender.sendRichMessage("You cannot stop a game that's not already started"); - return 0; + return this.generateError(ErrorMessage.NO_GAME_RUNNING, ctx.sender()); } player.sendRichMessage("You're game has been stopped.\nTo restart: /" + Config.PREFIX + " start"); diff --git a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Version.java b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Version.java index af72ab7..dae9179 100644 --- a/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Version.java +++ b/src/main/java/fr/korastrip/paperplugin/commands/group/sub/Version.java @@ -8,7 +8,6 @@ import io.papermc.paper.command.brigadier.Commands; import io.papermc.paper.plugin.configuration.PluginMeta; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.CommandSender; public class Version extends GroupSubCommand { @@ -19,11 +18,11 @@ public Version(SharedStats plugin) { @Override public LiteralArgumentBuilder build() { return Commands.literal("version").executes(context -> { - CommandSender sender = context.getSource().getSender(); + ContextResult ctx = this.getContext(context); PluginMeta pluginMeta = plugin.getPluginMeta(); - sender.sendRichMessage( + ctx.sender().sendRichMessage( " is running version .", Placeholder.unparsed("version", pluginMeta.getVersion()), Placeholder.unparsed("pluginname", pluginMeta.getName()) diff --git a/src/main/java/fr/korastrip/paperplugin/enums/ErrorMessage.java b/src/main/java/fr/korastrip/paperplugin/enums/ErrorMessage.java new file mode 100644 index 0000000..73036a7 --- /dev/null +++ b/src/main/java/fr/korastrip/paperplugin/enums/ErrorMessage.java @@ -0,0 +1,27 @@ +package fr.korastrip.paperplugin.enums; + +import fr.korastrip.paperplugin.Config; + +public enum ErrorMessage { + NO_GROUP("There is no group. Create one with /" + Config.PREFIX + " create."), + NOT_IN_GROUP("You are not in the group."), + NOT_OWNER("Only the group owner can use this command."), + NO_GAME_RUNNING("No game is running. Start one with /" + Config.PREFIX + " start."), + GAME_RUNNING("A game is running. Stop it with /" + Config.PREFIX + " stop."), + PLAYER_NOT_FOUND("Player not found."), + GROUP_ALREADY_EXISTS("A group already exists. You cannot create another one."), + PLAYER_ALREADY_IN_GROUP("This player is already in the group."), + PLAYER_NOT_IN_GROUP("This player is not in the group."), + CANNOT_REMOVE_YOURSELF("You cannot remove yourself. Use /" + Config.PREFIX + " revoke instead."), + NOT_ENOUGH_PLAYERS("You cannot start a game alone. Invite at least one player."); + + private final String message; + + ErrorMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/fr/korastrip/paperplugin/listener/DamageListener.java b/src/main/java/fr/korastrip/paperplugin/listener/DamageListener.java index f40f1e1..c8539ca 100644 --- a/src/main/java/fr/korastrip/paperplugin/listener/DamageListener.java +++ b/src/main/java/fr/korastrip/paperplugin/listener/DamageListener.java @@ -2,6 +2,7 @@ import fr.korastrip.paperplugin.SharedStats; import fr.korastrip.paperplugin.model.SharedGroup; +import fr.korastrip.paperplugin.services.TotemService; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.title.Title; @@ -37,12 +38,21 @@ public void onDamageReceive(EntityDamageEvent event) { } var finalDamage = event.getFinalDamage(); - event.setCancelled(true); + event.setDamage(0); + var newHealth = group.getHealth() - finalDamage; List players = group.getOnlinePlayers(); if (newHealth <= 0) { + + TotemService totemService = new TotemService(plugin); + + if(totemService.check()) { + totemService.applyEffect(); + return; + } + group.isGroupDying = true; Bukkit.getScheduler().runTask( @@ -59,6 +69,8 @@ public void onDamageReceive(EntityDamageEvent event) { final Component subtitle = Component.text("is dead", NamedTextColor.WHITE); final Title title = Title.title(mainTitle, subtitle); + group.addPlayerDeath(player); + players.forEach(p -> { p.showTitle(title); diff --git a/src/main/java/fr/korastrip/paperplugin/model/SharedGroup.java b/src/main/java/fr/korastrip/paperplugin/model/SharedGroup.java index af719bb..04612fa 100644 --- a/src/main/java/fr/korastrip/paperplugin/model/SharedGroup.java +++ b/src/main/java/fr/korastrip/paperplugin/model/SharedGroup.java @@ -8,46 +8,58 @@ public class SharedGroup { private final Set playersId = new HashSet<>(); + public Set getPlayersId() { return Collections.unmodifiableSet(this.playersId); } + private final HashMap deathLeaderBoard = new HashMap<>(); + private UUID ownerUuid; + public void setOwnerUuid(UUID ownerUuid) { this.ownerUuid = ownerUuid; } + public UUID getOwnerUuid() { return this.ownerUuid; } private boolean isPlaying = false; + public boolean getIsPlaying() { return this.isPlaying; } private double groupHealth = 20.0; + public void setHealth(double health) { this.groupHealth = health; } + public double getHealth() { return this.groupHealth; } - private double groupFood = 20.0; + private final double groupFood = 20.0; private int deadCount = 0; + public int getDeadCount() { return this.deadCount; } private final Set respawnedPlayers = new HashSet<>(); + public void addRespawnedPlayer(UUID playerId) { this.respawnedPlayers.add(playerId); } + public Set getRespawnedPlayers() { return Collections.unmodifiableSet(this.respawnedPlayers); } + public void clearRespawnedPlayers() { this.respawnedPlayers.clear(); } @@ -64,10 +76,11 @@ public void addPlayer(UUID uuid) { public void removePlayer(UUID uuid) { this.playersId.remove(uuid); + this.deathLeaderBoard.remove(uuid); } public void startGame() { - if(this.isPlaying) { + if (this.isPlaying) { throw new IllegalStateException(); } @@ -75,7 +88,7 @@ public void startGame() { } public void incrementsDeadCount() { - if(this.isPlaying) this.deadCount++; + if (this.isPlaying) this.deadCount++; } public void resetGroup() { @@ -89,6 +102,7 @@ public void resetStats() { this.isGroupDying = false; this.isPlaying = false; this.respawnedPlayers.clear(); + this.deathLeaderBoard.clear(); } public List getOnlinePlayers() { @@ -99,9 +113,16 @@ public List getOnlinePlayers() { } public void syncHealth() { - this.getOnlinePlayers().forEach(p -> { - p.setHealth(this.getHealth()); - }); + this.getOnlinePlayers().forEach(p -> p.setHealth(this.getHealth())); + } + + public void addPlayerDeath(Player player) { + UUID playerUUID = player.getUniqueId(); + deathLeaderBoard.merge(playerUUID, 1, Integer::sum); + } + + public int getPlayerDeaths(Player player) { + return deathLeaderBoard.getOrDefault(player.getUniqueId(), 0); } } diff --git a/src/main/java/fr/korastrip/paperplugin/services/TotemService.java b/src/main/java/fr/korastrip/paperplugin/services/TotemService.java new file mode 100644 index 0000000..1bdaf9d --- /dev/null +++ b/src/main/java/fr/korastrip/paperplugin/services/TotemService.java @@ -0,0 +1,90 @@ +package fr.korastrip.paperplugin.services; + +import fr.korastrip.paperplugin.SharedStats; +import fr.korastrip.paperplugin.Utils; +import fr.korastrip.paperplugin.model.SharedGroup; +import org.bukkit.EntityEffect; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.logging.Level; + +public class TotemService { + + private final SharedStats plugin; + + public TotemService(SharedStats plugin) { + this.plugin = plugin; + } + + public boolean check() { + SharedGroup group = this.plugin.getGroup(); + + for (Player player : group.getOnlinePlayers()) { + if (this.removeTotemFromUser(player)) { + return true; + } + } + return false; + } + + public void applyEffect() { + SharedGroup group = this.plugin.getGroup(); + + group.setHealth(1); + group.syncHealth(); + + group.getOnlinePlayers().forEach(p -> { + + //Apply the same effect as vanilla + p.clearActivePotionEffects(); + + p.playSound(p.getLocation(), Sound.ITEM_TOTEM_USE, 1f, 1f); + p.playEffect(EntityEffect.PROTECTED_FROM_DEATH); + p.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, Utils.toTick(45), 1)); + p.addPotionEffect(new PotionEffect(PotionEffectType.FIRE_RESISTANCE, Utils.toTick(40), 0)); + p.addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION, Utils.toTick(5), 1)); + }); + } + + private boolean removeTotemFromUser(Player player) { + + PlayerInventory playerInventory = player.getInventory(); + int slotID = -1; + for (int i = 0; i < playerInventory.getSize(); i++) { + ItemStack item = playerInventory.getItem(i); + if (item != null && item.getType() == Material.TOTEM_OF_UNDYING) { + slotID = i; + break; + } + } + + if (slotID == -1) { + this.plugin.getLogger().log(Level.FINE, "No totem find on this player"); + return false; + } + + + ItemStack item = playerInventory.getItem(slotID); + if (item == null) return false; + + int itemAmount = item.getAmount(); + if (itemAmount < 1) return false; + + if (itemAmount == 1) { + playerInventory.setItem(slotID, null); + } else { + item.setAmount(itemAmount - 1); + playerInventory.setItem(slotID, item); + } + + + return true; + } + +}