diff --git a/common/src/main/java/common/biome/Biome.java b/common/src/main/java/common/biome/Biome.java index 92a4d668..9ef237c9 100644 --- a/common/src/main/java/common/biome/Biome.java +++ b/common/src/main/java/common/biome/Biome.java @@ -10,9 +10,11 @@ import common.log.Log; import common.rng.PerlinGen; import common.rng.Random; import common.util.BlockPos; +import common.util.Displayable; import common.util.ExtMath; +import common.util.Identifyable; -public enum Biome { +public enum Biome implements Identifyable, Displayable { NONE(0, "none", "", 0x000000), PLAINS(1, "plains", "Ebene", 0x8db360, 12.0f, 40.0f), DESERT(2, "desert", "Wüste", 0xfa9418, 60.0f, 0.0f), @@ -232,4 +234,12 @@ public enum Biome { double d1 = (double)ExtMath.clampf(this.humidity * 0.01f, 0.0F, 1.0F); return Colorizer.getFoliageColor(d0, d1); } + + public String getName() { + return this.name; + } + + public String getDisplay() { + return this.display; + } } diff --git a/common/src/main/java/common/init/UniverseRegistry.java b/common/src/main/java/common/init/UniverseRegistry.java index 625dc0c4..6223e798 100755 --- a/common/src/main/java/common/init/UniverseRegistry.java +++ b/common/src/main/java/common/init/UniverseRegistry.java @@ -92,6 +92,7 @@ public abstract class UniverseRegistry { Dimension dim = Dimension.getByTag(list.get(z)); if(!REGISTRY.containsKey(dim.getDimensionId()) && !ALIASES.containsKey(dim.getDimensionName())) register(dim); + nextDimId = dim.getDimensionId() + 1 > nextDimId ? dim.getDimensionId() + 1 : nextDimId; } list = tag.getList("Names"); @@ -253,6 +254,7 @@ public abstract class UniverseRegistry { public static Planet registerPlanet(String star, String name, String custom, int sky, int fog, int clouds, long orbit, long rotation, float offset, float gravity, float temperature, int brightness) { + star = star == null ? new Random().pick(Lists.newArrayList(STAR_MAP.keySet())).getDimensionName() : star; if(!ALIASES.containsKey(star) || ALIASES.get(star).getType() != DimType.STAR || ALIASES.containsKey(name)) return null; Planet dim = new Planet(nextDimId++, name, sky, fog, clouds, orbit, rotation, offset, gravity, temperature, brightness); diff --git a/server/src/main/java/server/Server.java b/server/src/main/java/server/Server.java index b8569592..c256250c 100755 --- a/server/src/main/java/server/Server.java +++ b/server/src/main/java/server/Server.java @@ -103,7 +103,6 @@ import server.network.Player; import server.network.User; import server.vars.SVar; import server.vars.SVars; -import server.world.Converter; import server.world.Region; import server.world.WorldServer; @@ -405,7 +404,6 @@ public final class Server implements IThreadListener, Executor { public void run(long time) { Region.loadMap(); - Converter.convert("terra"); long wtime = this.loadServerConfig(); if(this.keyPair == null) { Log.SYSTEM.info("Generiere neues Schlüsselpaar"); diff --git a/server/src/main/java/server/command/ArgumentParser.java b/server/src/main/java/server/command/ArgumentParser.java index d8c66086..eb6956d4 100644 --- a/server/src/main/java/server/command/ArgumentParser.java +++ b/server/src/main/java/server/command/ArgumentParser.java @@ -6,6 +6,10 @@ import java.util.List; import common.collect.Lists; public abstract class ArgumentParser { + public static String escape(String str) { + return str.replace("\\", "\\\\").replace(" ", "\\ ").replace("\"", "\\\"").replace(";", "\\;"); + } + public static String[][] splitString(String str) { // if(str.isEmpty()) { // return new String[0]; diff --git a/server/src/main/java/server/command/Command.java b/server/src/main/java/server/command/Command.java index 25e0cb52..3cd72780 100644 --- a/server/src/main/java/server/command/Command.java +++ b/server/src/main/java/server/command/Command.java @@ -120,6 +120,22 @@ public abstract class Command implements Executable { return this.addParameter(new IntParser(name, false, def, min, max, def)); } + protected Command addLong(String name, char shortName, long min, long max, long def) { + return this.addParameter(shortName, new LongParser(name, def, min, max, def)); + } + + protected Command addLong(String name, long min, long max, long def) { + return this.addParameter(new LongParser(name, def, min, max, def)); + } + + protected Command addColor(String name, char shortName, int def) { + return this.addParameter(shortName, new ColorParser(name, def)); + } + + protected Command addColor(String name, int def) { + return this.addParameter(new ColorParser(name, def)); + } + protected Command addDouble(String name, char shortName, double min, double max, double def) { return this.addParameter(shortName, new DoubleParser(name, def, min, max, false, def)); } @@ -240,6 +256,14 @@ public abstract class Command implements Executable { return this.addParameter(new StringParser(name, null, allowEmpty, null, null, null, completions)); } + protected Command addString(String name, char shortName, boolean allowEmpty, Object ... completions) { + return this.addParameter(shortName, new StringParser(name, null, allowEmpty, null, null, null, completions)); + } + + protected Command addString(String name, char shortName, boolean allowEmpty, StringCompleter completer) { + return this.addParameter(shortName, new StringParser(name, null, allowEmpty, null, null, null, completer)); + } + protected Command addString(String name, boolean allowEmpty, StringCompleter completer) { return this.addParameter(new StringParser(name, null, allowEmpty, null, null, null, completer)); } diff --git a/server/src/main/java/server/command/CommandEnvironment.java b/server/src/main/java/server/command/CommandEnvironment.java index 4fa070c6..4471d96a 100644 --- a/server/src/main/java/server/command/CommandEnvironment.java +++ b/server/src/main/java/server/command/CommandEnvironment.java @@ -270,5 +270,6 @@ public class CommandEnvironment { this.registerExecutable(new CommandMore()); this.registerExecutable(new CommandReturn()); this.registerExecutable(new CommandDeathspot()); + this.registerExecutable(new CommandLoad()); } } diff --git a/server/src/main/java/server/command/commands/CommandLoad.java b/server/src/main/java/server/command/commands/CommandLoad.java new file mode 100644 index 00000000..f59cbbe0 --- /dev/null +++ b/server/src/main/java/server/command/commands/CommandLoad.java @@ -0,0 +1,96 @@ +package server.command.commands; + +import java.io.File; +import java.util.Arrays; + +import common.biome.Biome; +import common.collect.Iterables; +import common.collect.Lists; +import common.color.TextColor; +import common.dimension.Planet; +import common.dimension.Star; +import common.init.UniverseRegistry; +import server.command.ArgumentParser; +import server.command.Command; +import server.command.CommandEnvironment; +import server.command.Executor; +import server.command.RunException; +import server.network.Player; +import server.world.Converter; + +public class CommandLoad extends Command { + private static final File IMPORTS_DIR = new File("import"); + + private String loadingDim; + + public CommandLoad() { + super("load"); + + this.addString("name", false, null, null, ch -> (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_'); + this.addString("display", false); + this.setParamsOptional(); + this.addString("star", false); + this.addEnum("biome", Biome.DEF_BIOME, Biome.class, Biome.values()); + this.addString("convert", 'c', false, (env, last) -> { + File[] list = IMPORTS_DIR.listFiles(file -> file.isDirectory()); + if(list != null) + Arrays.sort(list); + return list == null ? Lists.newArrayList() : Lists.newArrayList(Iterables.transform(Lists.newArrayList(list), file -> ArgumentParser.escape(file.getName()))); + }); + this.addFlag("teleport", 't'); + this.addColor("sky", 's', 0xffffffff); + this.addColor("fog", 'f', 0xc0d8ff); + this.addColor("clouds", 'w', 0xffffff); + this.addLong("orbit", 'o', 1L, 1000000000000L, UniverseRegistry.EARTH_YEAR); + this.addLong("rotation", 'r', 1L, 1000000000000L, 24000L); + this.addDouble("offset", 'm', 0.0, 100000.0, 0.0); + this.addDouble("gravity", 'g', 0.0, 100000.0, 9.81); + this.addDouble("temperature", 'k', 0.0, 100000.0, 259.15); + this.addInt("brightness", 'b', 0, 15, 0); + } + + public void exec(CommandEnvironment env, Executor exec, String name, String display, String star, Biome biome, String convert, boolean teleport, int sky, int fog, int clouds, + long orbit, long rotation, double offset, double gravity, double temperature, int brightness) { + if(teleport && !exec.isPlayer()) + throw new RunException("Nur Spieler können teleportiert werden"); + if(UniverseRegistry.getDimension(name) != null) + throw new RunException("Dimension '%s' existiert bereits", name); + if(name.equals(this.loadingDim)) + throw new RunException("Dimension '%s' wird gerade geladen", name); + if(star != null && !(UniverseRegistry.getDimension(star) instanceof Star)) + throw new RunException("'%s' ist kein Stern", star); + if(convert != null) { + File dir = new File(IMPORTS_DIR, convert); + if(!IMPORTS_DIR.equals(dir.getParentFile())) + throw new RunException("Welt %s muss ein direkter Unterordner von %s/ sein", convert, IMPORTS_DIR); + if(!dir.exists()) { + IMPORTS_DIR.mkdirs(); + throw new RunException("Welt %s existiert nicht", dir); + } + this.loadingDim = name; + if(Converter.convert(dir, name, pos -> env.getServer().schedule(() -> { + Planet planet = UniverseRegistry.registerPlanet(star, name, display, sky, fog, clouds, orbit, rotation, (float)offset, (float)gravity, (float)temperature, brightness); + planet.setBiome(biome); + this.loadingDim = null; + exec.log(TextColor.GREEN + "Welt %s wurde erfolgreich in Dimension '%s' konvertiert", dir, display); + if(teleport && pos != null) { + Player player = env.getServer().getPlayer(((Player)exec).getUser()); + if(player != null && player.getPresentEntity() != null) + player.getPresentEntity().teleport(CommandWorld.adjust(env.getServer().getWorld(planet.getDimensionId()), pos), planet.getDimensionId()); + } + })) == null) { + this.loadingDim = null; + throw new RunException("Welt %s konnte nicht konvertiert werden", dir); + } + else { + exec.log(TextColor.ACID + "Welt %s wird in Dimension '%s' konvertiert ...", dir, display); + } + return; + } + Planet planet = UniverseRegistry.registerPlanet(star, name, display, sky, fog, clouds, orbit, rotation, (float)offset, (float)gravity, (float)temperature, brightness); + planet.setBiome(biome); + exec.log(TextColor.GREEN + "Dimension '%s' wurde registriert", display); + if(teleport && ((Player)exec).getPresentEntity() != null) + ((Player)exec).getPresentEntity().teleport(CommandWorld.adjust(env.getServer().getWorld(planet.getDimensionId()), ((Player)exec).getPresentEntity().getPosition()), planet.getDimensionId()); + } +} diff --git a/server/src/main/java/server/command/commands/CommandWorld.java b/server/src/main/java/server/command/commands/CommandWorld.java index 316fc18b..21edf5e6 100644 --- a/server/src/main/java/server/command/commands/CommandWorld.java +++ b/server/src/main/java/server/command/commands/CommandWorld.java @@ -21,20 +21,24 @@ public class CommandWorld extends Command { public Object exec(CommandEnvironment env, Executor exec, WorldServer world, List entities) { for(Entity entity : entities) { - BlockPos pos = entity.getPosition(); - pos = pos.getY() < 0 ? new BlockPos(pos.getX(), 0, pos.getZ()) : pos; - if(world.getState(pos).getBlock().getMaterial().blocksMovement() || world.getState(pos).getBlock().getMaterial().isLiquid()) { - while((world.getState(pos).getBlock().getMaterial().blocksMovement() || world.getState(pos).getBlock().getMaterial().isLiquid()) && pos.getY() < 511) - pos = pos.up(); - } - else { - while(!(world.getState(pos).getBlock().getMaterial().blocksMovement() || world.getState(pos).getBlock().getMaterial().isLiquid()) && pos.getY() > 0) - pos = pos.down(); - pos = pos.up(); - } + BlockPos pos = adjust(world, entity.getPosition()); entity.teleport(pos, world.dimension.getDimensionId()); exec.log("%s nach %d, %d, %d in %s teleportiert", entity.getCommandName(), pos.getX(), pos.getY(), pos.getZ(), world.dimension.getFormattedName(false)); } return entities.size(); } + + public static BlockPos adjust(WorldServer world, BlockPos pos) { + pos = pos.getY() < 0 ? new BlockPos(pos.getX(), 0, pos.getZ()) : pos; + if(world.getState(pos).getBlock().getMaterial().blocksMovement() || world.getState(pos).getBlock().getMaterial().isLiquid()) { + while((world.getState(pos).getBlock().getMaterial().blocksMovement() || world.getState(pos).getBlock().getMaterial().isLiquid()) && pos.getY() < 511) + pos = pos.up(); + } + else { + while(!(world.getState(pos).getBlock().getMaterial().blocksMovement() || world.getState(pos).getBlock().getMaterial().isLiquid()) && pos.getY() > 0) + pos = pos.down(); + pos = pos.up(); + } + return pos; + } } diff --git a/server/src/main/java/server/world/Converter.java b/server/src/main/java/server/world/Converter.java index 86f8e3ae..c4ca9779 100644 --- a/server/src/main/java/server/world/Converter.java +++ b/server/src/main/java/server/world/Converter.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.zip.GZIPInputStream; import java.util.zip.InflaterInputStream; @@ -2034,12 +2035,12 @@ public abstract class Converter { return start; } - public static BlockPos convert(String dest) { - if(new File("server.cdt").exists()) + public static BlockPos convert(File dir, String dest, Consumer finish) { + if(new File(dir, "server.cdt").exists()) return null; - File ldat = new File("level.dat"); + File ldat = new File(dir, "level.dat"); if(!ldat.exists()) - ldat = new File("level.dat_old"); + ldat = new File(dir, "level.dat_old"); if(!ldat.exists()) return null; Log.IO.info("Welt wird konvertiert ..."); @@ -2073,7 +2074,7 @@ public abstract class Converter { Log.IO.warn("Konvertiere keine Chunk-Daten, da Version zu neu (%s)", ver); return null; } - File regionDir = new File("region"); + File regionDir = new File(dir, "region"); if(!regionDir.exists()) { Log.IO.info("Kein Ordner region/ gefunden"); return null; @@ -2093,19 +2094,25 @@ public abstract class Converter { if(ver == SaveVersion.RELEASE_1_9) Log.IO.warn("Konvertiere von neuerer Version, dies wird Blöcke entfernen ..."); chunkDir.mkdirs(); - int progress = 0; - long time = System.currentTimeMillis(); - long start = postProgress(time, 0); - for(File file : files) { - int percent = (int)Math.round(100.0D * (double)progress / (double)files.length); - Log.IO.info("Konvertiere Chunk-Daten: " + file.getName() + " (" + progress + "/" + files.length + ")"); - start = convertChunks(chunkDir, file, start, progress, files.length); - ++progress; - start = postProgress(start, percent); - } - time = System.currentTimeMillis() - time; - Log.IO.info("Fertig. Konversion dauerte " + ((time / 60000L) > 0 ? ((time / 60000L) + " Minuten und ") : "") + ((time / 1000L) % 60L) + " Sekunden."); + BlockPos pos = new BlockPos(tag.getInt("SpawnX"), tag.getInt("SpawnY"), tag.getInt("SpawnZ")); + new Thread(new Runnable() { + public void run() { + int progress = 0; + long time = System.currentTimeMillis(); + long start = postProgress(time, 0); + for(File file : files) { + int percent = (int)Math.round(100.0D * (double)progress / (double)files.length); + Log.IO.info("Konvertiere Chunk-Daten: " + file.getName() + " (" + progress + "/" + files.length + ")"); + start = convertChunks(chunkDir, file, start, progress, files.length); + ++progress; + start = postProgress(start, percent); + } + time = System.currentTimeMillis() - time; + Log.IO.info("Fertig. Konversion dauerte " + ((time / 60000L) > 0 ? ((time / 60000L) + " Minuten und ") : "") + ((time / 1000L) % 60L) + " Sekunden."); + finish.accept(pos); + } + }, "Chunk converter " + dest + " thread").start(); Log.IO.info("Einstiegspunkt: /tele %d %d %d %s", tag.getInt("SpawnX"), tag.getInt("SpawnY"), tag.getInt("SpawnZ"), dest); - return new BlockPos(tag.getInt("SpawnX"), tag.getInt("SpawnY"), tag.getInt("SpawnZ")); + return pos; } }