Compare commits

...

8 Commits
1.0 ... master

Author SHA1 Message Date
533df11984 Bungeecord join issues solved
Fixed return-server not working
2023-10-23 14:21:15 +02:00
4aa5c1e5ae Removed dead config files and entries
Added option for bungeecord return server
2023-10-23 09:17:19 +02:00
a00c1f174c Added option to leave Server and go back to main server 2023-10-23 08:49:31 +02:00
6b2b25ce5e Fixed indefinite loading bug
Removed verbose logging
Changed loading-text
2023-10-23 08:11:13 +02:00
bb363dc06f Added void-world for selection
Added loading indicators
Added speed modifiers
Code cleanup
2023-10-22 22:22:39 +02:00
ebf9f36635 Bungeecord join error fix 2023-05-21 11:05:16 +02:00
3b36fcdbbf Word mistake correction 2023-05-20 17:29:48 +02:00
dd713732c6 version 1.1 release 2023-05-17 17:09:05 +02:00
29 changed files with 488 additions and 284 deletions

5
.idea/gradle.xml generated
View File

@ -4,8 +4,11 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <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="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/share/java/gradle" /> <option name="gradleJvm" value="17" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />

1
.idea/misc.xml generated
View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="corretto-17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="corretto-17" project-jdk-type="JavaSDK">

View File

