package games.dmg.spigotbase; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.function.Function; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.block.Biome; final class PocketBaseWorldService { private static final int PLATFORM_Y = 64; private static final String WORLD_PREFIX = "spigot_base_pocket_"; private final Server server; private final PluginSettingsProvider settings; private final PocketBasePolicy policy; private final Function biomeResolver; private final Map ownersByWorld = new HashMap<>(); PocketBaseWorldService(Server server, PluginSettingsProvider settings) { this(server, settings, biome -> resolveBiome(server, biome)); } PocketBaseWorldService( Server server, PluginSettingsProvider settings, Function biomeResolver ) { this.server = server; this.settings = settings; this.policy = new PocketBasePolicy(settings); this.biomeResolver = biomeResolver; } void loadExisting(Map states) { for (PocketBaseState state : states.values()) { if (state.level() > 0) { setBiome(state.ownerId(), state.level(), state.biome()); setMobSpawning( state.ownerId(), state.hostileMobSpawningEnabled(), state.passiveMobSpawningEnabled() ); } } } World expand(UUID ownerId, int previousLevel, int newLevel) { return expand(ownerId, previousLevel, newLevel, PocketBaseBiome.THE_VOID); } World expand( UUID ownerId, int previousLevel, int newLevel, PocketBaseBiome biome ) { World world = ensureWorld(ownerId); int newHalfSize = policy.size(newLevel) / 2; int previousHalfSize = previousLevel == 0 ? 0 : policy.size(previousLevel) / 2; for (int x = -newHalfSize; x < newHalfSize; x++) { for (int z = -newHalfSize; z < newHalfSize; z++) { boolean previouslyUnlocked = previousLevel > 0 && x >= -previousHalfSize && x < previousHalfSize && z >= -previousHalfSize && z < previousHalfSize; if (previouslyUnlocked) { continue; } for (int y = PLATFORM_Y - 3; y < PLATFORM_Y; y++) { world.getBlockAt(x, y, z).setType(Material.DIRT, false); } world.getBlockAt(x, PLATFORM_Y, z).setType(Material.GRASS_BLOCK, false); } } applyBiome(world, previousLevel, newLevel, biome); if (previousLevel == 0) { createReturnPortal(world); world.setSpawnLocation(0, PLATFORM_Y + 1, 5); } world.save(); return world; } Optional ownerForWorld(UUID worldId) { return Optional.ofNullable(ownersByWorld.get(worldId)); } World world(UUID ownerId) { return ensureWorld(ownerId); } void setMobSpawning( UUID ownerId, boolean hostileEnabled, boolean passiveEnabled ) { ensureWorld(ownerId).setSpawnFlags(hostileEnabled, passiveEnabled); } void setBiome(UUID ownerId, int level, PocketBaseBiome biome) { World world = ensureWorld(ownerId); applyBiome(world, 0, level, biome); world.save(); } Location arrival(UUID ownerId) { return new Location(ensureWorld(ownerId), 0.5, PLATFORM_Y + 1, 5.5, 180.0f, 0.0f); } PocketPortalLocation returnPortal(UUID ownerId) { World world = ensureWorld(ownerId); return new PocketPortalLocation( world.getUID(), world.getName(), -2, PLATFORM_Y + 1, 0, PocketPortalAxis.X ); } boolean returnPortalIsIntact(UUID ownerId, PocketPortalLocation portal) { World world = ensureWorld(ownerId); if (!portal.worldId().equals(world.getUID())) { return false; } Material frame = Material.valueOf(settings.current().pocketBasePortalFrameMaterial()); return PocketPortalGeometry.frameBlocks(portal).stream() .allMatch(position -> world.getBlockAt( position.x(), position.y(), position.z() ).getType() == frame); } private World ensureWorld(UUID ownerId) { String name = worldName(ownerId); World world = server.getWorld(name); boolean created = world == null; if (created) { WorldCreator creator = new WorldCreator(NamespacedKey.minecraft(name)) .environment(World.Environment.NORMAL) .generator(new VoidPocketChunkGenerator()) .generateStructures(false); world = server.createWorld(creator); } if (world == null) { throw new IllegalStateException("Could not create Pocket Base world " + name); } if (created) { world.setSpawnFlags(false, false); } ownersByWorld.put(world.getUID(), ownerId); return world; } private void applyBiome( World world, int previousLevel, int newLevel, PocketBaseBiome selectedBiome ) { int newHalfSize = policy.size(newLevel) / 2; int previousHalfSize = previousLevel == 0 ? 0 : policy.size(previousLevel) / 2; Biome biome = biomeResolver.apply(selectedBiome); for (int x = -newHalfSize; x < newHalfSize; x += 4) { for (int z = -newHalfSize; z < newHalfSize; z += 4) { boolean previouslyUnlocked = previousLevel > 0 && x >= -previousHalfSize && x < previousHalfSize && z >= -previousHalfSize && z < previousHalfSize; if (previouslyUnlocked) { continue; } for (int y = world.getMinHeight(); y < world.getMaxHeight(); y += 4) { world.setBiome(x, y, z, biome); } } } } private static Biome resolveBiome(Server server, PocketBaseBiome selectedBiome) { Registry biomeRegistry = server.getRegistry(Biome.class); if (biomeRegistry == null) { throw new IllegalStateException("Biome registry is unavailable"); } return biomeRegistry.getOrThrow( NamespacedKey.minecraft(selectedBiome.commandName()) ); } private void createReturnPortal(World world) { PocketPortalLocation portal = new PocketPortalLocation( world.getUID(), world.getName(), -2, PLATFORM_Y + 1, 0, PocketPortalAxis.X ); Material frame = Material.valueOf(settings.current().pocketBasePortalFrameMaterial()); for (BlockPosition position : PocketPortalGeometry.frameBlocks(portal)) { world.getBlockAt(position.x(), position.y(), position.z()).setType(frame, false); } } private static String worldName(UUID ownerId) { return WORLD_PREFIX + ownerId.toString().replace("-", ""); } }