mirror of
https://github.com/Multiverse/Multiverse-Core.git
synced 2024-11-22 18:47:20 +01:00
Finish up regen world
This commit is contained in:
parent
a0fa27f926
commit
9cb8724db2
@ -9,6 +9,8 @@ import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer;
|
||||
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
|
||||
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag;
|
||||
@ -19,6 +21,7 @@ import com.onarandombox.MultiverseCore.commandtools.queue.QueuedCommand;
|
||||
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
|
||||
import com.onarandombox.MultiverseCore.worldnew.MVWorld;
|
||||
import com.onarandombox.MultiverseCore.worldnew.WorldManager;
|
||||
import com.onarandombox.MultiverseCore.worldnew.options.RegenWorldOptions;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
@ -43,8 +46,14 @@ public class RegenCommand extends MultiverseCommand {
|
||||
.completion((input) -> Collections.singleton(String.valueOf(new Random().nextLong())))
|
||||
.optional()
|
||||
.build())
|
||||
.add(CommandFlag.builder("--keep-gamerules")
|
||||
.addAlias("-k")
|
||||
.add(CommandFlag.builder("--reset-world-config")
|
||||
.addAlias("-wc")
|
||||
.build())
|
||||
.add(CommandFlag.builder("--reset-gamerules")
|
||||
.addAlias("-gm")
|
||||
.build())
|
||||
.add(CommandFlag.builder("--reset-world-border")
|
||||
.addAlias("-wb")
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
@ -54,14 +63,14 @@ public class RegenCommand extends MultiverseCommand {
|
||||
@CommandCompletion("@mvworlds:scope=loaded @flags:groupName=mvregen")
|
||||
@Syntax("<world> --seed [seed] --keep-gamerules")
|
||||
@Description("{@@mv-core.regen.description}")
|
||||
public void onRegenCommand(BukkitCommandIssuer issuer,
|
||||
public void onRegenCommand(MVCommandIssuer issuer,
|
||||
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.regen.world.description}")
|
||||
MVWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("--seed [seed] --keep-gamerules")
|
||||
@Syntax("--seed [seed] --reset-gamerules")
|
||||
@Description("{@@mv-core.regen.other.description}")
|
||||
String[] flags
|
||||
) {
|
||||
@ -71,8 +80,19 @@ public class RegenCommand extends MultiverseCommand {
|
||||
issuer.getIssuer(),
|
||||
() -> {
|
||||
issuer.sendInfo(MVCorei18n.REGEN_REGENERATING, "{world}", world.getName());
|
||||
worldManager.regenWorld(world);
|
||||
issuer.sendInfo(MVCorei18n.REGEN_SUCCESS, "{world}", world.getName());
|
||||
worldManager.regenWorld(RegenWorldOptions.world(world)
|
||||
.randomSeed(!parsedFlags.hasFlagValue("--seed"))
|
||||
.seed(parsedFlags.flagValue("--seed", String.class))
|
||||
.keepWorldConfig(!parsedFlags.hasFlag("--reset-world-config"))
|
||||
.keepGameRule(!parsedFlags.hasFlag("--reset-gamerules"))
|
||||
.keepWorldBorder(!parsedFlags.hasFlag("--reset-world-border"))
|
||||
).onSuccess((success) -> {
|
||||
Logging.fine("World create success: " + success);
|
||||
issuer.sendInfo(success.getReasonMessage());
|
||||
}).onFailure((failure) -> {
|
||||
Logging.fine("World create failure: " + failure);
|
||||
issuer.sendError(failure.getReasonMessage());
|
||||
});
|
||||
},
|
||||
this.commandManager.formatMessage(
|
||||
issuer,
|
||||
|
@ -14,10 +14,12 @@ import com.onarandombox.MultiverseCore.worldnew.helpers.DataStore.GameRulesStore
|
||||
import com.onarandombox.MultiverseCore.worldnew.helpers.FilesManipulator;
|
||||
import com.onarandombox.MultiverseCore.worldnew.options.CreateWorldOptions;
|
||||
import com.onarandombox.MultiverseCore.worldnew.options.ImportWorldOptions;
|
||||
import com.onarandombox.MultiverseCore.worldnew.options.RegenWorldOptions;
|
||||
import com.onarandombox.MultiverseCore.worldnew.results.CreateWorldResult;
|
||||
import com.onarandombox.MultiverseCore.worldnew.results.DeleteWorldResult;
|
||||
import com.onarandombox.MultiverseCore.worldnew.results.ImportWorldResult;
|
||||
import com.onarandombox.MultiverseCore.worldnew.results.LoadWorldResult;
|
||||
import com.onarandombox.MultiverseCore.worldnew.results.RegenWorldResult;
|
||||
import com.onarandombox.MultiverseCore.worldnew.results.RemoveWorldResult;
|
||||
import com.onarandombox.MultiverseCore.worldnew.results.UnloadWorldResult;
|
||||
import io.vavr.control.Option;
|
||||
@ -512,40 +514,38 @@ public class WorldManager {
|
||||
/**
|
||||
* Regenerates a world.
|
||||
*
|
||||
* @param world The world to regenerate.
|
||||
* @param options The options for customizing the regeneration of a world.
|
||||
*/
|
||||
public void regenWorld(@NotNull MVWorld world) {
|
||||
public Result<RegenWorldResult.Success, RegenWorldResult.Failure> regenWorld(@NotNull RegenWorldOptions options) {
|
||||
// TODO: Teleport players out of world, and back in after regen
|
||||
MVWorld world = options.world();
|
||||
|
||||
GameRulesStore gameRulesStore = GameRulesStore.createAndCopyFrom(world);
|
||||
WorldConfigStore worldConfigStore = WorldConfigStore.createAndCopyFrom(world);
|
||||
|
||||
// TODO: Random/fixed seed option
|
||||
CreateWorldOptions createWorldOptions = CreateWorldOptions.worldName(world.getName())
|
||||
.environment(world.getEnvironment())
|
||||
.generateStructures(world.canGenerateStructures().getOrElse(true))
|
||||
.generator(world.getGenerator())
|
||||
.seed(world.getSeed())
|
||||
.seed(options.seed())
|
||||
.worldType(world.getWorldType().getOrElse(WorldType.NORMAL));
|
||||
|
||||
var deleteResult = deleteWorld(world);
|
||||
if (deleteResult.isFailure()) {
|
||||
Logging.severe("Failed to delete world: " + world.getName());
|
||||
return;
|
||||
return Result.failure(RegenWorldResult.Failure.DELETE_FAILED, deleteResult.getReasonMessage());
|
||||
}
|
||||
|
||||
var createResult = createWorld(createWorldOptions);
|
||||
if (createResult.isFailure()) {
|
||||
Logging.severe("Failed to create world: " + world.getName());
|
||||
return;
|
||||
return Result.failure(RegenWorldResult.Failure.CREATE_FAILED, createResult.getReasonMessage());
|
||||
}
|
||||
|
||||
// TODO: Error handling
|
||||
getMVWorld(createWorldOptions.worldName()).peek(newWorld -> {
|
||||
gameRulesStore.pasteTo(newWorld);
|
||||
worldConfigStore.pasteTo(newWorld);
|
||||
saveWorldsConfig();
|
||||
});
|
||||
return Result.success(RegenWorldResult.Success.REGENERATED, replace("{world}").with(world.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,9 +11,27 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A data store for storing and restoring data from an object.
|
||||
*
|
||||
* @param <T> The type of the object to store data from.
|
||||
*/
|
||||
@Service
|
||||
public interface DataStore<T> {
|
||||
/**
|
||||
* Stores the data from the given object in this {@link DataStore} instance.
|
||||
*
|
||||
* @param object The object to copy data from.
|
||||
* @return This {@link DataStore} instance.
|
||||
*/
|
||||
DataStore<T> copyFrom(T object);
|
||||
|
||||
/**
|
||||
* Copies the data from this {@link DataStore} instance to the given object.
|
||||
*
|
||||
* @param object The object to paste data to.
|
||||
* @return This {@link DataStore} instance.
|
||||
*/
|
||||
DataStore<T> pasteTo(T object);
|
||||
|
||||
class GameRulesStore implements DataStore<MVWorld> {
|
||||
@ -23,6 +41,10 @@ public interface DataStore<T> {
|
||||
|
||||
private Map<GameRule<?>, Object> gameRuleMap;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public GameRulesStore copyFrom(MVWorld world) {
|
||||
this.gameRuleMap = new HashMap<>();
|
||||
world.getBukkitWorld().peek(bukkitWorld -> {
|
||||
@ -34,6 +56,10 @@ public interface DataStore<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public GameRulesStore pasteTo(MVWorld world) {
|
||||
if (gameRuleMap == null) {
|
||||
return this;
|
||||
@ -65,6 +91,9 @@ public interface DataStore<T> {
|
||||
|
||||
private Map<String, Object> configMap;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public WorldConfigStore copyFrom(OfflineWorld world) {
|
||||
this.configMap = new HashMap<>();
|
||||
@ -76,6 +105,9 @@ public interface DataStore<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public WorldConfigStore pasteTo(OfflineWorld world) {
|
||||
if (configMap == null) {
|
||||
@ -90,4 +122,54 @@ public interface DataStore<T> {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class WorldBorderStore implements DataStore<MVWorld> {
|
||||
/**
|
||||
* Creates a new {@link WorldBorderStore} instance and copies the world border data from the given world.
|
||||
*
|
||||
* @param world The world to copy the world border data from.
|
||||
* @return A new {@link WorldBorderStore} instance.
|
||||
*/
|
||||
public static WorldBorderStore createAndCopyFrom(MVWorld world) {
|
||||
return new WorldBorderStore().copyFrom(world);
|
||||
}
|
||||
|
||||
private double borderCenterX;
|
||||
private double borderCenterZ;
|
||||
private double borderDamageAmount;
|
||||
private double borderDamageBuffer;
|
||||
private double borderSize;
|
||||
private int borderTimeRemaining;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public WorldBorderStore copyFrom(MVWorld world) {
|
||||
world.getBukkitWorld().peek(bukkitWorld -> {
|
||||
borderCenterX = bukkitWorld.getWorldBorder().getCenter().getX();
|
||||
borderCenterZ = bukkitWorld.getWorldBorder().getCenter().getZ();
|
||||
borderDamageAmount = bukkitWorld.getWorldBorder().getDamageAmount();
|
||||
borderDamageBuffer = bukkitWorld.getWorldBorder().getDamageBuffer();
|
||||
borderSize = bukkitWorld.getWorldBorder().getSize();
|
||||
borderTimeRemaining = bukkitWorld.getWorldBorder().getWarningTime();
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public WorldBorderStore pasteTo(MVWorld world) {
|
||||
world.getBukkitWorld().peek(bukkitWorld -> {
|
||||
bukkitWorld.getWorldBorder().setCenter(borderCenterX, borderCenterZ);
|
||||
bukkitWorld.getWorldBorder().setDamageAmount(borderDamageAmount);
|
||||
bukkitWorld.getWorldBorder().setDamageBuffer(borderDamageBuffer);
|
||||
bukkitWorld.getWorldBorder().setSize(borderSize);
|
||||
bukkitWorld.getWorldBorder().setWarningTime(borderTimeRemaining);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import org.bukkit.WorldType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Options for customizing the creation of a new world.
|
||||
*/
|
||||
@ -24,7 +26,7 @@ public class CreateWorldOptions {
|
||||
private World.Environment environment = World.Environment.NORMAL;
|
||||
private boolean generateStructures = true;
|
||||
private String generator = null;
|
||||
private long seed = Long.MIN_VALUE;
|
||||
private long seed;
|
||||
private boolean useSpawnAdjust = true;
|
||||
private WorldType worldType = WorldType.NORMAL;
|
||||
|
||||
@ -35,6 +37,7 @@ public class CreateWorldOptions {
|
||||
*/
|
||||
CreateWorldOptions(@NotNull String worldName) {
|
||||
this.worldName = worldName;
|
||||
this.seed = (new Random()).nextLong();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,7 +118,6 @@ public class CreateWorldOptions {
|
||||
*/
|
||||
public @NotNull CreateWorldOptions seed(@Nullable String seed) {
|
||||
if (seed == null) {
|
||||
this.seed = Long.MIN_VALUE;
|
||||
return this;
|
||||
}
|
||||
try {
|
||||
|
@ -0,0 +1,99 @@
|
||||
package com.onarandombox.MultiverseCore.worldnew.options;
|
||||
|
||||
import com.onarandombox.MultiverseCore.worldnew.MVWorld;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RegenWorldOptions {
|
||||
public static @NotNull RegenWorldOptions world(@NotNull MVWorld world) {
|
||||
return new RegenWorldOptions(world);
|
||||
}
|
||||
|
||||
private final MVWorld world;
|
||||
private boolean keepGameRule = true;
|
||||
private boolean keepWorldConfig = true;
|
||||
|
||||
private boolean keepWorldBorder = true;
|
||||
private boolean randomSeed = false;
|
||||
private long seed = Long.MIN_VALUE;
|
||||
|
||||
RegenWorldOptions(@NotNull MVWorld world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public @NotNull MVWorld world() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public @NotNull RegenWorldOptions keepGameRule(boolean keepGameRule) {
|
||||
this.keepGameRule = keepGameRule;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean keepGameRule() {
|
||||
return keepGameRule;
|
||||
}
|
||||
|
||||
public @NotNull RegenWorldOptions keepWorldConfig(boolean keepWorldConfig) {
|
||||
this.keepWorldConfig = keepWorldConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean keepWorldConfig() {
|
||||
return keepWorldConfig;
|
||||
}
|
||||
|
||||
public @NotNull RegenWorldOptions keepWorldBorder(boolean keepWorldBorder) {
|
||||
this.keepWorldBorder = keepWorldBorder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean keepWorldBorder() {
|
||||
return keepWorldBorder;
|
||||
}
|
||||
|
||||
public @NotNull RegenWorldOptions randomSeed(boolean randomSeed) {
|
||||
if (randomSeed && seed != Long.MIN_VALUE) {
|
||||
throw new IllegalStateException("Cannot set randomSeed to true when seed is set");
|
||||
}
|
||||
this.randomSeed = randomSeed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean randomSeed() {
|
||||
return randomSeed;
|
||||
}
|
||||
|
||||
public @NotNull RegenWorldOptions seed(@Nullable String seed) {
|
||||
if (seed == null) {
|
||||
this.seed = Long.MIN_VALUE;
|
||||
return this;
|
||||
}
|
||||
if (randomSeed) {
|
||||
randomSeed(false);
|
||||
}
|
||||
try {
|
||||
this.seed = Long.parseLong(seed);
|
||||
} catch (NumberFormatException numberformatexception) {
|
||||
this.seed = seed.hashCode();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull RegenWorldOptions seed(long seed) {
|
||||
this.seed = seed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long seed() {
|
||||
if (randomSeed) {
|
||||
return new Random().nextLong();
|
||||
}
|
||||
if (seed == Long.MIN_VALUE) {
|
||||
return world.getSeed();
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.onarandombox.MultiverseCore.worldnew.results;
|
||||
|
||||
import co.aikar.locales.MessageKey;
|
||||
import co.aikar.locales.MessageKeyProvider;
|
||||
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
|
||||
import com.onarandombox.MultiverseCore.utils.result.FailureReason;
|
||||
import com.onarandombox.MultiverseCore.utils.result.SuccessReason;
|
||||
|
||||
public class RegenWorldResult {
|
||||
public enum Success implements SuccessReason {
|
||||
REGENERATED(MVCorei18n.GENERIC_SUCCESS)
|
||||
;
|
||||
|
||||
private final MessageKeyProvider message;
|
||||
|
||||
Success(MessageKeyProvider message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageKey getMessageKey() {
|
||||
return message.getMessageKey();
|
||||
}
|
||||
}
|
||||
|
||||
public enum Failure implements FailureReason {
|
||||
DELETE_FAILED(null),
|
||||
CREATE_FAILED(null),
|
||||
;
|
||||
|
||||
private final MessageKeyProvider message;
|
||||
|
||||
Failure(MessageKeyProvider message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageKey getMessageKey() {
|
||||
return message.getMessageKey();
|
||||
}
|
||||
}
|
||||
}
|
@ -155,6 +155,8 @@ mv-core.loadworld.worldexistfolder=World '{world}' exists in server folders, but
|
||||
mv-core.loadworld.worldexistloaded=World '{world}' is already loaded!
|
||||
mv-core.loadworld.bukkitcreationfailed=Bukkit failed to load world '{world}': {error}\n&fSee console for more details.
|
||||
|
||||
mv-core.regenworld.regenerated=&aWorld '{world}' regenerated!
|
||||
|
||||
mv-core.removeworld.removed=&aWorld '{world}' removed!
|
||||
mv-core.removeworld.worldnonexistent=World '{world}' not found!
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user