@ -3,8 +3,7 @@ plugins {
id "com.github.johnrengelman.shadow" version "7.1.0" id "com.github.johnrengelman.shadow" version "7.1.0"
} }
group = '' + group = 'eu.mhsl.craftattack.worldmuseum'
''
version = '1.0' version = '1.0'
repositories { repositories {
@ -13,13 +12,25 @@ repositories {
} }
dependencies { dependencies {
implementation 'com.github.waxeria:Minestom:e0427a36f3'
implementation 'com.github.Minestom:Minestom:8ad2c7701f' implementation 'org.jctools:jctools-core:4.0.1'
implementation 'com.google.guava:guava:31.0.1-jre'
} }
tasks {
jar { jar {
manifest { manifest {
attributes 'Main-Class': 'eu.mhsl.craftattack.worldmuseum.Main', attributes 'Main-Class': 'eu.mhsl.craftattack.worldmuseum.Main'
"Multi-Release": true attributes 'Multi-Release': true
}
duplicatesStrategy = 'exclude'
from configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
build {
dependsOn(shadowJar)
}
shadowJar {
mergeServiceFiles()
archiveClassifier.set("")
} }
} }

View File

@ -1,7 +1,6 @@
package eu.mhsl.craftattack.worldmuseum; package eu.mhsl.craftattack.worldmuseum;
import eu.mhsl.craftattack.worldmuseum.commands.GamemodeCommand; 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.SpawnCommand;
import eu.mhsl.craftattack.worldmuseum.commands.TeleportCommand; import eu.mhsl.craftattack.worldmuseum.commands.TeleportCommand;
import eu.mhsl.craftattack.worldmuseum.listener.*; 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.Config;
import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer; import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer;
import eu.mhsl.craftattack.worldmuseum.handler.SignHandler; 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 eu.mhsl.craftattack.worldmuseum.worlds.WorldManager;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
@ -18,19 +17,21 @@ import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.event.inventory.InventoryPreClickEvent;
import net.minestom.server.event.item.ItemDropEvent; import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.player.*; import net.minestom.server.event.player.*;
import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import java.time.Duration; import java.io.IOException;
public class Main { public class Main {
static int PORT = 25565; static int PORT = 25565;
static final String IP = "0.0.0.0"; static final String IP = "0.0.0.0";
public static void main(String[] args) { public static void main(String[] args) throws IOException {
// Initialization // Initialization
System.setProperty("minestom.chunk-view-distance", "16"); System.setProperty("minestom.chunk-view-distance", "16");
MinecraftServer minecraftServer = MinecraftServer.init(); MinecraftServer minecraftServer = MinecraftServer.init();
MinecraftServer.getConnectionManager().setPlayerProvider(MuseumPlayer::new); MinecraftServer.getConnectionManager().setPlayerProvider(MuseumPlayer::new);
MinecraftServer.setBrandName("mhsl.eu:worldmuseum_by_olischma");
//update Taskbar //update Taskbar
MinecraftServer.getSchedulerManager().scheduleTask(new TablistUpdateTask(), TaskSchedule.tick(20), TaskSchedule.tick(20)); MinecraftServer.getSchedulerManager().scheduleTask(new TablistUpdateTask(), TaskSchedule.tick(20), TaskSchedule.tick(20));
@ -43,9 +44,12 @@ public class Main {
//load main config //load main config
Config config = Config.getInstance(); Config config = Config.getInstance();
config.loadConfig(); 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(); GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
//listeners //listeners
@ -53,7 +57,6 @@ public class Main {
globalEventHandler.addListener(PlayerChunkUnloadEvent.class, new ChunkUnloading()); globalEventHandler.addListener(PlayerChunkUnloadEvent.class, new ChunkUnloading());
globalEventHandler.addListener(InventoryPreClickEvent.class, new InventoryClickListener()); globalEventHandler.addListener(InventoryPreClickEvent.class, new InventoryClickListener());
globalEventHandler.addListener(PlayerBlockBreakEvent.class, new BlockBreakListener()); globalEventHandler.addListener(PlayerBlockBreakEvent.class, new BlockBreakListener());
globalEventHandler.addListener(PlayerMoveEvent.class, new MovementListener());
globalEventHandler.addListener(PlayerBlockPlaceEvent.class, new BlockPlaceListener()); globalEventHandler.addListener(PlayerBlockPlaceEvent.class, new BlockPlaceListener());
globalEventHandler.addListener(PlayerDisconnectEvent.class, new DisconnectListener()); globalEventHandler.addListener(PlayerDisconnectEvent.class, new DisconnectListener());
@ -71,16 +74,18 @@ public class Main {
globalEventHandler.addListener(PlayerLoginEvent.class, event -> { globalEventHandler.addListener(PlayerLoginEvent.class, event -> {
final MuseumPlayer player = (MuseumPlayer) event.getPlayer(); final MuseumPlayer player = (MuseumPlayer) event.getPlayer();
player.setSyncCooldown(Duration.ofSeconds(3)); final VoidWorld voidWorld = new VoidWorld();
SkinCache.setSkin(player);
event.setSpawningInstance(startworld);
event.setSpawningInstance(voidWorld);
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> {
player.setPermissionLevel(4); player.setPermissionLevel(4);
player.setRespawnPoint(startworld.getSpawn()); player.setRespawnPoint(voidWorld.getSpawn());
player.setGameMode(GameMode.SURVIVAL); player.setGameMode(GameMode.SPECTATOR);
player.setAllowFlying(true); player.setAllowFlying(true);
player.getInventory().setItemStack(0, ItemManager.getCompassItem()); SkinCache.setSkin(player);
player.getInventory().setItemStack(8, ItemManager.getBedItem()); voidWorld.movePlayer(player);
});
System.out.println("[Join] Player " + player.getUsername() +" joined the server."); System.out.println("[Join] Player " + player.getUsername() +" joined the server.");
}); });
@ -89,8 +94,9 @@ public class Main {
} catch (Exception e) { } catch (Exception e) {
if (args.length != 0) System.out.println("Given port doesn't work."); if (args.length != 0) System.out.println("Given port doesn't work.");
} }
// Start the server on port default port 25565 if none is given // Start the server on port default port 25565 if none is given
System.out.println("Running on " + IP + ":" + PORT); System.out.println("[Info] Running on " + IP + ":" + PORT);
minecraftServer.start(IP, PORT); minecraftServer.start(IP, PORT);
} }
} }

View File

@ -1,17 +1,23 @@
package eu.mhsl.craftattack.worldmuseum.commands; package eu.mhsl.craftattack.worldmuseum.commands;
import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer;
import eu.mhsl.craftattack.worldmuseum.worlds.World; import eu.mhsl.craftattack.worldmuseum.worlds.World;
import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Player;
public class SpawnCommand extends Command { public class SpawnCommand extends Command {
public SpawnCommand() { public SpawnCommand() {
super("spawn"); super("spawn");
setDefaultExecutor((sender, context) -> { setDefaultExecutor((sender, context) -> {
Player p = (Player) sender; if(sender instanceof MuseumPlayer p) {
World world = (World) p.getInstance(); teleportToSpawn(p);
assert world != null; }
p.teleport(world.getSpawn());
}); });
} }
public static void teleportToSpawn(MuseumPlayer p) {
if(p.getInstance() instanceof World world) {
p.startLoading();
p.teleport(world.getSpawn()).thenRun(p::stopLoading);
}
}
} }

View File

@ -11,22 +11,23 @@ public class TeleportCommand extends Command {
public TeleportCommand() { public TeleportCommand() {
super("tp"); super("tp");
var cordinate = ArgumentType.RelativeBlockPosition("Koordinate"); var coordinate = ArgumentType.RelativeBlockPosition("cords");
addSyntax(((sender, context) -> { addSyntax(((sender, context) -> {
Pos pos = context.get(cordinate).fromSender(sender).asPosition(); Pos pos = context.get(coordinate).fromSender(sender).asPosition();
Player player = (Player) sender; Player player = (Player) sender;
player.teleport(pos); 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) -> { 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 targetPlayer = (Player) context.get(playerArgument).find(sender).get(0);
Player p = (Player) sender; 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()); p.setInstance(Objects.requireNonNull(targetPlayer.getInstance()), targetPlayer.getPosition());
else } else {
p.teleport(targetPlayer.getPosition()); p.teleport(targetPlayer.getPosition());
}
}), playerArgument); }), playerArgument);
} }
} }

