Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Level builder #29

Merged
merged 10 commits into from
Aug 17, 2024
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package net.thenextlvl.worlds.api;

import net.thenextlvl.worlds.api.link.LinkController;
import net.thenextlvl.worlds.api.model.LevelBuilder;
import net.thenextlvl.worlds.api.view.GeneratorView;
import net.thenextlvl.worlds.api.view.LevelView;
import org.bukkit.plugin.Plugin;

import java.io.File;

public interface WorldsProvider extends Plugin {
GeneratorView generatorView();

LevelBuilder levelBuilder(File level);

LevelView levelView();

LinkController linkController();
Expand Down
39 changes: 39 additions & 0 deletions api/src/main/java/net/thenextlvl/worlds/api/model/Level.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package net.thenextlvl.worlds.api.model;

import core.nbt.file.NBTFile;
import core.nbt.tag.CompoundTag;
import net.kyori.adventure.key.Keyed;
import net.thenextlvl.worlds.api.preset.Preset;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;

public interface Level extends Keyed {
@Nullable Generator generator();

@Nullable Preset preset();

NBTFile<CompoundTag> levelData();

NamespacedKey key();

Optional<World> create();

String name();

World.Environment environment();

WorldPreset type();

boolean enabled();

boolean hardcore();

boolean importedBefore();

boolean structures();

long seed();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package net.thenextlvl.worlds.api.model;

import net.thenextlvl.worlds.api.preset.Preset;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.jetbrains.annotations.Nullable;

import java.io.File;

public interface LevelBuilder {
@Nullable Boolean hardcore();

@Nullable Boolean structures();

@Nullable Generator generator();

@Nullable Long seed();

@Nullable NamespacedKey key();

@Nullable Preset preset();

@Nullable String name();

@Nullable World.Environment environment();

@Nullable WorldPreset type();

File level();

LevelBuilder environment(@Nullable World.Environment environment);

LevelBuilder generator(@Nullable Generator generator);

LevelBuilder hardcore(@Nullable Boolean hardcore);

LevelBuilder key(@Nullable NamespacedKey key);

LevelBuilder name(@Nullable String name);

LevelBuilder preset(@Nullable Preset preset);

LevelBuilder seed(@Nullable Long seed);

LevelBuilder structures(@Nullable Boolean structures);

LevelBuilder type(@Nullable WorldPreset type);

Level build();
}
15 changes: 0 additions & 15 deletions api/src/main/java/net/thenextlvl/worlds/api/view/LevelView.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,13 @@
import net.thenextlvl.worlds.api.model.LevelExtras;
import net.thenextlvl.worlds.api.model.WorldPreset;
import net.thenextlvl.worlds.api.preset.Preset;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;

public interface LevelView {
@Nullable World loadLevel(File level);

@Nullable World loadLevel(File level, @Nullable NamespacedKey key, Predicate<Optional<LevelExtras>> predicate);

@Nullable World loadLevel(File level, Predicate<Optional<LevelExtras>> predicate);

@Nullable World loadLevel(File level, World.Environment environment);

@Nullable World loadLevel(File level, World.Environment environment, @Nullable NamespacedKey key, Predicate<Optional<LevelExtras>> predicate);

@Nullable World loadLevel(File level, World.Environment environment, Predicate<Optional<LevelExtras>> predicate);

NBTFile<CompoundTag> getLevelDataFile(File level);

Optional<LevelExtras> getExtras(CompoundTag data);
Expand Down
7 changes: 7 additions & 0 deletions plugin/src/main/java/net/thenextlvl/worlds/WorldsPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
import net.thenextlvl.worlds.api.WorldsProvider;
import net.thenextlvl.worlds.api.link.LinkController;
import net.thenextlvl.worlds.api.model.Generator;
import net.thenextlvl.worlds.api.model.LevelBuilder;
import net.thenextlvl.worlds.api.preset.Presets;
import net.thenextlvl.worlds.api.view.GeneratorView;
import net.thenextlvl.worlds.api.view.LevelView;
import net.thenextlvl.worlds.command.WorldCommand;
import net.thenextlvl.worlds.controller.WorldLinkController;
import net.thenextlvl.worlds.listener.PortalListener;
import net.thenextlvl.worlds.listener.ServerListener;
import net.thenextlvl.worlds.model.PaperLevelBuilder;
import net.thenextlvl.worlds.version.PluginVersionChecker;
import net.thenextlvl.worlds.view.PaperLevelView;
import net.thenextlvl.worlds.view.PluginGeneratorView;
Expand Down Expand Up @@ -78,6 +80,11 @@ public void onDisable() {
unloadWorlds();
}

@Override
public LevelBuilder levelBuilder(File level) {
return new PaperLevelBuilder(this, level);
}

private void unloadWorlds() {
getServer().getWorlds().stream().filter(world -> !world.isAutoSave()).forEach(world -> {
world.getPlayers().forEach(player -> player.kick(getServer().shutdownMessage()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.thenextlvl.worlds.WorldsPlugin;
import net.thenextlvl.worlds.api.model.Generator;
import net.thenextlvl.worlds.api.model.WorldPreset;
import net.thenextlvl.worlds.api.preset.Preset;
import net.thenextlvl.worlds.command.argument.*;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.concurrent.ThreadLocalRandom;

import static org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND;
Expand Down Expand Up @@ -50,7 +50,7 @@ class WorldCreateCommand {
true, ThreadLocalRandom.current().nextLong()))
.then(tree(this::createType))))
.executes(context -> create(context, World.Environment.NORMAL, true,
ThreadLocalRandom.current().nextLong(), WorldType.NORMAL, null, null)));
ThreadLocalRandom.current().nextLong(), WorldPreset.NORMAL, null, null)));
}

