Skip to content

Commit

Permalink
Merge pull request #22 from TheNextLvl-net/updates
Browse files Browse the repository at this point in the history
Updates
  • Loading branch information
NonSwag authored Aug 15, 2024
2 parents 9f4ab02 + 42857f0 commit 26eafdc
Show file tree
Hide file tree
Showing 16 changed files with 109 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import net.thenextlvl.worlds.api.link.LinkController;
import net.thenextlvl.worlds.api.view.GeneratorView;
import net.thenextlvl.worlds.api.view.LevelView;
import org.bukkit.plugin.Plugin;

public interface WorldsProvider {
public interface WorldsProvider extends Plugin {
GeneratorView generatorView();

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

import com.google.common.base.Preconditions;
import net.thenextlvl.worlds.api.WorldsProvider;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;

public record Generator(Plugin plugin, @Nullable String id) {
public String serialize() {
return id != null ? plugin.getName() + ":" + id : plugin.getName();
}

public static Generator deserialize(WorldsProvider provider, String serialized) {
var split = serialized.split(":", 2);
var generator = provider.getServer().getPluginManager().getPlugin(split[0]);
Preconditions.checkNotNull(generator, "Unknown plugin");
Preconditions.checkState(generator.isEnabled(), "Plugin is not enabled");
Preconditions.checkState(provider.generatorView().hasGenerator(generator), "Plugin has no generator");
return new Generator(generator, split.length > 1 ? split[1] : null);
}

public @Nullable ChunkGenerator generator(String worldName) {
return plugin().getDefaultWorldGenerator(worldName, id());
}

public @Nullable BiomeProvider biomeProvider(String worldName) {
return plugin().getDefaultBiomeProvider(worldName, id());
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package net.thenextlvl.worlds.api.model;

import net.thenextlvl.worlds.api.view.GeneratorView;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.Nullable;

public record LevelExtras(
@Nullable NamespacedKey key,
@Nullable Generator generator,
boolean enabled
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public interface LevelView {

Optional<Preset> getFlatPreset(CompoundTag generator);

Optional<String> getGenerator(World world);

Optional<String> getGeneratorSettings(CompoundTag generator);

Optional<String> getGeneratorType(CompoundTag generator);
Expand Down
19 changes: 15 additions & 4 deletions plugin/src/main/java/net/thenextlvl/worlds/WorldsPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
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.preset.Presets;
import net.thenextlvl.worlds.api.view.GeneratorView;
import net.thenextlvl.worlds.api.view.LevelView;
Expand Down Expand Up @@ -85,10 +86,20 @@ private void unloadWorlds() {
}

public void persistWorld(World world, boolean enabled) {
if (world.key().asString().equals("minecraft:overworld")) return;
var container = world.getPersistentDataContainer();
container.set(new NamespacedKey("worlds", "world_key"), STRING, world.getKey().asString());
container.set(new NamespacedKey("worlds", "enabled"), BOOLEAN, enabled);
var worldKey = new NamespacedKey("worlds", "world_key");
world.getPersistentDataContainer().set(worldKey, STRING, world.getKey().asString());
persistStatus(world, enabled, true);
}

public void persistStatus(World world, boolean enabled, boolean force) {
var enabledKey = new NamespacedKey("worlds", "enabled");
if (!force && !world.getPersistentDataContainer().has(enabledKey)) return;
world.getPersistentDataContainer().set(enabledKey, BOOLEAN, enabled);
}

public void persistGenerator(World world, Generator generator) {
var generatorKey = new NamespacedKey("worlds", "generator");
world.getPersistentDataContainer().set(generatorKey, STRING, generator.serialize());
}

private void registerServices() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
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.preset.Preset;
import net.thenextlvl.worlds.command.argument.*;
import org.bukkit.NamespacedKey;
Expand Down Expand Up @@ -75,7 +76,7 @@ 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 GeneratorArgument.Generator generator) {
long seed, WorldType worldType, @Nullable Preset preset, @Nullable Generator generator) {
var key = context.getArgument("key", NamespacedKey.class);
var name = key.getKey();
var creator = new WorldCreator(name, key)
Expand Down Expand Up @@ -104,14 +105,15 @@ private int create(CommandContext<CommandSourceStack> context, World.Environment

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

return world != null ? Command.SINGLE_SUCCESS : 0;
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
Expand Down Expand Up @@ -67,18 +66,10 @@ private int list(CommandSender sender, World world) {
.orElse(WorldType.NORMAL).getName().toLowerCase()));
plugin.bundle().sendMessage(sender, "world.info.dimension",
Placeholder.parsed("dimension", environment.orElse("unknown")));
getGenerator(world).ifPresent(gen -> plugin.bundle().sendMessage(sender,
plugin.levelView().getGenerator(world).ifPresent(gen -> plugin.bundle().sendMessage(sender,
"world.info.generator", Placeholder.parsed("generator", gen)));
plugin.bundle().sendMessage(sender, "world.info.seed",
Placeholder.parsed("seed", String.valueOf(world.getSeed())));
return Command.SINGLE_SUCCESS;
}

private Optional<String> getGenerator(World world) {
if (world.getGenerator() == null) return Optional.empty();
var loader = world.getGenerator().getClass().getClassLoader();
if (!(loader instanceof ConfiguredPluginClassLoader pluginLoader)) return Optional.empty();
if (pluginLoader.getPlugin() == null) return Optional.empty();
return Optional.of(pluginLoader.getPlugin().getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ public class WorldLinkCreateCommand {
return Commands.literal("create")
.requires(source -> source.getSender().hasPermission("worlds.command.link.create"))
.then(Commands.argument("source", ArgumentTypes.world())
.suggests(new WorldSuggestionProvider<>(plugin, world ->
.suggests(new WorldSuggestionProvider<>(plugin, (context, world) ->
world.getEnvironment().equals(World.Environment.NORMAL)))
.then(Commands.argument("destination", ArgumentTypes.world())
.suggests(new WorldSuggestionProvider<>(plugin, world ->
.suggests(new WorldSuggestionProvider<>(plugin, (context, world) ->
!world.getEnvironment().equals(World.Environment.NORMAL)))
.executes(context -> {
var source = context.getArgument("source", World.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class WorldLinkRemoveCommand {
return Commands.literal("remove")
.requires(source -> source.getSender().hasPermission("worlds.command.link.remove"))
.then(Commands.argument("world", ArgumentTypes.world())
.suggests(new WorldSuggestionProvider<>(plugin, world ->
.suggests(new WorldSuggestionProvider<>(plugin, (context, world) ->
world.getEnvironment().equals(World.Environment.NORMAL)))
.then(Commands.argument("relative", new RelativeArgument(relative ->
!relative.equals(Relative.OVERWORLD)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,22 @@ class WorldLoadCommand {
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 message = world != null ? "world.load.success" : "world.load.failed";
plugin.bundle().sendMessage(context.getSource().getSender(), message,
Placeholder.parsed("world", world != null ? world.key().asString() : name));

if (world != null && context.getSource().getSender() instanceof Entity entity)
entity.teleportAsync(world.getSpawnLocation(), COMMAND);

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

return world != null ? Command.SINGLE_SUCCESS : 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import net.thenextlvl.worlds.command.argument.CommandFlagsArgument;
import net.thenextlvl.worlds.command.suggestion.WorldSuggestionProvider;
import org.bukkit.World;
import org.bukkit.WorldCreator;

import java.io.File;
import java.util.Set;
Expand Down Expand Up @@ -71,15 +72,17 @@ private String regenerateNow(World world) {
var fallback = plugin.getServer().getWorlds().getFirst().getSpawnLocation();
players.forEach(player -> player.teleport(fallback, COMMAND));

plugin.persistWorld(world, true);
plugin.levelView().saveLevelData(world, false);

var creator = new WorldCreator(world.getName(), world.getKey()).copy(world);
plugin.levelView().getGenerator(world).ifPresent(creator::generator);

if (!plugin.getServer().unloadWorld(world, false))
return "world.unload.failed";

regenerate(worldFolder);

var regenerated = plugin.levelView().loadLevel(worldFolder, environment);
var regenerated = creator.createWorld();
if (regenerated != null) players.forEach(player ->
player.teleportAsync(regenerated.getSpawnLocation(), COMMAND));
return regenerated != null ? "world.regenerate.success" : "world.regenerate.failed";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class WorldUnloadCommand {
.then(Commands.argument("world", ArgumentTypes.world())
.suggests(new WorldSuggestionProvider<>(plugin))
.then(Commands.argument("fallback", ArgumentTypes.world())
.suggests(new WorldSuggestionProvider<>(plugin))
.suggests(new WorldSuggestionProvider<>(plugin, (context, world) ->
!world.equals(context.getLastChild().getArgument("world", World.class))))
.executes(context -> {
var world = context.getArgument("world", World.class);
var fallback = context.getArgument("fallback", World.class);
Expand All @@ -50,7 +51,7 @@ private String unload(World world, @Nullable World fallback) {
: plugin.getServer().getWorlds().getFirst().getSpawnLocation();
world.getPlayers().forEach(player -> player.teleport(fallbackSpawn));

plugin.persistWorld(world, false);
plugin.persistStatus(world, false, false);

var dragonBattle = world.getEnderDragonBattle();
if (dragonBattle != null) dragonBattle.getBossBar().removeAll();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
package net.thenextlvl.worlds.command.argument;

import com.google.common.base.Preconditions;
import com.mojang.brigadier.arguments.StringArgumentType;
import core.paper.command.WrappedArgumentType;
import net.thenextlvl.worlds.WorldsPlugin;
import net.thenextlvl.worlds.api.model.Generator;
import net.thenextlvl.worlds.command.suggestion.GeneratorSuggestionProvider;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;

public class GeneratorArgument extends WrappedArgumentType<String, GeneratorArgument.Generator> {
public class GeneratorArgument extends WrappedArgumentType<String, Generator> {
public GeneratorArgument(WorldsPlugin plugin) {
super(StringArgumentType.string(), (reader, type) -> {
var split = type.split(":", 2);
var generator = plugin.getServer().getPluginManager().getPlugin(split[0]);
Preconditions.checkNotNull(generator, "Unknown plugin");
Preconditions.checkState(generator.isEnabled(), "Plugin is not enabled");
Preconditions.checkState(plugin.generatorView().hasGenerator(generator), "Plugin has no generator");
return new Generator(generator, split.length > 1 ? split[1] : null);
}, new GeneratorSuggestionProvider(plugin));
}

public record Generator(Plugin plugin, @Nullable String id) {
super(StringArgumentType.string(), (reader, type) ->
Generator.deserialize(plugin, type),
new GeneratorSuggestionProvider(plugin));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@
import org.bukkit.plugin.Plugin;

import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.function.BiPredicate;

@AllArgsConstructor
@RequiredArgsConstructor
public class WorldSuggestionProvider<S> implements SuggestionProvider<S> {
private final Plugin plugin;
private Predicate<World> filter = world -> true;
private BiPredicate<CommandContext<S>, World> filter = (context, world) -> true;

@Override
public CompletableFuture<Suggestions> getSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
plugin.getServer().getWorlds().stream()
.filter(filter)
.filter(world -> filter.test(context, world))
.map(Keyed::key)
.map(Key::asString)
.filter(s -> s.contains(builder.getRemaining()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public void onWorldLoad(WorldLoadEvent event) {
var world = plugin.levelView().loadLevel(level);
if (world != null) plugin.getComponentLogger().debug("Loaded dimension {} at {}",
world.key().asString(), level.getPath());
else plugin.getComponentLogger().error("Failed to load the level {}", level.getPath());
} catch (Exception e) {
plugin.getComponentLogger().error("An unexpected error occurred while loading the level {}",
level.getPath(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import core.io.PathIO;
import core.nbt.file.NBTFile;
import core.nbt.tag.*;
import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader;
import lombok.RequiredArgsConstructor;
import net.thenextlvl.worlds.WorldsPlugin;
import net.thenextlvl.worlds.api.model.Generator;
import net.thenextlvl.worlds.api.model.LevelExtras;
import net.thenextlvl.worlds.api.model.WorldPreset;
import net.thenextlvl.worlds.api.preset.Biome;
Expand Down Expand Up @@ -84,7 +86,7 @@ public World.Environment getEnvironment(File level) {

@Override
public @Nullable World loadLevel(File level, World.Environment environment) {
return loadLevel(level, environment, extras -> extras.map(LevelExtras::enabled).isPresent());
return loadLevel(level, environment, extras -> extras.filter(LevelExtras::enabled).isPresent());
}

@Override
Expand Down Expand Up @@ -141,6 +143,10 @@ public World.Environment getEnvironment(File level) {

generatorSettings.ifPresent(preset -> creator.generatorSettings(preset.serialize().toString()));

var generatorExtras = extras.map(LevelExtras::generator);
generatorExtras.map(gen -> gen.biomeProvider(creator.name())).ifPresent(creator::biomeProvider);
generatorExtras.map(gen -> gen.generator(creator.name())).ifPresent(creator::generator);

return creator.createWorld();
}

Expand All @@ -158,12 +164,14 @@ public Optional<LevelExtras> getExtras(CompoundTag data) {
.map(values -> {
var key = values.optional("worlds:world_key")
.map(Tag::getAsString)
.map(NamespacedKey::fromString)
.orElse(null);
.map(NamespacedKey::fromString);
var generator = values.optional("worlds:generator")
.map(Tag::getAsString)
.map(serialized -> Generator.deserialize(plugin, serialized));
var enabled = values.optional("worlds:enabled")
.map(Tag::getAsBoolean)
.orElse(true);
return new LevelExtras(key, enabled);
.map(Tag::getAsBoolean);
if (key.isEmpty() && generator.isEmpty() && enabled.isEmpty()) return null;
return new LevelExtras(key.orElse(null), generator.orElse(null), enabled.orElse(false));
});
}

Expand Down Expand Up @@ -210,6 +218,16 @@ public Optional<Preset> getFlatPreset(CompoundTag generator) {
return Optional.of(preset);
}

@Override
@SuppressWarnings("UnstableApiUsage")
public Optional<String> getGenerator(World world) {
if (world.getGenerator() == null) return Optional.empty();
var loader = world.getGenerator().getClass().getClassLoader();
if (!(loader instanceof ConfiguredPluginClassLoader pluginLoader)) return Optional.empty();
if (pluginLoader.getPlugin() == null) return Optional.empty();
return Optional.of(pluginLoader.getPlugin().getName());
}

@Override
public NBTFile<CompoundTag> getLevelDataFile(File level) {
return new NBTFile<>(Optional.of(
Expand Down

0 comments on commit 26eafdc

Please sign in to comment.