View File

@ -1,3 +0,0 @@
{
"start_world": "world"
}

View File

@ -11,7 +11,6 @@ import java.util.Collection;
public class SignHandler implements BlockHandler { public class SignHandler implements BlockHandler {
@Override @Override
public @NotNull Collection<Tag<?>> getBlockEntityTags() { public @NotNull Collection<Tag<?>> getBlockEntityTags() {
return new ArrayList<>() { return new ArrayList<>() {
{ {
add(Tag.Byte("GlowingText")); add(Tag.Byte("GlowingText"));

View File

@ -0,0 +1,68 @@
package eu.mhsl.craftattack.worldmuseum.inventory;
import eu.mhsl.craftattack.worldmuseum.util.BunggeCordComunicator;
import eu.mhsl.craftattack.worldmuseum.util.Config;
import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer;
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.MinecraftServer;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.timer.TaskSchedule;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class WorldSelector extends Inventory {
public WorldSelector() {
super(InventoryType.CHEST_1_ROW, Component.text("Weltenauswahl").color(NamedTextColor.DARK_GRAY));
// Limit to seven worlds, so no overflow occurs // TODO make inventory bigger when more items are added
List<World> worlds = WorldManager
.getInstance()
.getWorlds()
.stream()
.limit(7)
.toList();
Map<Integer, World> worldIndex = IntStream
.range(0, worlds.size())
.boxed()
.collect(Collectors.toMap(i -> i, worlds::get));
worldIndex.forEach((integer, world) -> setItemStack(integer, world.getItem()));
setItemStack(8, ItemStack.of(Material.IRON_DOOR).withDisplayName(Component.text("Zurück zum Server").color(NamedTextColor.GOLD)));
addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> {
MuseumPlayer player = (MuseumPlayer) p;
inventoryConditionResult.setCancel(true);
if(player.isLoading()) return;
// leave World-Museum
if(slot == 8) {
player.closeInventory();
player.startLoading();
BunggeCordComunicator.connect(player, Config.getInstance().getBungeeReturnServerName());
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
if(player.isOnline()) player.kick("Timeout beim Serverwechsel. Bitte joine dem Server erneut!");
}, TaskSchedule.seconds(5), TaskSchedule.stop());
return;
}
// join any world
if(worldIndex.containsKey(slot)) {
player.closeInventory();
worldIndex.get(slot).movePlayer(player);
}
});
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -3,6 +3,7 @@ package eu.mhsl.craftattack.worldmuseum.listener;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.minestom.server.event.player.PlayerBlockBreakEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -12,6 +13,8 @@ public class BlockBreakListener implements Consumer<PlayerBlockBreakEvent> {
public void accept(PlayerBlockBreakEvent playerBlockBreakEvent) { public void accept(PlayerBlockBreakEvent playerBlockBreakEvent) {
Block block = playerBlockBreakEvent.getBlock(); Block block = playerBlockBreakEvent.getBlock();
Point point = playerBlockBreakEvent.getBlockPosition(); 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());
} }
} }

View File

@ -1,14 +1,25 @@
package eu.mhsl.craftattack.worldmuseum.listener; 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 net.minestom.server.event.player.PlayerBlockPlaceEvent;
import java.util.Objects; import net.minestom.server.event.player.PlayerUseItemEvent;
import java.util.function.Consumer; import java.util.function.Consumer;
public class BlockPlaceListener implements Consumer<PlayerBlockPlaceEvent> { public class BlockPlaceListener implements Consumer<PlayerBlockPlaceEvent> {
@Override @Override
public void accept(PlayerBlockPlaceEvent playerBlockPlaceEvent) { 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); playerBlockPlaceEvent.setCancelled(true);
} }
} }

View File

@ -10,7 +10,7 @@ public class ChunkUnloading implements Consumer<PlayerChunkUnloadEvent> {
var chunk = e.getInstance().getChunk(e.getChunkX(), e.getChunkZ()); var chunk = e.getInstance().getChunk(e.getChunkX(), e.getChunkZ());
if (chunk == null) return; if (chunk == null) return;
if (chunk.getViewers().size() == 0) { if (chunk.getViewers().isEmpty()) {
try { try {
e.getInstance().unloadChunk(e.getChunkX(), e.getChunkZ()); e.getInstance().unloadChunk(e.getChunkX(), e.getChunkZ());
} catch (NullPointerException ignored) {} } catch (NullPointerException ignored) {}

View File

@ -6,6 +6,6 @@ import java.util.function.Consumer;
public class DisconnectListener implements Consumer<PlayerDisconnectEvent> { public class DisconnectListener implements Consumer<PlayerDisconnectEvent> {
@Override @Override
public void accept(PlayerDisconnectEvent playerDisconnectEvent) { public void accept(PlayerDisconnectEvent playerDisconnectEvent) {
System.out.println("[Join] Player " + playerDisconnectEvent.getPlayer().getUsername() +" left the server."); System.out.println("[Disconnect] Player " + playerDisconnectEvent.getPlayer().getUsername() +" left the server.");
} }
} }

View File

@ -1,29 +1,12 @@
package eu.mhsl.craftattack.worldmuseum.listener; 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 net.minestom.server.event.inventory.InventoryPreClickEvent;
import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
public class InventoryClickListener implements Consumer<InventoryPreClickEvent> { public class InventoryClickListener implements Consumer<InventoryPreClickEvent> {
@Override @Override
public void accept(InventoryPreClickEvent inventoryPreClickEvent) { 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); inventoryPreClickEvent.setCancelled(true);
} }
} }

View File

@ -1,37 +1,18 @@
package eu.mhsl.craftattack.worldmuseum.listener; package eu.mhsl.craftattack.worldmuseum.listener;
import eu.mhsl.craftattack.worldmuseum.items.ItemManager; import eu.mhsl.craftattack.worldmuseum.items.ActionItem;
import eu.mhsl.craftattack.worldmuseum.util.MuseumPlayer;
import eu.mhsl.craftattack.worldmuseum.worlds.World;
import net.kyori.adventure.text.Component;
import net.minestom.server.event.player.PlayerUseItemEvent; import net.minestom.server.event.player.PlayerUseItemEvent;
import net.minestom.server.item.ItemStack;
import java.util.function.Consumer; import java.util.function.Consumer;
public class ItemUseListener implements Consumer<PlayerUseItemEvent> { public class ItemUseListener implements Consumer<PlayerUseItemEvent> {
@Override @Override
public void accept(PlayerUseItemEvent playerUseItemEvent) { public void accept(PlayerUseItemEvent playerUseItemEvent) {
MuseumPlayer p = (MuseumPlayer) playerUseItemEvent.getPlayer(); if(playerUseItemEvent.getItemStack().hasTag(ActionItem.tag)) {
ItemStack usedItem = playerUseItemEvent.getItemStack(); ActionItem.run(playerUseItemEvent.getItemStack().getTag(ActionItem.tag), playerUseItemEvent.getPlayer());
}
if (usedItem.equals(ItemManager.getCompassItem())) compassUse(p);
else if (usedItem.equals(ItemManager.getBedItem())) bedUse(p);
playerUseItemEvent.setCancelled(true); 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());
}
} }

View File

@ -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);
}
}

View File

@ -0,0 +1,16 @@
package eu.mhsl.craftattack.worldmuseum.util;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
public class BunggeCordComunicator {
private static final String bungeeTargetSelector = "bungeecord:main";
public static void connect(Player p, String bungeeServerTargetName) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(bungeeServerTargetName);
p.sendPacket(new PluginMessagePacket(bungeeTargetSelector, out.toByteArray()));
}
}