private RequiredArgumentBuilder<CommandSourceStack, World.Environment> tree(Creator<CommandSourceStack> creator) {
Expand All @@ -76,25 +76,25 @@ private RequiredArgumentBuilder<CommandSourceStack, World.Environment> tree(Crea
}

private int create(CommandContext<CommandSourceStack> context, World.Environment environment, boolean structures,
long seed, WorldType worldType, @Nullable Preset preset, @Nullable Generator generator) {
long seed, WorldPreset type, @Nullable Preset preset, @Nullable Generator generator) {
var key = context.getArgument("key", NamespacedKey.class);
var name = key.getKey();
var creator = new WorldCreator(name, key)
.environment(environment)
.generateStructures(structures)
.seed(seed)
.type(worldType);

if (preset != null) creator.generatorSettings(preset.serialize().toString());
var levelFolder = new File(plugin.getServer().getWorldContainer(), name);

if (generator != null) {
creator.generator(generator.plugin().getDefaultWorldGenerator(name, generator.id()));
creator.biomeProvider(generator.plugin().getDefaultBiomeProvider(name, generator.id()));
}
var level = plugin.levelBuilder(levelFolder)
.environment(environment)
.generator(generator)
.preset(preset)
.seed(seed)
.name(name)
.structures(structures)
.type(type)
.build();

var world = plugin.getServer().getWorld(creator.key()) == null
&& plugin.getServer().getWorld(name) == null
? creator.createWorld() : null;
var world = plugin.getServer().getWorld(level.key()) == null
&& plugin.getServer().getWorld(level.name()) == null
? level.create().orElse(null) : null;

var message = world != null ? "world.create.success" : "world.create.failed";
plugin.bundle().sendMessage(context.getSource().getSender(), message,
Expand All @@ -114,16 +114,16 @@ private int create(CommandContext<CommandSourceStack> context, World.Environment

private int createGenerator(CommandContext<CommandSourceStack> context, World.Environment environment, boolean structures, long seed) {
var generator = context.getArgument("generator", Generator.class);
return create(context, environment, structures, seed, WorldType.NORMAL, null, generator);
return create(context, environment, structures, seed, WorldPreset.NORMAL, null, generator);
}

private int createPreset(CommandContext<CommandSourceStack> context, World.Environment environment, boolean structures, long seed) {
var preset = context.getArgument("preset", Preset.class);
return create(context, environment, structures, seed, WorldType.FLAT, preset, null);
return create(context, environment, structures, seed, WorldPreset.FLAT, preset, null);
}

private int createType(CommandContext<CommandSourceStack> context, World.Environment environment, boolean structures, long seed) {
var type = context.getArgument("type", WorldType.class);
var type = context.getArgument("type", WorldPreset.class);
return create(context, environment, structures, seed, type, null, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.thenextlvl.worlds.WorldsPlugin;
import net.thenextlvl.worlds.api.model.Generator;
import net.thenextlvl.worlds.api.model.Level;
import net.thenextlvl.worlds.command.argument.DimensionArgument;
import net.thenextlvl.worlds.command.argument.GeneratorArgument;
import net.thenextlvl.worlds.command.suggestion.LevelSuggestionProvider;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
Expand All @@ -33,31 +36,39 @@ class WorldImportCommand {
.then(Commands.argument("world", StringArgumentType.string())
.suggests(new LevelSuggestionProvider<>(plugin))
.then(Commands.argument("key", ArgumentTypes.namespacedKey())
.executes(context -> {
var key = context.getArgument("key", NamespacedKey.class);
return execute(context, null, key);
}))
.then(Commands.argument("dimension", new DimensionArgument(plugin))
.then(Commands.argument("key", ArgumentTypes.namespacedKey())
.then(Commands.argument("dimension", new DimensionArgument(plugin))
.then(Commands.argument("generator", new GeneratorArgument(plugin))
.executes(context -> {
var environment = context.getArgument("dimension", World.Environment.class);
var generator = context.getArgument("generator", Generator.class);
var key = context.getArgument("key", NamespacedKey.class);
return execute(context, key, environment, generator);
}))
.executes(context -> {
var environment = context.getArgument("dimension", World.Environment.class);
var key = context.getArgument("key", NamespacedKey.class);
return execute(context, environment, key);
return execute(context, key, environment, null);
}))
.executes(context -> {
var environment = context.getArgument("dimension", World.Environment.class);
return execute(context, environment, null);
var key = context.getArgument("key", NamespacedKey.class);
return execute(context, key, null, null);
}))
.executes(context -> execute(context, null, null)));
.executes(context -> execute(context, null, null, null)));
}

private int execute(CommandContext<CommandSourceStack> context, @Nullable World.Environment environment, @Nullable NamespacedKey key) {
private int execute(CommandContext<CommandSourceStack> context, @Nullable NamespacedKey key,
@Nullable World.Environment environment, @Nullable Generator generator) {
var name = context.getArgument("world", String.class);
var level = new File(plugin.getServer().getWorldContainer(), name);
var levelFolder = new File(plugin.getServer().getWorldContainer(), name);

var build = plugin.levelView().isLevel(levelFolder)
? plugin.levelBuilder(levelFolder).environment(environment)
.generator(generator).key(key).build() : null;

var world = plugin.levelView().isLevel(level) ? environment != null
? plugin.levelView().loadLevel(level, environment, key, Optional::isEmpty)
: plugin.levelView().loadLevel(level, key, Optional::isEmpty) : null;
var world = Optional.ofNullable(build)
.filter(level -> !level.importedBefore())
.flatMap(Level::create)
.orElse(null);

var message = world != null ? "world.import.success" : "world.import.failed";
plugin.bundle().sendMessage(context.getSource().getSender(), message,
Expand All @@ -69,6 +80,7 @@ private int execute(CommandContext<CommandSourceStack> context, @Nullable World.

if (world != null) {
plugin.persistWorld(world, true);
if (generator != null) plugin.persistGenerator(world, generator);
plugin.levelView().saveLevelData(world, true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.thenextlvl.worlds.WorldsPlugin;
import net.thenextlvl.worlds.api.model.Level;
import net.thenextlvl.worlds.command.suggestion.LevelSuggestionProvider;
import org.bukkit.entity.Entity;

import java.io.File;
import java.util.Optional;

import static org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND;

Expand All @@ -33,8 +35,8 @@ private int load(CommandContext<CommandSourceStack> context) {
var name = context.getArgument("world", String.class);
var level = new File(plugin.getServer().getWorldContainer(), name);

var world = plugin.levelView().isLevel(level) ? plugin.levelView().loadLevel(level,
optional -> optional.map(extras -> !extras.enabled()).isPresent()) : null;
var build = plugin.levelView().isLevel(level) ? plugin.levelBuilder(level).build(): null;
var world = Optional.ofNullable(build).filter(Level::importedBefore).flatMap(Level::create).orElse(null);

var message = world != null ? "world.load.success" : "world.load.failed";
plugin.bundle().sendMessage(context.getSource().getSender(), message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@
import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
import net.kyori.adventure.key.Key;
import net.thenextlvl.worlds.WorldsPlugin;
import net.thenextlvl.worlds.api.model.WorldPreset;
import net.thenextlvl.worlds.command.suggestion.WorldTypeSuggestionProvider;
import org.bukkit.WorldType;

@SuppressWarnings("UnstableApiUsage")
public class WorldTypeArgument extends WrappedArgumentType<Key, WorldType> {
public class WorldTypeArgument extends WrappedArgumentType<Key, WorldPreset> {
public WorldTypeArgument(WorldsPlugin plugin) {
super(ArgumentTypes.key(), (reader, type) -> switch (type.asString()) {
case "minecraft:amplified" -> WorldType.AMPLIFIED;
case "minecraft:flat" -> WorldType.FLAT;
case "minecraft:large_biomes" -> WorldType.LARGE_BIOMES;
case "minecraft:normal" -> WorldType.NORMAL;
// case "minecraft:single_biome" -> ;
// case "minecraft:debug_world" -> ;
super(ArgumentTypes.key(), (reader, type) -> switch (type.asMinimalString()) {
case "amplified" -> WorldPreset.AMPLIFIED;
case "checkerboard" -> WorldPreset.CHECKERBOARD;
case "debug_all_block_states", "debug_world", "debug" -> WorldPreset.DEBUG;
case "fixed", "single_biome" -> WorldPreset.SINGLE_BIOME;
case "flat" -> WorldPreset.FLAT;
case "large_biomes" -> WorldPreset.LARGE_BIOMES;
case "noise", "normal", "default" -> WorldPreset.NORMAL;
default -> throw new IllegalArgumentException("Custom dimensions are not yet supported");
}, new WorldTypeSuggestionProvider(plugin));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ public class WorldTypeSuggestionProvider implements SuggestionProvider {

private final Map<String, String> dimensions = Map.of(
"minecraft:amplified", "world.type.amplified",
"minecraft:checkerboard", "world.type.checkerboard",
"minecraft:debug", "world.type.debug",
"minecraft:flat", "world.type.flat",
"minecraft:large_biomes", "world.type.large_biomes",
"minecraft:normal", "world.type.normal"
"minecraft:normal", "world.type.normal",
"minecraft:single_biome", "world.type.single_biome"
);

@Override
Expand Down
Loading
Loading