Files
purpur-base/src/main/java/games/dmg/spigotbase/PocketBaseWorldService.java
T
dmg 29413d36b3
Release / release (push) Successful in 5m29s
CI / build (push) Successful in 1m28s
fix(settings): use Purpur dialog API
2026-08-24 11:25:01 -04:00

204 lines
7.2 KiB
Java

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<PocketBaseBiome, Biome> biomeResolver;
private final Map<UUID, UUID> ownersByWorld = new HashMap<>();
PocketBaseWorldService(Server server, PluginSettingsProvider settings) {
this(server, settings, biome -> resolveBiome(server, biome));
}
PocketBaseWorldService(
Server server,
PluginSettingsProvider settings,
Function<PocketBaseBiome, Biome> biomeResolver
) {
this.server = server;
this.settings = settings;
this.policy = new PocketBasePolicy(settings);
this.biomeResolver = biomeResolver;
}
void loadExisting(Map<UUID, PocketBaseState> 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<UUID> 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<Biome> 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("-", "");
}
}