View File

@ -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() +".");
}
}

View File

@ -2,8 +2,6 @@ package eu.mhsl.craftattack.worldmuseum.util;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import eu.mhsl.craftattack.worldmuseum.worlds.World;
import eu.mhsl.craftattack.worldmuseum.worlds.WorldManager;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
@ -11,37 +9,32 @@ import java.io.IOException;
public class Config { public class Config {
private static Config instance; private static Config instance;
private World start_world; private boolean bungeecordEnabled = false;
private String bungeeReturnServerName;
public static Config getInstance() { public static Config getInstance() {
if (instance == null) instance = new Config(); if (instance == null) instance = new Config();
return instance; return instance;
} }
public void loadConfig() { public void loadConfig() {
checkConfig(); createDefaultIfNotExists();
try { try {
JsonObject config = (JsonObject) JsonParser.parseReader(new FileReader("config.json")); JsonObject config = (JsonObject) JsonParser.parseReader(new FileReader("config.json"));
for (World w : WorldManager.getInstance().getWorlds()) { this.bungeecordEnabled = config.get("bungeecord").getAsBoolean();
if (!w.getName().equals(config.get("start_world").getAsString())) continue; this.bungeeReturnServerName = config.get("bc-return-servername").getAsString();
this.start_world = w;
}
if (start_world == null) {
System.out.println("no starting world set");
System.exit(0);
}
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private void checkConfig() { private void createDefaultIfNotExists() {
try { try {
File checkfile = new File("./config.json"); File checkfile = new File("./config.json");
if (checkfile.createNewFile()) { if (checkfile.createNewFile()) {
FileWriter fileWriter = new FileWriter("config.json"); FileWriter fileWriter = new FileWriter("config.json");
String default_config = """ String default_config = """
{ {
"start_world": "world" "bc-return-servername": "server",
"bungeecord": false
}"""; }""";
fileWriter.write(default_config); fileWriter.write(default_config);
fileWriter.close(); fileWriter.close();
@ -51,7 +44,11 @@ public class Config {
} }
} }
public World getStart_world() { public boolean isBungeecordEnabled() {
return start_world; return bungeecordEnabled;
}
public String getBungeeReturnServerName() {
return bungeeReturnServerName;
} }
} }

View File

@ -1,70 +1,68 @@
package eu.mhsl.craftattack.worldmuseum.util; 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.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.title.Title;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.inventory.Inventory; import net.minestom.server.event.player.PlayerMoveEvent;
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.network.player.PlayerConnection; 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.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.Duration; import java.time.Duration;
import java.util.UUID; import java.util.UUID;
public class MuseumPlayer extends Player { public class MuseumPlayer extends Player {
private boolean isLoading = false;
private boolean allowMovement = true;
private long lastCompassUsage = 0;
private boolean allowCompassUsage = true;
public MuseumPlayer(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection playerConnection) { public MuseumPlayer(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection playerConnection) {
super(uuid, username, playerConnection); super(uuid, username, playerConnection);
}
public void setSyncCooldown(@Nullable Duration cooldown) { eventNode().addListener(PlayerMoveEvent.class, playerMoveEvent -> playerMoveEvent.setCancelled(isLoading));
this.setCustomSynchronizationCooldown(cooldown);
} }
public boolean isAllowMovement() { public void startLoading() {
return allowMovement; isLoading = true;
MinecraftServer.getSchedulerManager().submitTask(() -> {
addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 3, 600));
showTitle(Title.title(
Component.text("Welt wird geladen").color(NamedTextColor.GOLD),
Component.text("...").color(NamedTextColor.GOLD),
Title.Times.times(Duration.ZERO, Duration.ofSeconds(30), Duration.ZERO)
));
if(!isLoading) {
clearEffects();
clearTitle();
return TaskSchedule.stop();
} }
public void update_lastCompassUsage() { return TaskSchedule.millis(100);
lastCompassUsage = System.currentTimeMillis(); }, ExecutionType.ASYNC);
}
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;
}
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;
} }
public void stopLoading() {
isLoading = false;
}
public boolean isLoading() {
return isLoading;
}
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))
);
}
} }

