From bb363dc06fdfd32d45d8c9fe570a87a459e80a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= <elias@elias-mueller.com> Date: Sun, 22 Oct 2023 22:22:39 +0200 Subject: [PATCH] Added void-world for selection Added loading indicators Added speed modifiers Code cleanup --- .idea/gradle.xml | 5 +- .idea/misc.xml | 1 - build.gradle | 26 ++-- .../eu/mhsl/craftattack/worldmuseum/Main.java | 30 ++--- .../worldmuseum/commands/SpawnCommand.java | 16 ++- .../worldmuseum/commands/TeleportCommand.java | 15 ++- .../worldmuseum/handler/SignHandler.java | 1 - .../worldmuseum/inventory/WorldSelector.java | 31 +++++ .../worldmuseum/items/ActionItem.java | 32 +++++ .../worldmuseum/items/ItemManager.java | 14 -- .../craftattack/worldmuseum/items/Items.java | 67 ++++++++++ .../listener/BlockBreakListener.java | 5 +- .../listener/BlockPlaceListener.java | 17 ++- .../worldmuseum/listener/ChunkUnloading.java | 2 +- .../listener/InventoryClickListener.java | 19 +-- .../worldmuseum/listener/ItemUseListener.java | 29 +---- .../listener/MovementListener.java | 13 -- .../worldmuseum/util/ChangeWorld.java | 23 ---- .../craftattack/worldmuseum/util/Config.java | 6 +- .../worldmuseum/util/MuseumPlayer.java | 98 +++++++------- .../worldmuseum/util/TablistUpdateTask.java | 4 +- .../worldmuseum/worlds/PlayerMovable.java | 7 + .../worldmuseum/worlds/VoidWorld.java | 47 +++++++ .../craftattack/worldmuseum/worlds/World.java | 120 +++++++++++------- .../worldmuseum/worlds/WorldManager.java | 24 ++-- 25 files changed, 399 insertions(+), 253 deletions(-) create mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/inventory/WorldSelector.java create mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/items/ActionItem.java delete mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/items/ItemManager.java create mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/items/Items.java delete mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/listener/MovementListener.java delete mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/util/ChangeWorld.java create mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/PlayerMovable.java create mode 100644 src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/VoidWorld.java diff --git a/.idea/gradle.xml b/.idea/gradle.xml index d28243b..70217ed 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,8 +4,11 @@ <component name="GradleSettings"> <option name="linkedExternalProjectsSettings"> <GradleProjectSettings> + <option name="delegatedBuild" value="true" /> + <option name="testRunner" value="GRADLE" /> + <option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="externalProjectPath" value="$PROJECT_DIR$" /> - <option name="gradleHome" value="/usr/share/java/gradle" /> + <option name="gradleJvm" value="17" /> <option name="modules"> <set> <option value="$PROJECT_DIR$" /> diff --git a/.idea/misc.xml b/.idea/misc.xml index 775445d..9f230de 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="corretto-17" project-jdk-type="JavaSDK"> diff --git a/build.gradle b/build.gradle index adb2947..36c5a57 100644 --- a/build.gradle +++ b/build.gradle @@ -3,8 +3,7 @@ plugins { id "com.github.johnrengelman.shadow" version "7.1.0" } -group = '' + - '' +group = 'eu.mhsl.craftattack.worldmuseum' version = '1.0' repositories { @@ -13,13 +12,24 @@ repositories { } dependencies { - - implementation 'com.github.Minestom:Minestom:8ad2c7701f' + implementation 'com.github.waxeria:Minestom:e0427a36f3' + implementation 'org.jctools:jctools-core:4.0.1' } -jar { - manifest { - attributes 'Main-Class': 'eu.mhsl.craftattack.worldmuseum.Main', - "Multi-Release": true +tasks { + jar { + manifest { + attributes 'Main-Class': 'eu.mhsl.craftattack.worldmuseum.Main' + attributes 'Multi-Release': true + } + duplicatesStrategy = 'exclude' + from configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } + build { + dependsOn(shadowJar) + } + shadowJar { + mergeServiceFiles() + archiveClassifier.set("") } } \ No newline at end of file diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/Main.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/Main.java index 8590ec1..8f71d17 100755 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/Main.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/Main.java @@ -1,7 +1,6 @@ package eu.mhsl.craftattack.worldmuseum; import eu.mhsl.craftattack.worldmuseum.commands.GamemodeCommand; -import eu.mhsl.craftattack.worldmuseum.items.ItemManager; import eu.mhsl.craftattack.worldmuseum.commands.SpawnCommand; import eu.mhsl.craftattack.worldmuseum.commands.TeleportCommand; import eu.mhsl.craftattack.worldmuseum.listener.*; @@ -10,7 +9,7 @@ import eu.mhsl.craftattack.worldmuseum.util.TablistUpdateTask; import eu.mhsl.craftattack.worldmuseum.util.Config; import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; import eu.mhsl.craftattack.worldmuseum.handler.SignHandler; -import eu.mhsl.craftattack.worldmuseum.worlds.World; +import eu.mhsl.craftattack.worldmuseum.worlds.VoidWorld; import eu.mhsl.craftattack.worldmuseum.worlds.WorldManager; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.GameMode; @@ -21,13 +20,13 @@ import net.minestom.server.event.player.*; import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.timer.TaskSchedule; -import java.time.Duration; +import java.io.IOException; public class Main { static int PORT = 25565; static final String IP = "0.0.0.0"; - public static void main(String[] args) { + public static void main(String[] args) throws IOException { // Initialization System.setProperty("minestom.chunk-view-distance", "16"); MinecraftServer minecraftServer = MinecraftServer.init(); @@ -45,14 +44,12 @@ public class Main { //load main config Config config = Config.getInstance(); config.loadConfig(); - World startworld = config.getStart_world(); if (config.isBungeecordEnabled()) { BungeeCordProxy.enable(); System.out.println("[Info] Bungeecord enabled"); } - // Add an event callback to specify the spawning instance (and the spawn position) GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler(); //listeners @@ -60,7 +57,6 @@ public class Main { globalEventHandler.addListener(PlayerChunkUnloadEvent.class, new ChunkUnloading()); globalEventHandler.addListener(InventoryPreClickEvent.class, new InventoryClickListener()); globalEventHandler.addListener(PlayerBlockBreakEvent.class, new BlockBreakListener()); - globalEventHandler.addListener(PlayerMoveEvent.class, new MovementListener()); globalEventHandler.addListener(PlayerBlockPlaceEvent.class, new BlockPlaceListener()); globalEventHandler.addListener(PlayerDisconnectEvent.class, new DisconnectListener()); @@ -78,18 +74,17 @@ public class Main { globalEventHandler.addListener(PlayerLoginEvent.class, event -> { final MuseumPlayer player = (MuseumPlayer) event.getPlayer(); - player.setSyncCooldown(Duration.ofSeconds(3)); - event.setSpawningInstance(startworld); + final VoidWorld voidWorld = new VoidWorld(); player.setPermissionLevel(4); - player.setRespawnPoint(startworld.getSpawn()); - player.setGameMode(GameMode.SURVIVAL); - MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { - SkinCache.setSkin(player); - player.setAllowFlying(true); - player.getInventory().setItemStack(0, ItemManager.getCompassItem()); - player.getInventory().setItemStack(8, ItemManager.getBedItem()); - }); + player.setRespawnPoint(voidWorld.getSpawn()); + player.setGameMode(GameMode.SPECTATOR); + player.setAllowFlying(true); + SkinCache.setSkin(player); + + event.setSpawningInstance(voidWorld); + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> voidWorld.movePlayer(player)); + System.out.println("[Join] Player " + player.getUsername() +" joined the server."); }); @@ -98,6 +93,7 @@ public class Main { } catch (Exception e) { if (args.length != 0) System.out.println("Given port doesn't work."); } + // Start the server on port default port 25565 if none is given System.out.println("[Info] Running on " + IP + ":" + PORT); minecraftServer.start(IP, PORT); diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/SpawnCommand.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/SpawnCommand.java index 1395a9a..b44f4cf 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/SpawnCommand.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/SpawnCommand.java @@ -1,17 +1,23 @@ package eu.mhsl.craftattack.worldmuseum.commands; +import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; import eu.mhsl.craftattack.worldmuseum.worlds.World; import net.minestom.server.command.builder.Command; -import net.minestom.server.entity.Player; public class SpawnCommand extends Command { public SpawnCommand() { super("spawn"); setDefaultExecutor((sender, context) -> { - Player p = (Player) sender; - World world = (World) p.getInstance(); - assert world != null; - p.teleport(world.getSpawn()); + if(sender instanceof MuseumPlayer p) { + teleportToSpawn(p); + } }); } + + public static void teleportToSpawn(MuseumPlayer p) { + if(p.getInstance() instanceof World world) { + p.startLoading(); + p.teleport(world.getSpawn()).thenRun(p::stopLoading); + } + } } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/TeleportCommand.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/TeleportCommand.java index 86cca77..25e4a8b 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/TeleportCommand.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/commands/TeleportCommand.java @@ -11,22 +11,23 @@ public class TeleportCommand extends Command { public TeleportCommand() { super("tp"); - var cordinate = ArgumentType.RelativeBlockPosition("Koordinate"); + var coordinate = ArgumentType.RelativeBlockPosition("cords"); addSyntax(((sender, context) -> { - Pos pos = context.get(cordinate).fromSender(sender).asPosition(); + Pos pos = context.get(coordinate).fromSender(sender).asPosition(); Player player = (Player) sender; player.teleport(pos); - }), cordinate); + }), coordinate); - var playerArgument = ArgumentType.Entity("Spieler").onlyPlayers(true).singleEntity(true); + var playerArgument = ArgumentType.Entity("player").onlyPlayers(true).singleEntity(true); addSyntax(((sender, context) -> { - if (context.get(playerArgument).find(sender).size() == 0) return; //check if player is online + if (context.get(playerArgument).find(sender).isEmpty()) return; //check if player is online Player targetPlayer = (Player) context.get(playerArgument).find(sender).get(0); Player p = (Player) sender; - if (!Objects.equals(p.getInstance(), targetPlayer.getInstance())) + if (!Objects.equals(p.getInstance(), targetPlayer.getInstance())) { p.setInstance(Objects.requireNonNull(targetPlayer.getInstance()), targetPlayer.getPosition()); - else + } else { p.teleport(targetPlayer.getPosition()); + } }), playerArgument); } } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/handler/SignHandler.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/handler/SignHandler.java index caa0a45..11f6824 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/handler/SignHandler.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/handler/SignHandler.java @@ -11,7 +11,6 @@ import java.util.Collection; public class SignHandler implements BlockHandler { @Override public @NotNull Collection<Tag<?>> getBlockEntityTags() { - return new ArrayList<>() { { add(Tag.Byte("GlowingText")); diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/inventory/WorldSelector.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/inventory/WorldSelector.java new file mode 100644 index 0000000..c90db1f --- /dev/null +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/inventory/WorldSelector.java @@ -0,0 +1,31 @@ +package eu.mhsl.craftattack.worldmuseum.inventory; + +import eu.mhsl.craftattack.worldmuseum.worlds.World; +import eu.mhsl.craftattack.worldmuseum.worlds.WorldManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.inventory.Inventory; +import net.minestom.server.inventory.InventoryType; + +import java.util.List; + +public class WorldSelector extends Inventory { + public WorldSelector() { + super(InventoryType.CHEST_1_ROW, Component.text("Weltenauswahl").color(NamedTextColor.DARK_GRAY)); + + List<World> worlds = WorldManager.getInstance().getWorlds(); + for (int i = 0; i < worlds.size(); i++) { + World world = worlds.get(i); + setItemStack(i, world.getItem()); + } + + addInventoryCondition((player, slot, clickType, inventoryConditionResult) -> { + inventoryConditionResult.setCancel(true); + + player.closeInventory(); + try { + worlds.get(slot).movePlayer(player); + } catch (IndexOutOfBoundsException ignore) {} + }); + } +} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/items/ActionItem.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/items/ActionItem.java new file mode 100644 index 0000000..1eea542 --- /dev/null +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/items/ActionItem.java @@ -0,0 +1,32 @@ +package eu.mhsl.craftattack.worldmuseum.items; + +import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; +import net.minestom.server.entity.Player; +import net.minestom.server.item.ItemStack; +import net.minestom.server.tag.Tag; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +public class ActionItem { + public static Tag<UUID> tag = Tag.UUID("action"); + public static Map<UUID, Consumer<MuseumPlayer>> actions = new HashMap<>(); + + private final ItemStack itemStack; + + public ActionItem(Consumer<MuseumPlayer> action, ItemStack itemStack) { + UUID uuid = UUID.randomUUID(); + this.itemStack = itemStack.withTag(tag, uuid); + actions.put(uuid, action); + } + + public static void run(UUID uuid, Player p) { + actions.get(uuid).accept((MuseumPlayer) p); + } + + public ItemStack getItemStack() { + return itemStack; + } +} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/items/ItemManager.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/items/ItemManager.java deleted file mode 100644 index 5c73862..0000000 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/items/ItemManager.java +++ /dev/null @@ -1,14 +0,0 @@ -package eu.mhsl.craftattack.worldmuseum.items; - -import net.kyori.adventure.text.Component; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; - -public class ItemManager { - public static ItemStack getBedItem() { - return ItemStack.builder(Material.RED_BED).displayName(Component.text("Spawn-Teleporter")).build(); - } - public static ItemStack getCompassItem() { - return ItemStack.builder(Material.COMPASS).displayName(Component.text("World-changer")).build(); - } -} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/items/Items.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/items/Items.java new file mode 100644 index 0000000..7152b54 --- /dev/null +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/items/Items.java @@ -0,0 +1,67 @@ +package eu.mhsl.craftattack.worldmuseum.items; + +import eu.mhsl.craftattack.worldmuseum.commands.SpawnCommand; +import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; +import eu.mhsl.craftattack.worldmuseum.worlds.VoidWorld; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; + +import java.util.function.Consumer; + +public enum Items { + HUB( + ItemStack + .of(Material.IRON_DOOR) + .withDisplayName( + Component + .text("Zurück zur Überischt") + .color(NamedTextColor.GOLD) + ), + player -> new VoidWorld().movePlayer(player) + ), + + SPAWN( + ItemStack + .of(Material.TARGET) + .withDisplayName( + Component + .text("Zum Spawn") + .color(NamedTextColor.GOLD) + ), + SpawnCommand::teleportToSpawn + ), + + MORE_SPEED( + ItemStack + .of(Material.FEATHER) + .withDisplayName( + Component + .text("Schneller fliegen") + .color(NamedTextColor.AQUA) + ), + player -> player.updateFlyingSpeed(0.05f) + ), + + LESS_SPEED( + ItemStack + .of(Material.ANVIL) + .withDisplayName( + Component + .text("Langsamer fliegen") + .color(NamedTextColor.AQUA) + ), + player -> player.updateFlyingSpeed(-0.05f) + ); + + + private final ActionItem item; + Items(ItemStack itemStack, Consumer<MuseumPlayer> action) { + item = new ActionItem(action, itemStack); + } + + public ItemStack getItem() { + return item.getItemStack(); + } +} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockBreakListener.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockBreakListener.java index 68fdb4d..d4ee114 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockBreakListener.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockBreakListener.java @@ -3,6 +3,7 @@ package eu.mhsl.craftattack.worldmuseum.listener; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; import net.minestom.server.event.player.PlayerBlockBreakEvent; +import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import net.minestom.server.timer.TaskSchedule; import java.util.function.Consumer; @@ -12,6 +13,8 @@ public class BlockBreakListener implements Consumer<PlayerBlockBreakEvent> { public void accept(PlayerBlockBreakEvent playerBlockBreakEvent) { Block block = playerBlockBreakEvent.getBlock(); Point point = playerBlockBreakEvent.getBlockPosition(); - MinecraftServer.getSchedulerManager().scheduleTask(() -> playerBlockBreakEvent.getInstance().setBlock(point, block), TaskSchedule.seconds(10), TaskSchedule.stop()); + Instance instance = playerBlockBreakEvent.getInstance(); + + MinecraftServer.getSchedulerManager().scheduleTask(() -> instance.setBlock(point, block), TaskSchedule.seconds(10), TaskSchedule.stop()); } } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockPlaceListener.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockPlaceListener.java index ad017e6..86a725a 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockPlaceListener.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/BlockPlaceListener.java @@ -1,14 +1,25 @@ package eu.mhsl.craftattack.worldmuseum.listener; -import eu.mhsl.craftattack.worldmuseum.worlds.World; +import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerBlockPlaceEvent; -import java.util.Objects; +import net.minestom.server.event.player.PlayerUseItemEvent; + import java.util.function.Consumer; public class BlockPlaceListener implements Consumer<PlayerBlockPlaceEvent> { @Override public void accept(PlayerBlockPlaceEvent playerBlockPlaceEvent) { - playerBlockPlaceEvent.getPlayer().teleport(((World) Objects.requireNonNull(playerBlockPlaceEvent.getPlayer().getInstance())).getSpawn()); + Player p = playerBlockPlaceEvent.getPlayer(); + + // Fire ItemUseListener for possible missed block-clicks + new ItemUseListener().accept( + new PlayerUseItemEvent( + p, + playerBlockPlaceEvent.getHand(), + p.getInventory().getItemStack(p.getHeldSlot()) + ) + ); + playerBlockPlaceEvent.setCancelled(true); } } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ChunkUnloading.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ChunkUnloading.java index 7afa63f..9ea48c3 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ChunkUnloading.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ChunkUnloading.java @@ -10,7 +10,7 @@ public class ChunkUnloading implements Consumer<PlayerChunkUnloadEvent> { var chunk = e.getInstance().getChunk(e.getChunkX(), e.getChunkZ()); if (chunk == null) return; - if (chunk.getViewers().size() == 0) { + if (chunk.getViewers().isEmpty()) { try { e.getInstance().unloadChunk(e.getChunkX(), e.getChunkZ()); } catch (NullPointerException ignored) {} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/InventoryClickListener.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/InventoryClickListener.java index ee58547..ca73ac6 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/InventoryClickListener.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/InventoryClickListener.java @@ -1,29 +1,12 @@ package eu.mhsl.craftattack.worldmuseum.listener; -import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; -import eu.mhsl.craftattack.worldmuseum.util.ChangeWorld; -import eu.mhsl.craftattack.worldmuseum.worlds.World; -import eu.mhsl.craftattack.worldmuseum.worlds.WorldManager; import net.minestom.server.event.inventory.InventoryPreClickEvent; -import java.util.Objects; + import java.util.function.Consumer; public class InventoryClickListener implements Consumer<InventoryPreClickEvent> { @Override public void accept(InventoryPreClickEvent inventoryPreClickEvent) { - MuseumPlayer p = (MuseumPlayer) inventoryPreClickEvent.getPlayer(); - WorldManager worldManager = WorldManager.getInstance(); - - for (World w : worldManager.getWorlds()) { - if (!w.getItem().equals(inventoryPreClickEvent.getClickedItem())) continue; - if (Objects.equals(p.getInstance(), w)) { - p.closeInventory(); - p.teleport(w.getSpawn()); - } else { - p.closeInventory(); - ChangeWorld.changeWorld(p, w); - } - } inventoryPreClickEvent.setCancelled(true); } } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ItemUseListener.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ItemUseListener.java index 4754e1d..80432fe 100755 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ItemUseListener.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/ItemUseListener.java @@ -1,37 +1,18 @@ package eu.mhsl.craftattack.worldmuseum.listener; -import eu.mhsl.craftattack.worldmuseum.items.ItemManager; -import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; -import eu.mhsl.craftattack.worldmuseum.worlds.World; -import net.kyori.adventure.text.Component; +import eu.mhsl.craftattack.worldmuseum.items.ActionItem; import net.minestom.server.event.player.PlayerUseItemEvent; -import net.minestom.server.item.ItemStack; + import java.util.function.Consumer; public class ItemUseListener implements Consumer<PlayerUseItemEvent> { @Override public void accept(PlayerUseItemEvent playerUseItemEvent) { - MuseumPlayer p = (MuseumPlayer) playerUseItemEvent.getPlayer(); - ItemStack usedItem = playerUseItemEvent.getItemStack(); - - if (usedItem.equals(ItemManager.getCompassItem())) compassUse(p); - else if (usedItem.equals(ItemManager.getBedItem())) bedUse(p); + if(playerUseItemEvent.getItemStack().hasTag(ActionItem.tag)) { + ActionItem.run(playerUseItemEvent.getItemStack().getTag(ActionItem.tag), playerUseItemEvent.getPlayer()); + } playerUseItemEvent.setCancelled(true); } - private void compassUse(MuseumPlayer p) { - if (!p.isAllowCompassUsage()) { - long lastUsed = (System.currentTimeMillis() - p.getLastCompassUsage()) / 1000; - p.sendActionBar(Component.text("Du kannst den Kompass erst in " + (15 - lastUsed) + " Sekunden wieder benutzen.")); - return; - } - p.openInventory(p.getCompassInventory()); - } - - private void bedUse(MuseumPlayer player) { - World world = (World) player.getInstance(); - assert world != null; - player.teleport(world.getSpawn()); - } } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/MovementListener.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/MovementListener.java deleted file mode 100644 index f6e36b5..0000000 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/listener/MovementListener.java +++ /dev/null @@ -1,13 +0,0 @@ -package eu.mhsl.craftattack.worldmuseum.listener; - -import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; -import net.minestom.server.event.player.PlayerMoveEvent; -import java.util.function.Consumer; - -public class MovementListener implements Consumer<PlayerMoveEvent> { - @Override - public void accept(PlayerMoveEvent playerMoveEvent) { - MuseumPlayer player = (MuseumPlayer) playerMoveEvent.getPlayer(); - if (!player.isAllowMovement()) playerMoveEvent.setCancelled(true); - } -} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/ChangeWorld.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/util/ChangeWorld.java deleted file mode 100644 index 48f6c31..0000000 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/ChangeWorld.java +++ /dev/null @@ -1,23 +0,0 @@ -package eu.mhsl.craftattack.worldmuseum.util; - -import eu.mhsl.craftattack.worldmuseum.worlds.World; -import net.minestom.server.potion.Potion; -import net.minestom.server.potion.PotionEffect; -public class ChangeWorld { - public static void changeWorld(MuseumPlayer player, World targetWorld) { - player.setAllowMovement(false); - World world = (World) player.getInstance(); - player.setAllowCompassUsage(false); - player.addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 0, 1000000)); - - player.setRespawnPoint(targetWorld.getSpawn()); - player.setInstance(targetWorld, targetWorld.getSpawn()).thenRun(() -> { - player.setAllowMovement(true); - player.clearEffects(); - player.update_lastCompassUsage(); - player.setAllowCompassUsage(true); - }); - assert world != null; - System.out.println("[Worldchange] Player " + player.getUsername() + " changed world from " + world.getName() + " to " + targetWorld.getName() +"."); - } -} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/Config.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/util/Config.java index 5437aab..9288351 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/Config.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/util/Config.java @@ -25,13 +25,9 @@ public class Config { if (!w.getName().equals(config.get("start_world").getAsString())) continue; this.start_world = w; } - if (start_world == null) { - System.out.println("no starting world set"); - System.exit(0); - } this.bungeecordEnabled = config.get("bungeecord").getAsBoolean(); - }catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); } } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/MuseumPlayer.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/util/MuseumPlayer.java index 68b6e53..4955be8 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/MuseumPlayer.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/util/MuseumPlayer.java @@ -1,70 +1,66 @@ package eu.mhsl.craftattack.worldmuseum.util; -import eu.mhsl.craftattack.worldmuseum.worlds.World; -import eu.mhsl.craftattack.worldmuseum.worlds.WorldManager; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.title.Title; +import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; -import net.minestom.server.inventory.Inventory; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.Enchantment; -import net.minestom.server.item.ItemHideFlag; -import net.minestom.server.item.ItemStack; +import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.network.player.PlayerConnection; +import net.minestom.server.potion.Potion; +import net.minestom.server.potion.PotionEffect; +import net.minestom.server.timer.ExecutionType; +import net.minestom.server.timer.TaskSchedule; +import net.minestom.server.utils.MathUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; + import java.time.Duration; import java.util.UUID; public class MuseumPlayer extends Player { - - private boolean allowMovement = true; - private long lastCompassUsage = 0; - private boolean allowCompassUsage = true; + private boolean isLoading = false; public MuseumPlayer(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection playerConnection) { super(uuid, username, playerConnection); - } - public void setSyncCooldown(@Nullable Duration cooldown) { - this.setCustomSynchronizationCooldown(cooldown); + + eventNode().addListener(PlayerMoveEvent.class, playerMoveEvent -> playerMoveEvent.setCancelled(isLoading)); } - public boolean isAllowMovement() { - return allowMovement; - } - public void update_lastCompassUsage() { - lastCompassUsage = System.currentTimeMillis(); - } - public boolean isAllowCompassUsage() { - long UsageDifference = System.currentTimeMillis() - lastCompassUsage; - long difference = 15000; //in Milisec - return UsageDifference >= difference && allowCompassUsage; - } - public void setAllowMovement(boolean allowMovement) { - this.allowMovement = allowMovement; - } - public void setAllowCompassUsage(boolean allowCompassUsage) { - this.allowCompassUsage = allowCompassUsage; - } - public long getLastCompassUsage() { - return lastCompassUsage; - } - public Inventory getCompassInventory() { - Inventory inventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("World-changer")); - for (World w : WorldManager.getInstance().getWorlds()) { - if (!w.equals(this.getInstance())) { - inventory.addItemStack(w.getItem()); - continue; + public void startLoading() { + isLoading = true; + MinecraftServer.getSchedulerManager().submitTask(() -> { + sendMessage("" + System.currentTimeMillis()); + addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 3, 600)); + showTitle(Title.title( + Component.text("Loading").decorate(TextDecoration.BOLD).color(NamedTextColor.GOLD), + Component.text("...").color(NamedTextColor.YELLOW), + Title.Times.times(Duration.ZERO, Duration.ofSeconds(30), Duration.ZERO) + )); + + if(!isLoading) { + clearEffects(); + clearTitle(); + return TaskSchedule.stop(); } - ItemStack itemStack = ItemStack.builder(w.getItem().material()) - .displayName(w.getItem().getDisplayName()) - .meta(metaBuilder -> - metaBuilder - .enchantment(Enchantment.MENDING, (short) 10) - .hideFlag(ItemHideFlag.HIDE_ENCHANTS)) - .build(); - inventory.addItemStack(itemStack); - } - return inventory; + return TaskSchedule.millis(100); + }, ExecutionType.ASYNC); } + public void stopLoading() { + isLoading = false; + } + + public void updateFlyingSpeed(float speed) { + speed = MathUtils.clamp(getFlyingSpeed() + speed, 0.01f, 0.2f); + setFlyingSpeed(speed); + sendActionBar( + Component + .text("Geschwindigkeit: ") + .color(NamedTextColor.GOLD) + .append(Component.text(Math.round(speed * 1000) + "%").color(NamedTextColor.WHITE)) + ); + } + + } diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/TablistUpdateTask.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/util/TablistUpdateTask.java index 631a49d..e27dd13 100644 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/util/TablistUpdateTask.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/util/TablistUpdateTask.java @@ -5,9 +5,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.MinecraftServer; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.entity.Player; -import net.minestom.server.monitoring.TickMonitor; import java.util.Collection; -import java.util.concurrent.atomic.AtomicReference; public class TablistUpdateTask implements Runnable { @Override @@ -18,7 +16,7 @@ public class TablistUpdateTask implements Runnable { final Component header = Component.newline() .append(Component.text(" Welten-Museum ", NamedTextColor.GOLD)) - .append(Component.newline()).append(Component.text("Players: " + players.size())) + .append(Component.newline()).append(Component.text("Spieler: " + players.size())) .append(Component.newline()); final Component footer = diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/PlayerMovable.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/PlayerMovable.java new file mode 100644 index 0000000..dd95381 --- /dev/null +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/PlayerMovable.java @@ -0,0 +1,7 @@ +package eu.mhsl.craftattack.worldmuseum.worlds; + +import net.minestom.server.entity.Player; + +public interface PlayerMovable { + void movePlayer(Player p); +} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/VoidWorld.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/VoidWorld.java new file mode 100644 index 0000000..128261d --- /dev/null +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/VoidWorld.java @@ -0,0 +1,47 @@ +package eu.mhsl.craftattack.worldmuseum.worlds; + +import eu.mhsl.craftattack.worldmuseum.inventory.WorldSelector; +import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; +import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.Player; +import net.minestom.server.event.inventory.InventoryCloseEvent; +import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.instance.InstanceContainer; +import net.minestom.server.instance.block.Block; +import net.minestom.server.world.DimensionType; + +import java.util.UUID; + +public class VoidWorld extends InstanceContainer implements PlayerMovable { + public VoidWorld() { + super(UUID.randomUUID(), DimensionType.OVERWORLD); + MinecraftServer.getInstanceManager().registerInstance(this); + setBlock(getSpawn().sub(0, 1, 0), Block.BARRIER); + + eventNode().addListener(InventoryCloseEvent.class, inventoryCloseEvent -> { + if(inventoryCloseEvent.getPlayer().getInstance() != this) return; + inventoryCloseEvent.setNewInventory(inventoryCloseEvent.getInventory()); + }); + + eventNode().addListener(PlayerMoveEvent.class, playerMoveEvent -> playerMoveEvent.setCancelled(true)); + } + + public Pos getSpawn() { + return new Pos(0, 50, 0, 0, 0); + } + + public void movePlayer(Player p) { + MuseumPlayer museumPlayer = (MuseumPlayer) p; + if(p.getInstance() != this) p.setInstance(this).thenRun(() -> { + p.teleport(getSpawn()); + p.openInventory(new WorldSelector()); + museumPlayer.stopLoading(); + }); + + museumPlayer.startLoading(); + p.getInventory().clear(); + p.setRespawnPoint(getSpawn()); + p.setAllowFlying(false); + } +} diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/World.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/World.java index 0eef411..831980b 100755 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/World.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/World.java @@ -1,78 +1,108 @@ package eu.mhsl.craftattack.worldmuseum.worlds; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import eu.mhsl.craftattack.worldmuseum.items.Items; +import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.GameMode; +import net.minestom.server.entity.Player; import net.minestom.server.instance.AnvilLoader; import net.minestom.server.instance.InstanceContainer; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.utils.NamespaceID; import net.minestom.server.world.DimensionType; + import java.io.*; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; -public class World extends InstanceContainer { +public class World extends InstanceContainer implements PlayerMovable { private final static DimensionType dimension = DimensionType.builder(NamespaceID.from("mhsl.eu:worldview_by_olischma")).height(400).ambientLight(2.0f).build(); - private final ItemStack item; - private String name = "default"; - private Pos spawn = new Pos(0,0,0); - private boolean enabled = false; + + private final boolean enabled; + private final String name; + private final Material material; + private final Pos spawn; + private final List<String> tags = new ArrayList<>(); + static { MinecraftServer.getDimensionTypeManager().addDimension(dimension); } - AnvilLoader anvilLoader; - public World(File file) { + public World(File file) throws IOException { super(UUID.randomUUID(), dimension, new AnvilLoader(file.getPath())); - this.anvilLoader = new AnvilLoader(file.getPath()); MinecraftServer.getInstanceManager().registerInstance(this); - try { - File checkFile = new File(file.getPath() + "/config.json"); - if (checkFile.createNewFile()) { - FileWriter fileWriter = new FileWriter(file.getPath() + "/config.json"); - String defaultConfig = """ - { - "enabled": false, - "name": "DEFAULT_NAME", - "material": "GRASS_BLOCK", - "spawn": { - "x": 0, - "y": 0, - "z": 0 - }, - "tags": [ - "RANDOM_TAG" - ] - }"""; - fileWriter.write(defaultConfig); - fileWriter.close(); - } - } catch (IOException e){ - e.printStackTrace(); + + File configFile = new File(file.getPath() + "/config.json"); + if (configFile.createNewFile()) { + writeDefaultConfig(file); } - Material material = Material.GRASS_BLOCK; - try { - JsonObject config = (JsonObject) JsonParser.parseReader(new FileReader(file.getPath() + "/config.json")); - this.name = config.get("name").getAsString(); - JsonObject spawn = config.getAsJsonObject("spawn"); - this.spawn = new Pos(spawn.get("x").getAsDouble(), spawn.get("y").getAsDouble(), spawn.get("z").getAsDouble()); - material = Material.fromNamespaceId("minecraft:" + config.get("material").getAsString().toLowerCase()); - this.enabled = config.get("enabled").getAsBoolean(); + JsonObject config = (JsonObject) JsonParser.parseReader(new FileReader(file.getPath() + "/config.json")); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - assert material != null; - item = ItemStack.builder(material).displayName(Component.text(name)).build(); + this.enabled = config.get("enabled").getAsBoolean(); + this.name = config.get("name").getAsString(); + this.material = Material.fromNamespaceId("minecraft:" + config.get("material").getAsString().toLowerCase()); + + JsonObject spawn = config.getAsJsonObject("spawn"); + this.spawn = new Pos(spawn.get("x").getAsDouble(), spawn.get("y").getAsDouble(), spawn.get("z").getAsDouble()); + + JsonArray tags = config.getAsJsonArray("tags"); + tags.forEach(jsonElement -> this.tags.add(jsonElement.getAsString())); + + } + + @Override + public void movePlayer(Player player) { + MuseumPlayer p = (MuseumPlayer) player; + + p.startLoading(); + p.teleport(getSpawn()); + p.setInstance(this).thenRun(() -> { + p.setRespawnPoint(getSpawn()); + p.teleport(getSpawn()); + p.setGameMode(GameMode.SURVIVAL); + p.setAllowFlying(true); + + p.getInventory().setItemStack(3, Items.MORE_SPEED.getItem()); + p.getInventory().setItemStack(4, Items.LESS_SPEED.getItem()); + + p.getInventory().setItemStack(7, Items.SPAWN.getItem()); + p.getInventory().setItemStack(8, Items.HUB.getItem()); + + p.stopLoading(); + }); + } + + private void writeDefaultConfig(File file) throws IOException { + FileWriter fileWriter = new FileWriter(file.getPath() + "/config.json"); + String defaultConfig = """ + { + "enabled": false, + "name": "DEFAULT_NAME", + "material": "GRASS_BLOCK", + "spawn": { + "x": 0, + "y": 0, + "z": 0 + }, + "tags": [ + "RANDOM_TAG" + ] + }"""; + fileWriter.write(defaultConfig); + fileWriter.close(); } public ItemStack getItem() { - return item; + return ItemStack.builder(material).displayName(Component.text(name)).build(); } public String getName() { diff --git a/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/WorldManager.java b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/WorldManager.java index dc35ee7..ea0c089 100755 --- a/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/WorldManager.java +++ b/src/main/java/eu/mhsl/craftattack/worldmuseum/worlds/WorldManager.java @@ -1,7 +1,9 @@ package eu.mhsl.craftattack.worldmuseum.worlds; import java.io.File; +import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class WorldManager { @@ -14,11 +16,11 @@ public class WorldManager { } return instance; } - public void loadWorlds() { + public void loadWorlds() throws IOException { File saveDirectory = new File("saves"); - List<File> worldFolders = getFolderNames(saveDirectory); - for (File f: worldFolders - ) { + if(!saveDirectory.exists()) throw new IOException("Saves folder 'saves' could not be found!"); + List<File> worldFolders = getFolders(saveDirectory); + for (File f : worldFolders) { World w = new World(f); if (w.isEnabled()) { worlds.add(w); @@ -26,16 +28,14 @@ public class WorldManager { System.out.println("Es gibt eine nicht aktivierte Welt: " + f); } } + } - private List<File> getFolderNames(File curDir) { - File[] fileList = curDir.listFiles(); - List<File> returnFolders = new ArrayList<>(); - assert fileList != null; - for (File f: fileList) { - if (f.isDirectory()) returnFolders.add(f); - } - return returnFolders; + private List<File> getFolders(File directory) { + File[] fileList = directory.listFiles(); + if(fileList == null) return new ArrayList<>(); + + return Arrays.stream(fileList).filter(File::isDirectory).toList(); } public List<World> getWorlds() {