diff --git a/api/src/main/java/ru/dragonestia/msb3/api/module/PreloadedWorldModule.java b/api/src/main/java/ru/dragonestia/msb3/api/module/PreloadedWorldModule.java new file mode 100644 index 0000000..09e4a8a --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/module/PreloadedWorldModule.java @@ -0,0 +1,63 @@ +package ru.dragonestia.msb3.api.module; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.GameMode; +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; +import net.minestom.server.event.player.PlayerDisconnectEvent; +import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.event.player.PlayerSpawnEvent; +import ru.dragonestia.msb3.api.world.World; +import ru.dragonestia.msb3.api.world.WorldFactory; + +import java.io.File; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +public class PreloadedWorldModule { + + private static boolean used = false; + + private PreloadedWorldModule() {} + + public static void init(File worldDir, GameMode gameMode, Pos spawnPos) { + init(worldDir, gameMode, () -> spawnPos); + } + + public static synchronized void init(File worldDir, GameMode gameMode, Supplier spawnPosSupplier) { + if (used) return; + used = true; + + var loadingWorld = MinecraftServer.getInstanceManager().createInstanceContainer(); + loadingWorld.eventNode().addListener(PlayerMoveEvent.class, event -> event.setCancelled(true)); + + var factory = WorldFactory.anvil(worldDir); + var worlds = new ConcurrentHashMap(); + + MinecraftServer.getGlobalEventHandler().addListener(AsyncPlayerConfigurationEvent.class, event -> { + var player = event.getPlayer(); + + player.setRespawnPoint(new Pos(0, 60, 0)); + player.setGameMode(gameMode); + + event.setSpawningInstance(loadingWorld); + }).addListener(PlayerSpawnEvent.class, event -> { + if (!event.isFirstSpawn()) return; + + var player = event.getPlayer(); + factory.createWorld().thenAccept(world -> { + worlds.put(player.getUuid(), world); + player.setInstance(world.getInstance(), spawnPosSupplier.get()); + }); + }).addListener(PlayerDisconnectEvent.class, event -> { + var player = event.getPlayer(); + var world = worlds.remove(player.getUuid()); + + if (world == null) return; + if (world.getInstance().getEntityTracker().entities().stream().filter(entity -> entity != player).count() == 0) { + world.unload(); + } + }); + } +}