View File

@ -5,9 +5,7 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.adventure.audience.Audiences;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.monitoring.TickMonitor;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.atomic.AtomicReference;
public class TablistUpdateTask implements Runnable { public class TablistUpdateTask implements Runnable {
@Override @Override
@ -18,7 +16,7 @@ public class TablistUpdateTask implements Runnable {
final Component header = final Component header =
Component.newline() Component.newline()
.append(Component.text(" Welten-Museum ", NamedTextColor.GOLD)) .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()); .append(Component.newline());
final Component footer = final Component footer =

View File

@ -0,0 +1,7 @@
package eu.mhsl.craftattack.worldmuseum.worlds;
import net.minestom.server.entity.Player;
public interface PlayerMovable {
void movePlayer(Player p);
}

View File

@ -0,0 +1,54 @@
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;
museumPlayer.startLoading();
if(p.getInstance() != this) {
p.setInstance(this).thenRun(() -> onTpComplete(museumPlayer));
} else {
onTpComplete(museumPlayer);
}
p.getInventory().clear();
p.setRespawnPoint(getSpawn());
p.setAllowFlying(false);
}
private void onTpComplete(MuseumPlayer p) {
p.teleport(getSpawn());
p.openInventory(new WorldSelector());
p.stopLoading();
}
}

