diff --git a/build.gradle.kts b/build.gradle.kts index 4325182..590d0d4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -82,4 +82,13 @@ bukkit { load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.STARTUP main = "club.devcord.gamejam.Nigulpyggub" apiVersion = "1.21" + + commands { + register("team") { + description = "Overall team management command" + } + register("game") { + description = "Overall game management command" + } + } } diff --git a/src/main/java/club/devcord/gamejam/Nigulpyggub.java b/src/main/java/club/devcord/gamejam/Nigulpyggub.java index 00da313..eba49da 100644 --- a/src/main/java/club/devcord/gamejam/Nigulpyggub.java +++ b/src/main/java/club/devcord/gamejam/Nigulpyggub.java @@ -1,10 +1,20 @@ package club.devcord.gamejam; +import club.devcord.gamejam.commands.GameCommand; +import club.devcord.gamejam.commands.TeamCommand; +import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + public class Nigulpyggub extends JavaPlugin { + private final List teams = new ArrayList<>(); + private final Lagger lagger = new Lagger(this); + @Override public void onDisable() { @@ -12,7 +22,28 @@ public void onDisable() { @Override public void onEnable() { + getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); + getServer().getPluginCommand("team").setExecutor(new TeamCommand(this)); + getServer().getPluginCommand("game").setExecutor(new GameCommand(this)); + } + + public Optional teamForName(String name) { + return teams.stream() + .filter(team -> team.creator().getName().equalsIgnoreCase(name)) + .findAny(); + } + + public Optional teamForPlayer(Player player) { + return teams.stream() + .filter(team -> team.players().contains(player)) + .findAny(); + } + + public List teams() { + return teams; + } - getServer().getPluginManager().registerEvents(new ResourcePackActivator(), this); + public Lagger lagger() { + return lagger; } } diff --git a/src/main/java/club/devcord/gamejam/ResourcePackActivator.java b/src/main/java/club/devcord/gamejam/PlayerJoinListener.java similarity index 90% rename from src/main/java/club/devcord/gamejam/ResourcePackActivator.java rename to src/main/java/club/devcord/gamejam/PlayerJoinListener.java index a794f29..04ea380 100644 --- a/src/main/java/club/devcord/gamejam/ResourcePackActivator.java +++ b/src/main/java/club/devcord/gamejam/PlayerJoinListener.java @@ -5,8 +5,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; - -public class ResourcePackActivator implements Listener { +public class PlayerJoinListener implements Listener { @EventHandler public void activatePlayerResourcePack(PlayerJoinEvent event) { diff --git a/src/main/java/club/devcord/gamejam/Team.java b/src/main/java/club/devcord/gamejam/Team.java new file mode 100644 index 0000000..0ee2bb6 --- /dev/null +++ b/src/main/java/club/devcord/gamejam/Team.java @@ -0,0 +1,23 @@ +package club.devcord.gamejam; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public record Team( + Player creator, + List players, + World world +) { + public List players() { + var list = new ArrayList<>(players); + list.addFirst(creator); + return list; + } + + public void addPlayer(Player player) { + players.add(player); + } +} diff --git a/src/main/java/club/devcord/gamejam/commands/GameCommand.java b/src/main/java/club/devcord/gamejam/commands/GameCommand.java new file mode 100644 index 0000000..8eed7c7 --- /dev/null +++ b/src/main/java/club/devcord/gamejam/commands/GameCommand.java @@ -0,0 +1,48 @@ +package club.devcord.gamejam.commands; + +import club.devcord.gamejam.Nigulpyggub; +import club.devcord.gamejam.Team; +import club.devcord.gamejam.world.WorldDuplicator; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.GameMode; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class GameCommand implements CommandExecutor { + + private final Nigulpyggub plugin; + + public GameCommand(Nigulpyggub plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (!(sender instanceof Player player)) return true; + if(!player.isOp()) { + player.sendMessage(MiniMessage.miniMessage().deserialize("Du musst mehr Rechte tanken.")); + return false; + } + + if (args.length != 1) { + player.sendMessage(MiniMessage.miniMessage().deserialize("You have to use: /game start")); + return false; + } + + switch (args[0].toLowerCase()) { + case "start" -> { + for (Team team : plugin.teams()) { + team.players().forEach(teamPlayer -> teamPlayer.setGameMode(GameMode.ADVENTURE)); + } + } + default -> player.sendMessage(MiniMessage.miniMessage().deserialize(" Unknown command.")); + } + return true; + } +} diff --git a/src/main/java/club/devcord/gamejam/commands/TeamCommand.java b/src/main/java/club/devcord/gamejam/commands/TeamCommand.java new file mode 100644 index 0000000..75846ff --- /dev/null +++ b/src/main/java/club/devcord/gamejam/commands/TeamCommand.java @@ -0,0 +1,127 @@ +package club.devcord.gamejam.commands; + +import club.devcord.gamejam.Nigulpyggub; +import club.devcord.gamejam.Team; +import club.devcord.gamejam.world.WorldDuplicator; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class TeamCommand implements TabExecutor { + + private final Nigulpyggub plugin; + private final WorldDuplicator duplicator; + + public TeamCommand(Nigulpyggub plugin) { + this.plugin = plugin; + this.duplicator = new WorldDuplicator(plugin); + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (!(sender instanceof Player player)) return true; + + if (args.length < 1) { + player.sendMessage(MiniMessage.miniMessage().deserialize("You have to use: /team create")); + return false; + } + + switch (args[0].toLowerCase()) { + + case "delete" -> plugin.teamForName(player.getName()) + .ifPresentOrElse(team -> { + plugin.teams().remove(team); + player.sendMessage(MiniMessage.miniMessage().deserialize("Your team was deleted!")); + }, () -> player.sendMessage(MiniMessage.miniMessage().deserialize("You're not the creator of a team."))); + + case "create" -> { + boolean alreadyInTeam = plugin.teamForPlayer(player).isPresent(); + + if (alreadyInTeam) { + player.sendMessage(MiniMessage.miniMessage().deserialize("You are already in a team!")); + return true; + } + + World teamWorld = duplicator.duplicate(player.getName()); + Team team = new Team(player, List.of(), teamWorld); + plugin.teams().add(team); + player.sendMessage(MiniMessage.miniMessage().deserialize("Team with name %s created".formatted(player.getName()))); + } + case "join" -> { + if (args.length != 2) { + player.sendMessage(MiniMessage.miniMessage().deserialize("You have to use: /team join ")); + return false; + } + + if(plugin.teamForPlayer(player).isPresent()) { + player.sendMessage(MiniMessage.miniMessage().deserialize("You are already in a team!")); + return false; + } + + plugin.teamForName(args[1]).ifPresentOrElse(team -> { + team.addPlayer(player); + player.sendMessage(MiniMessage.miniMessage().deserialize("You joined the team of %s".formatted(team.creator().getName()))); + }, () -> player.sendMessage(MiniMessage.miniMessage().deserialize("No team found for creator %s".formatted(args[1])))); + } + case "tp" -> { + if (!player.isOp()) { + player.sendMessage(MiniMessage.miniMessage().deserialize("Du musst mehr Rechte tanken.")); + return false; + } + + if (args.length != 2) { + player.sendMessage(MiniMessage.miniMessage().deserialize("You have to use: /team tp ")); + } + String name = args[1]; + + plugin.getServer().getWorlds().stream() + .filter(world -> world.getName().equalsIgnoreCase(name)) + .findAny() + .ifPresentOrElse(world -> { + Location playerLocation = player.getLocation(); + playerLocation.setWorld(world); + player.teleport(playerLocation); + + player.sendMessage(MiniMessage.miniMessage().deserialize("You were teleport to world %s".formatted(world.getName()))); + }, () -> player.sendMessage(MiniMessage.miniMessage().deserialize(" Team with name %s not found".formatted(name)))); + + } + default -> player.sendMessage(MiniMessage.miniMessage().deserialize("Unknown command")); + } + + return false; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length <= 1) { + return completions(sender, List.of("create", "join", "delete"), List.of("tp")); + } + + if (args[0].equalsIgnoreCase("tp") && sender.isOp()) { + return plugin.getServer().getWorlds().stream() + .map(World::getName) + .toList(); + } + return List.of(); + } + + private List completions(CommandSender player, List normal, List admin) { + if (!player.isOp()) { + return normal; + } + + ArrayList strings = new ArrayList<>(normal); + strings.addAll(admin); + return strings; + } +} diff --git a/src/main/java/club/devcord/gamejam/world/WorldDuplicator.java b/src/main/java/club/devcord/gamejam/world/WorldDuplicator.java new file mode 100644 index 0000000..e5eedf5 --- /dev/null +++ b/src/main/java/club/devcord/gamejam/world/WorldDuplicator.java @@ -0,0 +1,78 @@ +package club.devcord.gamejam.world; + +import club.devcord.gamejam.Nigulpyggub; +import club.devcord.gamejam.Team; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.WorldCreator; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +public class WorldDuplicator { + private final Nigulpyggub plugin; + + private final Path defaultWorld = Path.of("world"); + + public WorldDuplicator(Nigulpyggub plugin) { + this.plugin = plugin; + } + + public World duplicate(String name) { + String worldName = "world_" + name; + Path worldPath = Path.of(worldName); + var existingWorld = Bukkit.getWorld(worldName); + if(existingWorld != null) { + Bukkit.unloadWorld(existingWorld, false); + } + recursiveDelete(worldPath); + recursiveCopy(defaultWorld, worldPath); + return Bukkit.createWorld(WorldCreator.name(worldName)); + } + + private void recursiveCopy(Path from, Path to) { + try { + Files.walk(from) + .forEach(path -> { + if (Files.isDirectory(path) || path.getFileName().equals(Path.of("uid.dat"))) return; + try { + Path destination = to.resolve(path.subpath(from.getNameCount(), path.getNameCount())); + Files.createDirectories(destination.getParent()); + Files.copy(path, destination); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void recursiveDelete(Path path) { + try { + Files.walkFileTree(path, + new SimpleFileVisitor<>() { + @Override + public FileVisitResult postVisitDirectory( + Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile( + Path file, BasicFileAttributes attrs) + throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +}