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">
<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$" />

1
.idea/misc.xml generated
View File

@ -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">

View File

@ -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,25 @@ repositories {
}
dependencies {
implementation 'com.github.Minestom:Minestom:8ad2c7701f'
implementation 'com.github.waxeria:Minestom:e0427a36f3'
implementation 'org.jctools:jctools-core:4.0.1'
implementation 'com.google.guava:guava:31.0.1-jre'
}
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("")
}
}

View File

@ -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;
@ -18,19 +17,21 @@ import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.inventory.InventoryPreClickEvent;
import net.minestom.server.event.item.ItemDropEvent;
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();
MinecraftServer.getConnectionManager().setPlayerProvider(MuseumPlayer::new);
MinecraftServer.setBrandName("mhsl.eu:worldmuseum_by_olischma");
//update Taskbar
MinecraftServer.getSchedulerManager().scheduleTask(new TablistUpdateTask(), TaskSchedule.tick(20), TaskSchedule.tick(20));
@ -43,9 +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
@ -53,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());
@ -71,16 +74,18 @@ public class Main {
globalEventHandler.addListener(PlayerLoginEvent.class, event -> {
final MuseumPlayer player = (MuseumPlayer) event.getPlayer();
player.setSyncCooldown(Duration.ofSeconds(3));
SkinCache.setSkin(player);
event.setSpawningInstance(startworld);
final VoidWorld voidWorld = new VoidWorld();
event.setSpawningInstance(voidWorld);
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> {
player.setPermissionLevel(4);
player.setRespawnPoint(voidWorld.getSpawn());
player.setGameMode(GameMode.SPECTATOR);
player.setAllowFlying(true);
SkinCache.setSkin(player);
voidWorld.movePlayer(player);
});
player.setPermissionLevel(4);
player.setRespawnPoint(startworld.getSpawn());
player.setGameMode(GameMode.SURVIVAL);
player.setAllowFlying(true);
player.getInventory().setItemStack(0, ItemManager.getCompassItem());
player.getInventory().setItemStack(8, ItemManager.getBedItem());
System.out.println("[Join] Player " + player.getUsername() +" joined the server.");
});
@ -89,8 +94,9 @@ 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("Running on " + IP + ":" + PORT);
System.out.println("[Info] Running on " + IP + ":" + PORT);
minecraftServer.start(IP, PORT);
}
}

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -6,6 +6,6 @@ import java.util.function.Consumer;
public class DisconnectListener implements Consumer<PlayerDisconnectEvent> {
@Override
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;
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);
}
}

View File

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

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.JsonParser;
import eu.mhsl.craftattack.worldmuseum.worlds.World;
import eu.mhsl.craftattack.worldmuseum.worlds.WorldManager;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
@ -11,37 +9,32 @@ import java.io.IOException;
public class Config {
private static Config instance;
private World start_world;
private boolean bungeecordEnabled = false;
private String bungeeReturnServerName;
public static Config getInstance() {
if (instance == null) instance = new Config();
return instance;
}
public void loadConfig() {
checkConfig();
createDefaultIfNotExists();
try {
JsonObject config = (JsonObject) JsonParser.parseReader(new FileReader("config.json"));
for (World w : WorldManager.getInstance().getWorlds()) {
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);
}
}catch (IOException e) {
this.bungeecordEnabled = config.get("bungeecord").getAsBoolean();
this.bungeeReturnServerName = config.get("bc-return-servername").getAsString();
} catch (IOException e) {
e.printStackTrace();
}
}
private void checkConfig() {
private void createDefaultIfNotExists() {
try {
File checkfile = new File("./config.json");
if (checkfile.createNewFile()) {
FileWriter fileWriter = new FileWriter("config.json");
String default_config = """
{
"start_world": "world"
"bc-return-servername": "server",
"bungeecord": false
}""";
fileWriter.write(default_config);
fileWriter.close();
@ -51,7 +44,11 @@ public class Config {
}
}
public World getStart_world() {
return start_world;
public boolean isBungeecordEnabled() {
return bungeecordEnabled;
}
public String getBungeeReturnServerName() {
return bungeeReturnServerName;
}
}

View File

@ -1,70 +1,68 @@
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.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(() -> {
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();
}
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 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.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 =

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,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 {
private final static DimensionType dimension = DimensionType.builder(NamespaceID.from("mhsl: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;
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 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() {

View File

@ -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() {

View File

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