View File

@ -1,38 +1,87 @@
package eu.mhsl.craftattack.worldmuseum.worlds; package eu.mhsl.craftattack.worldmuseum.worlds;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; 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.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos; 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.AnvilLoader;
import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import net.minestom.server.world.DimensionType; import net.minestom.server.world.DimensionType;
import java.io.*; import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; 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:worldview_by_olischma")).height(400).ambientLight(2.0f).build(); 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 final boolean enabled;
private Pos spawn = new Pos(0,0,0); private final String name;
private boolean enabled = false; private final Material material;
private final Pos spawn;
private final List<String> tags = new ArrayList<>();
static { static {
MinecraftServer.getDimensionTypeManager().addDimension(dimension); MinecraftServer.getDimensionTypeManager().addDimension(dimension);
} }
AnvilLoader anvilLoader;
public World(File file) { public World(File file) throws IOException {
super(UUID.randomUUID(), dimension, new AnvilLoader(file.getPath())); super(UUID.randomUUID(), dimension, new AnvilLoader(file.getPath()));
this.anvilLoader = new AnvilLoader(file.getPath());
MinecraftServer.getInstanceManager().registerInstance(this); MinecraftServer.getInstanceManager().registerInstance(this);
try {
File checkFile = new File(file.getPath() + "/config.json"); File configFile = new File(file.getPath() + "/config.json");
if (checkFile.createNewFile()) { if (configFile.createNewFile()) {
writeDefaultConfig(file);
}
JsonObject config = (JsonObject) JsonParser.parseReader(new FileReader(file.getPath() + "/config.json"));
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"); FileWriter fileWriter = new FileWriter(file.getPath() + "/config.json");
String defaultConfig = """ String defaultConfig = """
{ {
@ -51,28 +100,9 @@ public class World extends InstanceContainer {
fileWriter.write(defaultConfig); fileWriter.write(defaultConfig);
fileWriter.close(); fileWriter.close();
} }
} catch (IOException e){
e.printStackTrace();
}
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();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
assert material != null;
item = ItemStack.builder(material).displayName(Component.text(name)).build();
}
public ItemStack getItem() { public ItemStack getItem() {
return item; return ItemStack.builder(material).displayName(Component.text(name)).build();
} }
public String getName() { public String getName() {

View File

@ -1,7 +1,9 @@
package eu.mhsl.craftattack.worldmuseum.worlds; package eu.mhsl.craftattack.worldmuseum.worlds;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
public class WorldManager { public class WorldManager {
@ -14,11 +16,11 @@ public class WorldManager {
} }
return instance; return instance;
} }
public void loadWorlds() { public void loadWorlds() throws IOException {
File saveDirectory = new File("saves"); File saveDirectory = new File("saves");
List<File> worldFolders = getFolderNames(saveDirectory); if(!saveDirectory.exists()) throw new IOException("Saves folder 'saves' could not be found!");
for (File f: worldFolders List<File> worldFolders = getFolders(saveDirectory);
) { for (File f : worldFolders) {
World w = new World(f); World w = new World(f);
if (w.isEnabled()) { if (w.isEnabled()) {
worlds.add(w); worlds.add(w);
@ -26,16 +28,14 @@ public class WorldManager {
System.out.println("Es gibt eine nicht aktivierte Welt: " + f); System.out.println("Es gibt eine nicht aktivierte Welt: " + f);
} }
} }
} }
private List<File> getFolderNames(File curDir) { private List<File> getFolders(File directory) {
File[] fileList = curDir.listFiles(); File[] fileList = directory.listFiles();
List<File> returnFolders = new ArrayList<>(); if(fileList == null) return new ArrayList<>();
assert fileList != null;
for (File f: fileList) { return Arrays.stream(fileList).filter(File::isDirectory).toList();
if (f.isDirectory()) returnFolders.add(f);
}
return returnFolders;
} }
public List<World> getWorlds() { public List<World> getWorlds() {

View File

@ -1,13 +0,0 @@
{
"enabled": false,
"name": "DEFAULT_NAME",
"material": "GRASS_BLOCK",
"spawn": {
"x": 0,
"y": 0,
"z": 0
},
"tags": [
"RANDOM_TAG"
]
}