diff --git a/pom.xml b/pom.xml index 1fe96b8c..c2e52603 100644 --- a/pom.xml +++ b/pom.xml @@ -130,5 +130,10 @@ provided maven-plugin + + javax.vecmath + vecmath + 1.5.2 + \ No newline at end of file diff --git a/src/main/java/amidst/AmidstSettings.java b/src/main/java/amidst/AmidstSettings.java index 0035033d..e55477c9 100644 --- a/src/main/java/amidst/AmidstSettings.java +++ b/src/main/java/amidst/AmidstSettings.java @@ -26,6 +26,9 @@ public class AmidstSettings { public final Setting showOceanMonuments; public final Setting showNetherFortresses; public final Setting showEndCities; + public final Setting showMinetestRivers; + public final Setting showMinetestOceans; + public final Setting showMinetestMountains; public final Setting enableAllLayers; public final Setting smoothScrolling; @@ -58,6 +61,9 @@ public class AmidstSettings { showOceanMonuments = Settings.createBoolean( preferences, "oceanMonumentIcons", true); showNetherFortresses = Settings.createBoolean( preferences, "netherFortressIcons", false); showEndCities = Settings.createBoolean( preferences, "endCityIcons", false); + showMinetestRivers = Settings.createBoolean( preferences, "minetestRivers", true); + showMinetestOceans = Settings.createBoolean( preferences, "minetestOceans", true); + showMinetestMountains = Settings.createBoolean( preferences, "minetestMountains", true); enableAllLayers = Settings.createBoolean( preferences, "enableAllLayers", false); smoothScrolling = Settings.createBoolean( preferences, "mapFlicking", true); diff --git a/src/main/java/amidst/CommandLineParameters.java b/src/main/java/amidst/CommandLineParameters.java index f889052c..fec341ce 100644 --- a/src/main/java/amidst/CommandLineParameters.java +++ b/src/main/java/amidst/CommandLineParameters.java @@ -11,6 +11,9 @@ import amidst.documentation.ThreadSafe; @ThreadSafe public class CommandLineParameters { // @formatter:off + @Option(name = "-mtpath", usage = "location of the minetest directory.", metaVar = "") + public volatile String minetestDirectory; + @Option(name = "-mcpath", usage = "location of the '.minecraft' directory.", metaVar = "") public volatile String dotMinecraftDirectory; diff --git a/src/main/java/amidst/FeatureToggles.java b/src/main/java/amidst/FeatureToggles.java index cc92356c..7f1158e3 100644 --- a/src/main/java/amidst/FeatureToggles.java +++ b/src/main/java/amidst/FeatureToggles.java @@ -8,4 +8,5 @@ public enum FeatureToggles { public static final boolean SEED_SEARCH = false; public static final boolean WORLD_EXPORTER = false; + public static final boolean MINETEST_SUPPORT = true; } diff --git a/src/main/java/amidst/PerApplicationInjector.java b/src/main/java/amidst/PerApplicationInjector.java index e40278be..2b8ae09e 100644 --- a/src/main/java/amidst/PerApplicationInjector.java +++ b/src/main/java/amidst/PerApplicationInjector.java @@ -19,6 +19,7 @@ import amidst.gui.main.viewer.PerViewerFacadeInjector; import amidst.gui.main.viewer.ViewerFacade; import amidst.gui.main.viewer.Zoom; import amidst.gui.profileselect.ProfileSelectWindow; +import amidst.minetest.file.MinetestInstallation; import amidst.mojangapi.LauncherProfileRunner; import amidst.mojangapi.RunningLauncherProfile; import amidst.mojangapi.file.DotMinecraftDirectoryNotFoundException; @@ -41,6 +42,7 @@ public class PerApplicationInjector { private final PlayerInformationProvider playerInformationProvider; private final SeedHistoryLogger seedHistoryLogger; private final MinecraftInstallation minecraftInstallation; + private final MinetestInstallation minetestInstallation; private final Optional preferredLauncherProfile; private final WorldBuilder worldBuilder; private final LauncherProfileRunner launcherProfileRunner; @@ -64,8 +66,12 @@ public class PerApplicationInjector { this.seedHistoryLogger = SeedHistoryLogger.from(parameters.seedHistoryFile); this.minecraftInstallation = MinecraftInstallation .newLocalMinecraftInstallation(parameters.dotMinecraftDirectory); - this.preferredLauncherProfile = minecraftInstallation - .tryReadLauncherProfile(parameters.minecraftJarFile, parameters.minecraftJsonFile); + this.minetestInstallation = MinetestInstallation + .newLocalMinetestInstallationOrDefault(parameters.minetestDirectory); + //this.preferredLauncherProfile = minecraftInstallation + // .tryReadLauncherProfile(parameters.minecraftJarFile, parameters.minecraftJsonFile); + this.preferredLauncherProfile = minetestInstallation + .defaultLauncherProfile(); this.worldBuilder = new WorldBuilder(playerInformationProvider, seedHistoryLogger); this.launcherProfileRunner = new LauncherProfileRunner(worldBuilder); this.biomeProfileDirectory = BiomeProfileDirectory.create(parameters.biomeProfilesDirectory); @@ -102,7 +108,7 @@ public class PerApplicationInjector { application, metadata, settings, - minecraftInstallation, + minetestInstallation, runningLauncherProfile, biomeProfileDirectory, this::createViewerFacade, @@ -116,7 +122,7 @@ public class PerApplicationInjector { metadata, threadMaster.getWorkerExecutor(), versionListProvider, - minecraftInstallation, + minetestInstallation, launcherProfileRunner, settings); } diff --git a/src/main/java/amidst/fragment/Fragment.java b/src/main/java/amidst/fragment/Fragment.java index 6b42e128..b21861d3 100644 --- a/src/main/java/amidst/fragment/Fragment.java +++ b/src/main/java/amidst/fragment/Fragment.java @@ -83,7 +83,14 @@ public class Fragment { private volatile CoordinatesInWorld corner; private volatile float alpha; - private volatile short[][] biomeData; + private volatile short[][] biomeData; + /** + * a mask to apply to biomeData if you wish to use it like a biome index. + * This will remove any bits from the integer that are being used + * to indicate 1-bit overlay biome layers, such as minetest rivers + * and oceans + */ + private volatile short biomeDataIndexMask; // private volatile List endIslands; private final AtomicReferenceArray images; private final AtomicReferenceArray> worldIcons; @@ -106,14 +113,23 @@ public class Fragment { } @CalledOnlyBy(AmidstThread.FRAGMENT_LOADER) - public void populateBiomeData(BiomeDataOracle biomeDataOracle) { - biomeDataOracle.populateArray(corner, biomeData, true); + public void populateBiomeData(IBiomeDataOracle biomeDataOracle) { + biomeDataIndexMask = biomeDataOracle.populateArray(corner, biomeData, true); } + public short getBiomeIndexAt(int x, int y) { + return (short)(biomeData[x][y] & biomeDataIndexMask); + } + + /** + * Gets the raw data stored in the biomeData array, not to be + * confused with getBiomeIndexAt(), as the raw data may contain + * bitplanes so should not be treated as a short integer index. + */ public short getBiomeDataAt(int x, int y) { return biomeData[x][y]; } - + public void setEndIslands(List endIslands) { this.endIslands = endIslands; } diff --git a/src/main/java/amidst/fragment/IBiomeDataOracle.java b/src/main/java/amidst/fragment/IBiomeDataOracle.java new file mode 100644 index 00000000..499dd609 --- /dev/null +++ b/src/main/java/amidst/fragment/IBiomeDataOracle.java @@ -0,0 +1,17 @@ +package amidst.fragment; + +import amidst.mojangapi.world.coordinates.CoordinatesInWorld; + +public interface IBiomeDataOracle { + + // Returns the biome-index mask: a mask you should apply to the + // returned biome data if you wish to use it like a biome index. + // This will remove any bits from the integer that are being used + // to indicate other things, such as 1-bit overlay biome layers + // for minetest rivers and oceans + public short populateArray( + CoordinatesInWorld corner, + short[][] result, + boolean useQuarterResolution + ); +} diff --git a/src/main/java/amidst/fragment/colorprovider/BiomeColorProvider.java b/src/main/java/amidst/fragment/colorprovider/BiomeColorProvider.java index a5150b1a..397b2d39 100644 --- a/src/main/java/amidst/fragment/colorprovider/BiomeColorProvider.java +++ b/src/main/java/amidst/fragment/colorprovider/BiomeColorProvider.java @@ -19,7 +19,7 @@ public class BiomeColorProvider implements ColorProvider { @Override public int getColorAt(Dimension dimension, Fragment fragment, long cornerX, long cornerY, int x, int y) { - return getColor(fragment.getBiomeDataAt(x, y)); + return getColor(fragment.getBiomeIndexAt(x, y)); } private int getColor(int biomeIndex) { diff --git a/src/main/java/amidst/fragment/colorprovider/MinetestRiverColorProvider.java b/src/main/java/amidst/fragment/colorprovider/MinetestRiverColorProvider.java new file mode 100644 index 00000000..654fd3e2 --- /dev/null +++ b/src/main/java/amidst/fragment/colorprovider/MinetestRiverColorProvider.java @@ -0,0 +1,22 @@ +package amidst.fragment.colorprovider; + +import amidst.documentation.ThreadSafe; +import amidst.fragment.Fragment; +import amidst.mojangapi.world.Dimension; +import amidst.minetest.world.oracle.BiomeDataOracle; + +@ThreadSafe +public class MinetestRiverColorProvider implements ColorProvider { + private static final int RIVER_COLOR = 0xA0FE80FA; + private static final int NOT_RIVER_COLOR = 0x00000000; + + @Override + public int getColorAt(Dimension dimension, Fragment fragment, long cornerX, long cornerY, int x, int y) { + + if ((fragment.getBiomeDataAt(x, y) & BiomeDataOracle.BITPLANE_RIVER) > 0) { + return RIVER_COLOR; + } else { + return NOT_RIVER_COLOR; + } + } +} diff --git a/src/main/java/amidst/fragment/layer/LayerBuilder.java b/src/main/java/amidst/fragment/layer/LayerBuilder.java index e03b4ef0..434c07a4 100644 --- a/src/main/java/amidst/fragment/layer/LayerBuilder.java +++ b/src/main/java/amidst/fragment/layer/LayerBuilder.java @@ -9,6 +9,7 @@ import amidst.documentation.Immutable; import amidst.fragment.Fragment; import amidst.fragment.colorprovider.BackgroundColorProvider; import amidst.fragment.colorprovider.BiomeColorProvider; +import amidst.fragment.colorprovider.MinetestRiverColorProvider; import amidst.fragment.colorprovider.SlimeColorProvider; import amidst.fragment.colorprovider.TheEndColorProvider; import amidst.fragment.constructor.BiomeDataConstructor; @@ -54,6 +55,9 @@ public class LayerBuilder { new BiomeDataConstructor(Resolution.QUARTER), new EndIslandsConstructor(), new ImageConstructor(Resolution.QUARTER, LayerIds.BACKGROUND), + new ImageConstructor(Resolution.QUARTER, LayerIds.MINETEST_RIVER), + new ImageConstructor(Resolution.QUARTER, LayerIds.MINETEST_OCEAN), + new ImageConstructor(Resolution.QUARTER, LayerIds.MINETEST_MOUNTAIN), new ImageConstructor(Resolution.CHUNK, LayerIds.SLIME))); } @@ -99,6 +103,11 @@ public class LayerBuilder { declare(settings, declarations, versionFeatures, LayerIds.OCEAN_MONUMENT, Dimension.OVERWORLD, false, settings.showOceanMonuments); declare(settings, declarations, versionFeatures, LayerIds.NETHER_FORTRESS, Dimension.OVERWORLD, false, settings.showNetherFortresses); declare(settings, declarations, versionFeatures, LayerIds.END_CITY, Dimension.END, false, settings.showEndCities); + + declare(settings, declarations, versionFeatures, LayerIds.MINETEST_RIVER, Dimension.OVERWORLD, false, settings.showMinetestRivers); + declare(settings, declarations, versionFeatures, LayerIds.MINETEST_OCEAN, Dimension.OVERWORLD, false, settings.showMinetestOceans); + declare(settings, declarations, versionFeatures, LayerIds.MINETEST_MOUNTAIN, Dimension.OVERWORLD, false, settings.showMinetestMountains); + // @formatter:on return Collections.unmodifiableList(Arrays.asList(declarations)); } @@ -134,6 +143,7 @@ public class LayerBuilder { new BiomeDataLoader( declarations.get(LayerIds.BIOME_DATA), world.getBiomeDataOracle()), new EndIslandsLoader( declarations.get(LayerIds.END_ISLANDS), world.getEndIslandOracle()), new ImageLoader( declarations.get(LayerIds.BACKGROUND), Resolution.QUARTER, new BackgroundColorProvider(new BiomeColorProvider(biomeSelection, settings.biomeProfileSelection), new TheEndColorProvider())), + new ImageLoader( declarations.get(LayerIds.MINETEST_RIVER), Resolution.QUARTER, new MinetestRiverColorProvider()), new ImageLoader( declarations.get(LayerIds.SLIME), Resolution.CHUNK, new SlimeColorProvider(world.getSlimeChunkOracle())), new WorldIconLoader<>(declarations.get(LayerIds.SPAWN), world.getSpawnProducer()), new WorldIconLoader<>(declarations.get(LayerIds.STRONGHOLD), world.getStrongholdProducer()), @@ -160,6 +170,7 @@ public class LayerBuilder { return Collections.unmodifiableList(Arrays.asList( new AlphaUpdater( declarations.get(LayerIds.ALPHA)), new ImageDrawer( declarations.get(LayerIds.BACKGROUND), Resolution.QUARTER, accelerationCounter), + new ImageDrawer( declarations.get(LayerIds.MINETEST_RIVER), Resolution.QUARTER, accelerationCounter), new ImageDrawer( declarations.get(LayerIds.SLIME), Resolution.CHUNK, accelerationCounter), new GridDrawer( declarations.get(LayerIds.GRID), zoom), new WorldIconDrawer(declarations.get(LayerIds.SPAWN), zoom, worldIconSelection), diff --git a/src/main/java/amidst/fragment/layer/LayerIds.java b/src/main/java/amidst/fragment/layer/LayerIds.java index 6ac1184c..ec11d77d 100644 --- a/src/main/java/amidst/fragment/layer/LayerIds.java +++ b/src/main/java/amidst/fragment/layer/LayerIds.java @@ -24,6 +24,12 @@ public class LayerIds { public static final int OCEAN_MONUMENT = 12; public static final int NETHER_FORTRESS = 13; public static final int END_CITY = 14; - public static final int NUMBER_OF_LAYERS = 15; + + public static final int MINETEST_RIVER = 15; + public static final int MINETEST_OCEAN = 16; + public static final int MINETEST_MOUNTAIN = 17; + + public static final int NUMBER_OF_LAYERS = 18; + // @formatter:on } diff --git a/src/main/java/amidst/fragment/loader/BiomeDataLoader.java b/src/main/java/amidst/fragment/loader/BiomeDataLoader.java index 3b7fec34..f8d39379 100644 --- a/src/main/java/amidst/fragment/loader/BiomeDataLoader.java +++ b/src/main/java/amidst/fragment/loader/BiomeDataLoader.java @@ -4,15 +4,15 @@ import amidst.documentation.AmidstThread; import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; import amidst.fragment.Fragment; +import amidst.fragment.IBiomeDataOracle; import amidst.fragment.layer.LayerDeclaration; import amidst.mojangapi.world.Dimension; -import amidst.mojangapi.world.oracle.BiomeDataOracle; @NotThreadSafe public class BiomeDataLoader extends FragmentLoader { - private final BiomeDataOracle biomeDataOracle; + private final IBiomeDataOracle biomeDataOracle; - public BiomeDataLoader(LayerDeclaration declaration, BiomeDataOracle biomeDataOracle) { + public BiomeDataLoader(LayerDeclaration declaration, IBiomeDataOracle biomeDataOracle) { super(declaration); this.biomeDataOracle = biomeDataOracle; } diff --git a/src/main/java/amidst/gameengineabstraction/GameEngineType.java b/src/main/java/amidst/gameengineabstraction/GameEngineType.java new file mode 100644 index 00000000..88fd1bab --- /dev/null +++ b/src/main/java/amidst/gameengineabstraction/GameEngineType.java @@ -0,0 +1,17 @@ +package amidst.gameengineabstraction; + +public enum GameEngineType { + + MINECRAFT ("Minecraft"), + MINETESTv7 ("Minetest v7"); + + private final String name; + + private GameEngineType(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/amidst/gameengineabstraction/file/IGameInstallation.java b/src/main/java/amidst/gameengineabstraction/file/IGameInstallation.java new file mode 100644 index 00000000..c266a46d --- /dev/null +++ b/src/main/java/amidst/gameengineabstraction/file/IGameInstallation.java @@ -0,0 +1,20 @@ +package amidst.gameengineabstraction.file; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import amidst.mojangapi.file.SaveGame; +import amidst.parsing.FormatException; + +/** + * base interface for MinetestInstallation and MinecraftInstallation + */ +public interface IGameInstallation { + + public List readLauncherProfiles() throws FormatException, IOException; + + public SaveGame newSaveGame(File location) throws IOException, FormatException; + + +} diff --git a/src/main/java/amidst/gameengineabstraction/file/IUnresolvedLauncherProfile.java b/src/main/java/amidst/gameengineabstraction/file/IUnresolvedLauncherProfile.java new file mode 100644 index 00000000..f2ee5b17 --- /dev/null +++ b/src/main/java/amidst/gameengineabstraction/file/IUnresolvedLauncherProfile.java @@ -0,0 +1,17 @@ +package amidst.gameengineabstraction.file; + +import java.io.IOException; + +import amidst.mojangapi.file.LauncherProfile; +import amidst.mojangapi.file.VersionList; +import amidst.parsing.FormatException; + +public interface IUnresolvedLauncherProfile { + + public String getName(); + + public LauncherProfile resolve(VersionList versionList) throws FormatException, IOException; + + public LauncherProfile resolveToVanilla(VersionList versionList) throws FormatException, IOException; + +} diff --git a/src/main/java/amidst/gui/main/Actions.java b/src/main/java/amidst/gui/main/Actions.java index 5566847f..e0469530 100644 --- a/src/main/java/amidst/gui/main/Actions.java +++ b/src/main/java/amidst/gui/main/Actions.java @@ -16,6 +16,7 @@ import amidst.Application; import amidst.documentation.AmidstThread; import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.gui.crash.CrashWindow; import amidst.gui.main.menu.MovePlayerPopupMenu; import amidst.gui.main.viewer.ViewerFacade; @@ -39,6 +40,7 @@ public class Actions { private final SeedSearcherWindow seedSearcherWindow; private final Supplier viewerFacadeSupplier; private final BiomeProfileSelection biomeProfileSelection; + private final GameEngineType gameEngineType; @CalledOnlyBy(AmidstThread.EDT) public Actions( @@ -47,18 +49,20 @@ public class Actions { WorldSwitcher worldSwitcher, SeedSearcherWindow seedSearcherWindow, Supplier viewerFacadeSupplier, - BiomeProfileSelection biomeProfileSelection) { + BiomeProfileSelection biomeProfileSelection, + GameEngineType gameEngineType) { this.application = application; this.dialogs = dialogs; this.worldSwitcher = worldSwitcher; this.seedSearcherWindow = seedSearcherWindow; this.viewerFacadeSupplier = viewerFacadeSupplier; this.biomeProfileSelection = biomeProfileSelection; + this.gameEngineType = gameEngineType; } @CalledOnlyBy(AmidstThread.EDT) public void newFromSeed() { - WorldSeed seed = dialogs.askForSeed(); + WorldSeed seed = dialogs.askForSeed(gameEngineType); if (seed != null) { newFromSeed(seed); } @@ -66,7 +70,7 @@ public class Actions { @CalledOnlyBy(AmidstThread.EDT) public void newFromRandom() { - newFromSeed(WorldSeed.random()); + newFromSeed(WorldSeed.random(gameEngineType)); } @CalledOnlyBy(AmidstThread.EDT) diff --git a/src/main/java/amidst/gui/main/MainWindowDialogs.java b/src/main/java/amidst/gui/main/MainWindowDialogs.java index c521057d..6d3130e3 100644 --- a/src/main/java/amidst/gui/main/MainWindowDialogs.java +++ b/src/main/java/amidst/gui/main/MainWindowDialogs.java @@ -11,6 +11,7 @@ import amidst.AmidstSettings; import amidst.documentation.AmidstThread; import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.logging.AmidstMessageBox; import amidst.mojangapi.RunningLauncherProfile; import amidst.mojangapi.world.WorldSeed; @@ -41,8 +42,8 @@ public class MainWindowDialogs { } @CalledOnlyBy(AmidstThread.EDT) - public WorldSeed askForSeed() { - return new SeedPrompt(frame).askForSeed(); + public WorldSeed askForSeed(GameEngineType engine_type) { + return new SeedPrompt(frame, engine_type).askForSeed(); } @CalledOnlyBy(AmidstThread.EDT) diff --git a/src/main/java/amidst/gui/main/PerMainWindowInjector.java b/src/main/java/amidst/gui/main/PerMainWindowInjector.java index c042b545..3d79d5b3 100644 --- a/src/main/java/amidst/gui/main/PerMainWindowInjector.java +++ b/src/main/java/amidst/gui/main/PerMainWindowInjector.java @@ -13,13 +13,14 @@ import amidst.dependency.injection.Factory2; import amidst.documentation.AmidstThread; import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; +import amidst.gameengineabstraction.GameEngineType; +import amidst.gameengineabstraction.file.IGameInstallation; import amidst.gui.main.menu.AmidstMenu; import amidst.gui.main.menu.AmidstMenuBuilder; import amidst.gui.main.viewer.ViewerFacade; import amidst.gui.seedsearcher.SeedSearcher; import amidst.gui.seedsearcher.SeedSearcherWindow; import amidst.mojangapi.RunningLauncherProfile; -import amidst.mojangapi.file.MinecraftInstallation; import amidst.mojangapi.world.World; import amidst.settings.biomeprofile.BiomeProfileDirectory; import amidst.threading.ThreadMaster; @@ -52,17 +53,21 @@ public class PerMainWindowInjector { private final Actions actions; private final AmidstMenu menuBar; private final MainWindow mainWindow; + private final GameEngineType gameEngine; @CalledOnlyBy(AmidstThread.EDT) public PerMainWindowInjector( Application application, AmidstMetaData metadata, AmidstSettings settings, - MinecraftInstallation minecraftInstallation, + IGameInstallation gameInstallation, RunningLauncherProfile runningLauncherProfile, BiomeProfileDirectory biomeProfileDirectory, Factory2 viewerFacadeFactory, ThreadMaster threadMaster) { + + gameEngine = runningLauncherProfile.getGameEngineType(); + this.viewerFacadeFactory = viewerFacadeFactory; this.versionString = createVersionString(metadata, runningLauncherProfile); this.frame = new JFrame(); @@ -70,7 +75,7 @@ public class PerMainWindowInjector { this.viewerFacadeReference = new AtomicReference<>(); this.dialogs = new MainWindowDialogs(settings, runningLauncherProfile, frame); this.worldSwitcher = new WorldSwitcher( - minecraftInstallation, + gameInstallation, runningLauncherProfile, this::createViewerFacade, threadMaster, @@ -95,7 +100,8 @@ public class PerMainWindowInjector { worldSwitcher, seedSearcherWindow, viewerFacadeReference::get, - settings.biomeProfileSelection); + settings.biomeProfileSelection, + gameEngine); this.menuBar = new AmidstMenuBuilder(settings, actions, biomeProfileDirectory).construct(); this.mainWindow = new MainWindow(frame, worldSwitcher, seedSearcherWindow); this.mainWindow.initializeFrame(metadata, versionString, actions, menuBar); diff --git a/src/main/java/amidst/gui/main/SeedPrompt.java b/src/main/java/amidst/gui/main/SeedPrompt.java index 2fc08e48..bc229031 100644 --- a/src/main/java/amidst/gui/main/SeedPrompt.java +++ b/src/main/java/amidst/gui/main/SeedPrompt.java @@ -15,6 +15,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import amidst.documentation.NotThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.mojangapi.world.WorldSeed; import amidst.mojangapi.world.WorldSeed.WorldSeedType; import net.miginfocom.swing.MigLayout; @@ -31,13 +32,16 @@ public class SeedPrompt { private final JLabel warningLabel; private final JPanel panel; private WorldSeed seed; + private GameEngineType engineType; - public SeedPrompt(JFrame frame) { + public SeedPrompt(JFrame frame, GameEngineType engine_type) { this.frame = frame; this.textField = createTextField(); this.seedLabel = createSeedLabel(); this.warningLabel = createWarningLabel(); this.panel = createPanel(); + + this.engineType = engine_type; } private JTextField createTextField() { @@ -111,7 +115,8 @@ public class SeedPrompt { } private void update() { - seed = WorldSeed.fromUserInput(textField.getText()); + + seed = WorldSeed.fromUserInput(textField.getText(), engineType); if (WorldSeedType.TEXT == seed.getType() && seed.getText().startsWith(" ")) { warningLabel.setText(STARTS_WITH_SPACE_TEXT); } else if (WorldSeedType.TEXT == seed.getType() && seed.getText().endsWith(" ")) { diff --git a/src/main/java/amidst/gui/main/WorldSwitcher.java b/src/main/java/amidst/gui/main/WorldSwitcher.java index 485db0a0..e0bff4ed 100644 --- a/src/main/java/amidst/gui/main/WorldSwitcher.java +++ b/src/main/java/amidst/gui/main/WorldSwitcher.java @@ -15,9 +15,9 @@ import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; import amidst.gui.main.menu.AmidstMenu; import amidst.gui.main.viewer.ViewerFacade; +import amidst.gameengineabstraction.file.IGameInstallation; import amidst.logging.AmidstLogger; import amidst.mojangapi.RunningLauncherProfile; -import amidst.mojangapi.file.MinecraftInstallation; import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException; import amidst.mojangapi.world.World; import amidst.mojangapi.world.WorldSeed; @@ -29,7 +29,7 @@ import amidst.threading.ThreadMaster; @NotThreadSafe public class WorldSwitcher { - private final MinecraftInstallation minecraftInstallation; + private final IGameInstallation minecraftInstallation; private final RunningLauncherProfile runningLauncherProfile; private final Factory1 viewerFacadeFactory; private final ThreadMaster threadMaster; @@ -41,7 +41,7 @@ public class WorldSwitcher { @CalledOnlyBy(AmidstThread.EDT) public WorldSwitcher( - MinecraftInstallation minecraftInstallation, + IGameInstallation minecraftInstallation, RunningLauncherProfile runningLauncherProfile, Factory1 viewerFacadeFactory, ThreadMaster threadMaster, @@ -75,9 +75,9 @@ public class WorldSwitcher { @CalledOnlyBy(AmidstThread.EDT) public void displayWorld(File file) { try { - clearViewerFacade(); + clearViewerFacade(); setWorld(runningLauncherProfile.createWorldFromSaveGame(minecraftInstallation.newSaveGame(file))); - } catch (IllegalStateException | MinecraftInterfaceException | IOException | FormatException e) { + } catch (IllegalStateException | MinecraftInterfaceException | IOException | FormatException | UnsupportedOperationException e) { AmidstLogger.warn(e); dialogs.displayError(e); } diff --git a/src/main/java/amidst/gui/main/menu/LayersMenu.java b/src/main/java/amidst/gui/main/menu/LayersMenu.java index 8fc9f2fa..9792dffe 100644 --- a/src/main/java/amidst/gui/main/menu/LayersMenu.java +++ b/src/main/java/amidst/gui/main/menu/LayersMenu.java @@ -61,7 +61,13 @@ public class LayersMenu { @CalledOnlyBy(AmidstThread.EDT) private void createDimensionLayers(Dimension dimension) { - if (viewerFacade.hasLayer(LayerIds.END_ISLANDS)) { + if (viewerFacade.hasLayer(LayerIds.MINETEST_OCEAN)) { + createAllDimensions(); + menu.addSeparator(); + createMinetestLayers(dimension); + createEnableAllLayersIfNecessary(); + + } else if (viewerFacade.hasLayer(LayerIds.END_ISLANDS)) { createAllDimensions(); menu.addSeparator(); createOverworldAndEndLayers(dimension); @@ -96,6 +102,21 @@ public class LayersMenu { // @formatter:on } + @CalledOnlyBy(AmidstThread.EDT) + private void createMinetestLayers(Dimension dimension) { + // @formatter:off + overworldLayer(settings.showMinetestRivers, "Rivers", getIcon("slime.png"), MenuShortcuts.SHOW_MINETEST_RIVERS, dimension, LayerIds.MINETEST_RIVER); + overworldLayer(settings.showMinetestOceans, "Oceans", getIcon("slime.png"), MenuShortcuts.SHOW_MINETEST_OCEANS, dimension, LayerIds.MINETEST_OCEAN); + overworldLayer(settings.showMinetestMountains, "Mountains", getIcon("slime.png"), MenuShortcuts.SHOW_MINETEST_MOUNTAINS, dimension, LayerIds.MINETEST_MOUNTAIN); + + // temp for debug + // (Remove SLIME from DefaultVersionFeatures as well when finished) + if (viewerFacade.hasLayer(LayerIds.SLIME)) { + overworldLayer(settings.showSlimeChunks, "Slime Chunks", getIcon("slime.png"), MenuShortcuts.SHOW_SLIME_CHUNKS, dimension, LayerIds.SLIME); + } + // @formatter:on + } + @CalledOnlyBy(AmidstThread.EDT) private void createOverworldLayers(Dimension dimension) { // @formatter:off diff --git a/src/main/java/amidst/gui/main/menu/MenuShortcuts.java b/src/main/java/amidst/gui/main/menu/MenuShortcuts.java index de30c107..8b887e36 100644 --- a/src/main/java/amidst/gui/main/menu/MenuShortcuts.java +++ b/src/main/java/amidst/gui/main/menu/MenuShortcuts.java @@ -42,6 +42,11 @@ public enum MenuShortcuts implements MenuShortcut { SHOW_OCEAN_MONUMENTS("menu 7"), SHOW_NETHER_FORTRESSES("menu 8"), SHOW_END_CITIES("menu 9"), + + SHOW_MINETEST_RIVERS("menu 1"), + SHOW_MINETEST_OCEANS("menu 2"), + SHOW_MINETEST_MOUNTAINS("menu 3"), + SHOW_GRID("menu G"), SHOW_PLAYERS("menu P"), ENABLE_ALL_LAYERS("menu E"), diff --git a/src/main/java/amidst/gui/main/viewer/widget/CursorInformationWidget.java b/src/main/java/amidst/gui/main/viewer/widget/CursorInformationWidget.java index c802b72b..9782f633 100644 --- a/src/main/java/amidst/gui/main/viewer/widget/CursorInformationWidget.java +++ b/src/main/java/amidst/gui/main/viewer/widget/CursorInformationWidget.java @@ -71,7 +71,7 @@ public class CursorInformationWidget extends TextWidget { if (fragment != null && fragment.isLoaded()) { long x = coordinates.getXRelativeToFragmentAs(Resolution.QUARTER); long y = coordinates.getYRelativeToFragmentAs(Resolution.QUARTER); - short biome = fragment.getBiomeDataAt((int) x, (int) y); + short biome = fragment.getBiomeIndexAt((int) x, (int) y); try { return Biome.getByIndex(biome).getName(); } catch (UnknownBiomeIndexException e) { diff --git a/src/main/java/amidst/gui/profileselect/LocalProfileComponent.java b/src/main/java/amidst/gui/profileselect/LocalProfileComponent.java index fc578548..006d4245 100644 --- a/src/main/java/amidst/gui/profileselect/LocalProfileComponent.java +++ b/src/main/java/amidst/gui/profileselect/LocalProfileComponent.java @@ -9,10 +9,10 @@ import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; import amidst.logging.AmidstLogger; import amidst.logging.AmidstMessageBox; +import amidst.gameengineabstraction.file.IUnresolvedLauncherProfile; import amidst.mojangapi.LauncherProfileRunner; import amidst.mojangapi.RunningLauncherProfile; import amidst.mojangapi.file.LauncherProfile; -import amidst.mojangapi.file.UnresolvedLauncherProfile; import amidst.mojangapi.file.VersionListProvider; import amidst.mojangapi.minecraftinterface.local.LocalMinecraftInterfaceCreationException; import amidst.parsing.FormatException; @@ -24,7 +24,7 @@ public class LocalProfileComponent extends ProfileComponent { private final WorkerExecutor workerExecutor; private final VersionListProvider versionListProvider; private final LauncherProfileRunner launcherProfileRunner; - private final UnresolvedLauncherProfile unresolvedProfile; + private final IUnresolvedLauncherProfile unresolvedProfile; private volatile boolean isResolving = false; private volatile boolean failedResolving = false; @@ -38,7 +38,7 @@ public class LocalProfileComponent extends ProfileComponent { WorkerExecutor workerExecutor, VersionListProvider versionListProvider, LauncherProfileRunner launcherProfileRunner, - UnresolvedLauncherProfile unresolvedProfile) { + IUnresolvedLauncherProfile unresolvedProfile) { this.application = application; this.workerExecutor = workerExecutor; this.versionListProvider = versionListProvider; diff --git a/src/main/java/amidst/gui/profileselect/ProfileSelectWindow.java b/src/main/java/amidst/gui/profileselect/ProfileSelectWindow.java index 61417f6e..6a48b964 100644 --- a/src/main/java/amidst/gui/profileselect/ProfileSelectWindow.java +++ b/src/main/java/amidst/gui/profileselect/ProfileSelectWindow.java @@ -20,9 +20,9 @@ import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; import amidst.logging.AmidstLogger; import amidst.logging.AmidstMessageBox; +import amidst.gameengineabstraction.file.IGameInstallation; +import amidst.gameengineabstraction.file.IUnresolvedLauncherProfile; import amidst.mojangapi.LauncherProfileRunner; -import amidst.mojangapi.file.MinecraftInstallation; -import amidst.mojangapi.file.UnresolvedLauncherProfile; import amidst.mojangapi.file.VersionListProvider; import amidst.parsing.FormatException; import amidst.threading.WorkerExecutor; @@ -36,7 +36,7 @@ public class ProfileSelectWindow { private final AmidstMetaData metadata; private final WorkerExecutor workerExecutor; private final VersionListProvider versionListProvider; - private final MinecraftInstallation minecraftInstallation; + private final IGameInstallation gameInstallation; private final LauncherProfileRunner launcherProfileRunner; private final AmidstSettings settings; @@ -51,14 +51,14 @@ public class ProfileSelectWindow { AmidstMetaData metadata, WorkerExecutor workerExecutor, VersionListProvider versionListProvider, - MinecraftInstallation minecraftInstallation, + IGameInstallation gameInstallation, LauncherProfileRunner launcherProfileRunner, AmidstSettings settings) { this.application = application; this.metadata = metadata; this.workerExecutor = workerExecutor; this.versionListProvider = versionListProvider; - this.minecraftInstallation = minecraftInstallation; + this.gameInstallation = gameInstallation; this.launcherProfileRunner = launcherProfileRunner; this.settings = settings; this.profileSelectPanel = new ProfileSelectPanel(settings.lastProfile, "Scanning..."); @@ -122,22 +122,22 @@ public class ProfileSelectWindow { } @CalledOnlyBy(AmidstThread.WORKER) - private List scanAndLoadProfiles() throws FormatException, IOException { + private List scanAndLoadProfiles() throws FormatException, IOException { AmidstLogger.info("Scanning for profiles."); - List launcherProfiles = minecraftInstallation.readLauncherProfiles(); + List launcherProfiles = gameInstallation.readLauncherProfiles(); AmidstLogger.info("Successfully loaded profile list."); return launcherProfiles; } @CalledOnlyBy(AmidstThread.EDT) - private void displayProfiles(List launcherProfiles) { + private void displayProfiles(List launcherProfiles) { createProfileComponentsIfNecessary(launcherProfiles); restoreSelection(); frame.pack(); } @CalledOnlyBy(AmidstThread.EDT) - private void createProfileComponentsIfNecessary(List launcherProfiles) { + private void createProfileComponentsIfNecessary(List launcherProfiles) { if (launcherProfiles.isEmpty()) { AmidstLogger.warn("No profiles found in launcher_profiles.json"); profileSelectPanel.setEmptyMessage("No profiles found"); @@ -155,8 +155,8 @@ public class ProfileSelectWindow { } @CalledOnlyBy(AmidstThread.EDT) - private void createProfileComponents(List launcherProfiles) { - for (UnresolvedLauncherProfile profile : launcherProfiles) { + private void createProfileComponents(List launcherProfiles) { + for (IUnresolvedLauncherProfile profile : launcherProfiles) { profileSelectPanel.addProfile( new LocalProfileComponent( application, diff --git a/src/main/java/amidst/gui/seedsearcher/SeedSearcher.java b/src/main/java/amidst/gui/seedsearcher/SeedSearcher.java index f1e4fa85..fd8da55a 100644 --- a/src/main/java/amidst/gui/seedsearcher/SeedSearcher.java +++ b/src/main/java/amidst/gui/seedsearcher/SeedSearcher.java @@ -5,6 +5,7 @@ import java.util.function.Consumer; import amidst.documentation.AmidstThread; import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.gui.main.MainWindowDialogs; import amidst.logging.AmidstLogger; import amidst.mojangapi.RunningLauncherProfile; @@ -93,7 +94,7 @@ public class SeedSearcher { throws IllegalStateException, MinecraftInterfaceException { while (!isStopRequested) { - World world = runningLauncherProfile.createWorldFromSeed(WorldSeed.random(), configuration.getWorldType()); + World world = runningLauncherProfile.createWorldFromSeed(WorldSeed.random(GameEngineType.MINECRAFT), configuration.getWorldType()); if (configuration.getWorldFilter().isValid(world)) { reporter.report(world.getWorldSeed()); world.dispose(); diff --git a/src/main/java/amidst/minetest/MinetestLauncherProfile.java b/src/main/java/amidst/minetest/MinetestLauncherProfile.java new file mode 100644 index 00000000..5544069e --- /dev/null +++ b/src/main/java/amidst/minetest/MinetestLauncherProfile.java @@ -0,0 +1,38 @@ +package amidst.minetest; + +import amidst.minetest.file.directory.MinetestDirectory; +import amidst.minetest.world.mapgen.MapgenV7Params; +import amidst.mojangapi.file.LauncherProfile; +import amidst.mojangapi.file.json.version.VersionJson; + +public class MinetestLauncherProfile extends LauncherProfile { + + // Can be null! (minetest might not be installed, and we might be using + // defaults) + private final MinetestDirectory minetestDirectory; + + public static MinetestLauncherProfile InternalDefault = new MinetestLauncherProfile( + null, "Minetest mapgen v7 default"); + + public MinetestLauncherProfile(MinetestDirectory minetestDirectory, + String profileName) { + + super(null, // dotMinecraftDirectory, + null, // profileDirectory, + null, // versionDirectory, + new VersionJson("v7", null), // versionJson, + true, // isVersionListedInProfile, + profileName); + + this.minetestDirectory = minetestDirectory; + + // TODO Auto-generated constructor stub + } + + public MapgenV7Params getMapGenParams() { + + // TODO: fetch the MapgenV7Params from MinetestDirectory + return new MapgenV7Params(); + } + +} diff --git a/src/main/java/amidst/minetest/MinetestMapgenV7Interface.java b/src/main/java/amidst/minetest/MinetestMapgenV7Interface.java new file mode 100644 index 00000000..b07666c1 --- /dev/null +++ b/src/main/java/amidst/minetest/MinetestMapgenV7Interface.java @@ -0,0 +1,42 @@ +package amidst.minetest; + +import amidst.gameengineabstraction.GameEngineType; +import amidst.minetest.world.mapgen.MapgenV7Params; +import amidst.mojangapi.minecraftinterface.MinecraftInterface; +import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException; +import amidst.mojangapi.minecraftinterface.RecognisedVersion; +import amidst.mojangapi.world.WorldType; + +public class MinetestMapgenV7Interface implements MinecraftInterface { + + public final MapgenV7Params params; + + public MinetestMapgenV7Interface(MapgenV7Params params) { + + this.params = params; + } + + @Override + public int[] getBiomeData(int x, int y, int width, int height, + boolean useQuarterResolution) throws MinecraftInterfaceException { + // TODO Auto-generated method stub + return null; + } + + @Override + public void createWorld(long seed, WorldType worldType, + String generatorOptions) throws MinecraftInterfaceException { + // TODO Auto-generated method stub + + } + + @Override + public RecognisedVersion getRecognisedVersion() { + return RecognisedVersion.Minetest_v7; + } + + @Override + public GameEngineType getGameEngineType() { + return GameEngineType.MINETESTv7; + } +} diff --git a/src/main/java/amidst/minetest/file/MinetestInstallation.java b/src/main/java/amidst/minetest/file/MinetestInstallation.java new file mode 100644 index 00000000..cb6fbe22 --- /dev/null +++ b/src/main/java/amidst/minetest/file/MinetestInstallation.java @@ -0,0 +1,145 @@ +package amidst.minetest.file; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import amidst.documentation.Immutable; +import amidst.logging.AmidstLogger; +import amidst.gameengineabstraction.file.IUnresolvedLauncherProfile; +import amidst.gameengineabstraction.file.IGameInstallation; +import amidst.minetest.MinetestLauncherProfile; +import amidst.minetest.file.directory.MinetestDirectory; +import amidst.minetest.file.service.MinetestDirectoryService; +import amidst.minetest.file.UnresolvedLauncherProfile; +import amidst.mojangapi.file.DotMinecraftDirectoryNotFoundException; +import amidst.mojangapi.file.LauncherProfile; +import amidst.mojangapi.file.SaveGame; +import amidst.mojangapi.file.directory.DotMinecraftDirectory; +import amidst.mojangapi.file.directory.SaveDirectory; +import amidst.mojangapi.file.directory.VersionDirectory; +import amidst.mojangapi.file.json.version.VersionJson; +import amidst.mojangapi.file.service.DotMinecraftDirectoryService; +import amidst.mojangapi.file.service.SaveDirectoryService; +import amidst.parsing.FormatException; +import amidst.parsing.json.JsonReader; + +@Immutable +public class MinetestInstallation implements IGameInstallation { + + public static MinetestInstallation newLocalMinetestInstallation() throws DotMinecraftDirectoryNotFoundException { + return newLocalMinetestInstallationOrDefault(null); + } + + public static MinetestInstallation newLocalMinetestInstallationOrDefault(String preferredMinetestDirectory) { + + MinetestDirectory minetestDirectory = null; + try { + minetestDirectory = new MinetestDirectoryService() + .createMinetestDirectory(preferredMinetestDirectory); + AmidstLogger.info("using minetest directory at: '" + minetestDirectory.getRoot() + "'"); + } catch (DotMinecraftDirectoryNotFoundException e) { + + AmidstLogger.info("Minetest directory not found, using default mapgen v7 profile"); + } + return new MinetestInstallation(minetestDirectory); + } + + private final MinetestDirectoryService minetestDirectoryService = new MinetestDirectoryService(); + private final MinetestDirectory minetestDirectory; + + public MinetestInstallation(MinetestDirectory minetestDirectory) { + this.minetestDirectory = minetestDirectory; + } + + + public Optional defaultLauncherProfile() { + + return Optional.of(MinetestLauncherProfile.InternalDefault); + } + + public SaveGame newSaveGame(File location) throws IOException, FormatException { + //SaveDirectory saveDirectory = saveDirectoryService.newSaveDirectory(location); + //return new SaveGame(saveDirectory, saveDirectoryService.readLevelDat(saveDirectory)); + throw new UnsupportedOperationException("need to add support for world saves"); + } + + @Override + public List readLauncherProfiles() + throws FormatException, IOException { + // TODO Auto-generated method stub + + ArrayList result = new ArrayList(); + result.add(new UnresolvedLauncherProfile()); + return result; + } + + /* + public List readInstalledVersionsAsLauncherProfiles() throws FormatException, IOException { + List result = new LinkedList<>(); + for (VersionDirectory versionDirectory : minetestDirectoryService + .findInstalledValidVersionDirectories(minetestDirectory)) { + result.add(newLauncherProfile(versionDirectory)); + } + return result; + } + + public List readLauncherProfiles() throws FormatException, IOException { + return minetestDirectoryService + .readLauncherProfilesFrom(minetestDirectory) + .getProfiles() + .values() + .stream() + .map(p -> new UnresolvedLauncherProfile(minetestDirectory, p)) + .collect(Collectors.toList()); + } + + public LauncherProfile newLauncherProfile(String versionId) throws FormatException, IOException { + return newLauncherProfile( + minetestDirectoryService.createValidVersionDirectory(minetestDirectory, versionId)); + } + + public LauncherProfile newLauncherProfile(File jar, File json) throws FormatException, IOException { + return newLauncherProfile(minetestDirectoryService.createValidVersionDirectory(jar, json)); + } + + private LauncherProfile newLauncherProfile(VersionDirectory versionDirectory) throws FormatException, IOException { + VersionJson versionJson = JsonReader.readLocation(versionDirectory.getJson(), VersionJson.class); + return new LauncherProfile( + minetestDirectory, + minetestDirectory.asProfileDirectory(), + versionDirectory, + versionJson, + false, + versionJson.getId()); + } + + public SaveGame newSaveGame(File location) throws IOException, FormatException { + SaveDirectory saveDirectory = saveDirectoryService.newSaveDirectory(location); + return new SaveGame(saveDirectory, saveDirectoryService.readLevelDat(saveDirectory)); + } + + public Optional tryReadLauncherProfile( + String preferredMinecraftJarFile, + String preferredMinecraftJsonFile) { + if (preferredMinecraftJarFile != null && preferredMinecraftJsonFile != null) { + try { + return Optional.of( + newLauncherProfile(new File(preferredMinecraftJarFile), new File(preferredMinecraftJsonFile))); + } catch (FormatException | IOException e) { + AmidstLogger.error( + e, + "cannot read launcher profile. preferredMinecraftJarFile: '" + preferredMinecraftJarFile + + "', preferredMinecraftJsonFile: '" + "'"); + return Optional.empty(); + } + } else { + return Optional.empty(); + } + } + */ +} diff --git a/src/main/java/amidst/minetest/file/UnresolvedLauncherProfile.java b/src/main/java/amidst/minetest/file/UnresolvedLauncherProfile.java new file mode 100644 index 00000000..d00b452c --- /dev/null +++ b/src/main/java/amidst/minetest/file/UnresolvedLauncherProfile.java @@ -0,0 +1,45 @@ +package amidst.minetest.file; + +import java.io.IOException; + +import amidst.documentation.Immutable; +import amidst.gameengineabstraction.file.IUnresolvedLauncherProfile; +import amidst.minetest.MinetestLauncherProfile; +import amidst.minetest.file.directory.MinetestDirectory; +import amidst.mojangapi.file.LauncherProfile; +import amidst.mojangapi.file.VersionList; +import amidst.parsing.FormatException; + +@Immutable +public class UnresolvedLauncherProfile implements IUnresolvedLauncherProfile { + private final MinetestDirectory minetestDirectory; + private final String name; + + public UnresolvedLauncherProfile( + MinetestDirectory minetestDirectory, + String name) { + this.minetestDirectory = minetestDirectory; + this.name = name; + } + + public UnresolvedLauncherProfile() { + this.minetestDirectory = null; + this.name = MinetestLauncherProfile.InternalDefault.getProfileName(); + } + + public String getName() { + return name; + } + + @Override + public LauncherProfile resolve(VersionList versionList) throws FormatException, IOException { + return new MinetestLauncherProfile(minetestDirectory, name); + } + + @Override + public LauncherProfile resolveToVanilla(VersionList versionList) throws FormatException, IOException { + // Vanilla is a concept for modded Minecraft, Minetest doesn't need it. + return resolve(versionList); + } + +} diff --git a/src/main/java/amidst/minetest/file/directory/MinetestDirectory.java b/src/main/java/amidst/minetest/file/directory/MinetestDirectory.java new file mode 100644 index 00000000..ac22ce94 --- /dev/null +++ b/src/main/java/amidst/minetest/file/directory/MinetestDirectory.java @@ -0,0 +1,74 @@ +package amidst.minetest.file.directory; + +import java.io.File; +import java.util.Objects; + +import amidst.documentation.Immutable; + +@Immutable +public class MinetestDirectory { + /** + * Allows to customize all parts of the minetest directory, mainly for + * testing and the dev tools. Pass null to use default values. + */ + public static MinetestDirectory newCustom( + File root, + File games, + File worlds, + File mods, + File launcherProfilesJson) { + Objects.requireNonNull(root); + return new MinetestDirectory( + root, + games != null ? games : new File(root, "games"), + worlds != null ? worlds : new File(root, "worlds"), + mods != null ? mods : new File(root, "mods"), + launcherProfilesJson != null ? launcherProfilesJson : new File(root, "launcher_profiles.json")); + } + + private final File root; + private final File mods; + private final File worlds; + private final File games; + private final File launcherProfilesJson; + + public MinetestDirectory(File root) { + this.root = root; + this.mods = new File(root, "mods"); + this.worlds = new File(root, "worlds"); + this.games = new File(root, "games"); + this.launcherProfilesJson = new File(root, "launcher_profiles.json"); + } + + private MinetestDirectory(File root, File games, File worlds, File mods, File launcherProfilesJson) { + this.root = root; + this.games = games; + this.worlds = worlds; + this.mods = mods; + this.launcherProfilesJson = launcherProfilesJson; + } + + public boolean isValid() { + return root.isDirectory() && mods.isDirectory() && games.isDirectory() && launcherProfilesJson.isFile(); + } + + public File getRoot() { + return root; + } + + public File getMods() { + return mods; + } + + public File getWorlds() { + return worlds; + } + + public File getGames() { + return games; + } + + public File getLauncherProfilesJson() { + return launcherProfilesJson; + } +} diff --git a/src/main/java/amidst/minetest/file/service/MinetestDirectoryService.java b/src/main/java/amidst/minetest/file/service/MinetestDirectoryService.java new file mode 100644 index 00000000..0d041514 --- /dev/null +++ b/src/main/java/amidst/minetest/file/service/MinetestDirectoryService.java @@ -0,0 +1,74 @@ +package amidst.minetest.file.service; + +import java.io.File; + +import amidst.documentation.Immutable; +import amidst.documentation.NotNull; +import amidst.logging.AmidstLogger; +import amidst.minetest.file.directory.MinetestDirectory; +import amidst.mojangapi.file.DotMinecraftDirectoryNotFoundException; +import amidst.util.OperatingSystemDetector; + +@Immutable +public class MinetestDirectoryService { + + @NotNull + public MinetestDirectory createMinetestDirectory(String preferredMinetestDirectory) + throws DotMinecraftDirectoryNotFoundException { + return validate(new MinetestDirectory(findMinetestDirectory(preferredMinetestDirectory))); + } + + @NotNull + private MinetestDirectory validate(MinetestDirectory minecraftDirectory) + throws DotMinecraftDirectoryNotFoundException { + if (minecraftDirectory.isValid()) { + return minecraftDirectory; + } else { + throw new DotMinecraftDirectoryNotFoundException( + "invalid mintest directory at: '" + minecraftDirectory.getRoot() + "'"); + } + } + + @NotNull + private File findMinetestDirectory(String preferredMinetestDirectory) throws DotMinecraftDirectoryNotFoundException { + + File result = null; + + if (preferredMinetestDirectory != null) { + result = new File(preferredMinetestDirectory); + if (!result.isDirectory()) { + AmidstLogger.warn( + "Unable to set Minetest directory to: " + result + + " as that location does not exist or is not a folder."); + result = getMinetestDirectory(); + } + } else { + result = getMinetestDirectory(); + } + + if (result == null) throw new DotMinecraftDirectoryNotFoundException("unable to locate minetest directory"); + return result; + } + + private File getMinetestDirectory() { + + File result = null; + + File home = new File(System.getProperty("user.home", ".")); + if (OperatingSystemDetector.isWindows()) { + result = new File("C:\\minetest"); + if (!result.isDirectory()) result = new File("C:\\games\\minetest"); + if (!result.isDirectory()) result = null; + + } else if (OperatingSystemDetector.isMac()) { + // /home/username/.minetest/ + } + + if (result == null) result = new File(home, ".minetest"); + if (!result.isDirectory()) result = new File(home, "minetest"); + + if (!result.isDirectory()) result = null; + + return result; + } +} diff --git a/src/main/java/amidst/minetest/world/mapgen/Constants.java b/src/main/java/amidst/minetest/world/mapgen/Constants.java new file mode 100644 index 00000000..9782c646 --- /dev/null +++ b/src/main/java/amidst/minetest/world/mapgen/Constants.java @@ -0,0 +1,10 @@ +package amidst.minetest.world.mapgen; + +public class Constants { + + // Dimension of a MapBlock + // WARNING: A MineTest MapBlock is similar to a Minecraft Chunk, while + // a Minetest Chunk is 5 x 5 x 5 MapBlocks! + public static final int MAP_BLOCKSIZE = 16; + +} diff --git a/src/main/java/amidst/minetest/world/mapgen/InvalidNoiseParamsException.java b/src/main/java/amidst/minetest/world/mapgen/InvalidNoiseParamsException.java new file mode 100644 index 00000000..da541813 --- /dev/null +++ b/src/main/java/amidst/minetest/world/mapgen/InvalidNoiseParamsException.java @@ -0,0 +1,16 @@ +package amidst.minetest.world.mapgen; + +import amidst.documentation.Immutable; + +@SuppressWarnings("serial") +@Immutable +public class InvalidNoiseParamsException extends Exception { + + public InvalidNoiseParamsException() { + super(); + } + + public InvalidNoiseParamsException(String message) { + super(message); + } +} diff --git a/src/main/java/amidst/minetest/world/mapgen/MapgenV7Params.java b/src/main/java/amidst/minetest/world/mapgen/MapgenV7Params.java new file mode 100644 index 00000000..66a6544a --- /dev/null +++ b/src/main/java/amidst/minetest/world/mapgen/MapgenV7Params.java @@ -0,0 +1,73 @@ +package amidst.minetest.world.mapgen; + +import javax.vecmath.Vector3f; + +public class MapgenV7Params { + + public static final int FLAG_V7_MOUNTAINS = 0x01; + public static final int FLAG_V7_RIDGES = 0x02; + public static final int FLAG_V7_FLOATLANDS = 0x04; + public static final int FLAG_V7_CAVERNS = 0x08; + public static final int FLAG_V7_BIOMEREPEAT = 0x10; // Now unused + + /* + private short mount_zero_level; + private short large_cave_depth; + private float float_mount_density; + private float float_mount_height; + private float float_mount_exponent; + private short floatland_level; + private short shadow_limit; + private short dungeon_ymin; + private short dungeon_ymax; + + private Noise noise_terrain_alt; + private Noise noise_terrain_persist; + private Noise noise_height_select; + private Noise noise_mount_height; + private Noise noise_ridge_uwater; + private Noise noise_floatland_base; + private Noise noise_float_base_height; + private Noise noise_mountain; + private Noise noise_ridge; + */ + + + + public int spflags = FLAG_V7_MOUNTAINS | FLAG_V7_RIDGES | FLAG_V7_CAVERNS; + short mount_zero_level = 0; + float cave_width = 0.09f; + short large_cave_depth = -33; + short lava_depth = -256; + float float_mount_density = 0.6f; + float float_mount_height = 128.0f; + float float_mount_exponent = 0.75f; + short floatland_level = 1280; + short shadow_limit = 1024; + short cavern_limit = -256; + short cavern_taper = 256; + float cavern_threshold = 0.7f; + short dungeon_ymin = -31000; + short dungeon_ymax = 31000; + + int chunksize_in_mapblocks = 5; + public int chunk_length_x = chunksize_in_mapblocks * Constants.MAP_BLOCKSIZE; + public int chunk_length_y = chunk_length_x; + public int chunk_length_z = chunk_length_x; + + // params that aren't public aren't being used by Amidst + NoiseParams np_terrain_base = new NoiseParams(4, 70, new Vector3f(600, 600, 600), 82341, (short)5, 0.6f, 2.0f); + NoiseParams np_terrain_alt = new NoiseParams(4, 25, new Vector3f(600, 600, 600), 5934, (short)5, 0.6f, 2.0f); + NoiseParams np_terrain_persist = new NoiseParams(0.6f, 0.1f, new Vector3f(2000, 2000, 2000), 539, (short)3, 0.6f, 2.0f); + NoiseParams np_height_select = new NoiseParams(-8, 16, new Vector3f(500, 500, 500), 4213, (short)6, 0.7f, 2.0f); + NoiseParams np_filler_depth = new NoiseParams(0, 1.2f, new Vector3f(150, 150, 150), 261, (short)3, 0.7f, 2.0f); + NoiseParams np_mount_height = new NoiseParams(256f, 112f, new Vector3f(1000, 1000, 1000), 72449, (short)3, 0.6f, 2.0f); + public NoiseParams np_ridge_uwater = new NoiseParams(0, 1, new Vector3f(1000, 1000, 1000), 85039, (short)5, 0.6f, 2.0f); + NoiseParams np_floatland_base = new NoiseParams(-0.6f, 1.5f, new Vector3f(600, 600, 600), 114, (short)5, 0.6f, 2.0f); + NoiseParams np_float_base_height = new NoiseParams(48, 24, new Vector3f(300, 300, 300), 907, (short)4, 0.7f, 2.0f); + public NoiseParams np_mountain = new NoiseParams(-0.6f, 1, new Vector3f(250, 350, 250), 5333, (short)5, 0.63f, 2.0f); + public NoiseParams np_ridge = new NoiseParams(0, 1, new Vector3f(100, 100, 100), 6467, (short)4, 0.75f, 2.0f); + NoiseParams np_cavern = new NoiseParams(0, 1, new Vector3f(384, 128, 384), 723, (short)5, 0.63f, 2.0f); + NoiseParams np_cave1 = new NoiseParams(0, 12, new Vector3f(61, 61, 61), 52534, (short)3, 0.5f, 2.0f); + NoiseParams np_cave2 = new NoiseParams(0, 12, new Vector3f(67, 67, 67), 10325, (short)3, 0.5f, 2.0f); +} diff --git a/src/main/java/amidst/minetest/world/mapgen/Noise.java b/src/main/java/amidst/minetest/world/mapgen/Noise.java new file mode 100644 index 00000000..23a58d22 --- /dev/null +++ b/src/main/java/amidst/minetest/world/mapgen/Noise.java @@ -0,0 +1,186 @@ +package amidst.minetest.world.mapgen; + +public class Noise { + + public static final int FLAG_DEFAULTS = 0x01; + public static final int FLAG_EASED = 0x02; + public static final int FLAG_ABSVALUE = 0x04; + public static final int FLAG_POINTBUFFER = 0x08; + public static final int FLAG_SIMPLEX = 0x10; + + public static final int MAGIC_X = 1619; + public static final int MAGIC_Y = 31337; + public static final int MAGIC_Z = 52591; + public static final int MAGIC_SEED = 1013; + + public NoiseParams np; + private int seed; + private int sx; + private int sy; + private int sz; + private float[] noise_buf = null; + private float[] gradient_buf = null; + private float[] persist_buf = null; + private float[] result = null; + + public Noise(NoiseParams np_, int seed, int sx, int sy) throws InvalidNoiseParamsException { + + this(np_, seed, sx, sy, 1); + } + + public Noise(NoiseParams np_, int seed, int sx, int sy, int sz) throws InvalidNoiseParamsException { + this.np = np_; + this.seed = seed; + this.sx = sx; + this.sy = sy; + this.sz = sz; + + allocBuffers(); + } + + private void allocBuffers() throws InvalidNoiseParamsException + { + if (sx < 1) sx = 1; + if (sy < 1) sy = 1; + if (sz < 1) sz = 1; + + this.noise_buf = null; + resizeNoiseBuf(sz > 1); + + gradient_buf = null; + persist_buf = null; + result = null; + + try { + int bufsize = sx * sy * sz; + persist_buf = null; + gradient_buf = new float[bufsize]; + result = new float[bufsize]; + } catch (OutOfMemoryError e) { + throw new InvalidNoiseParamsException("out of memory"); + } + } + + private void resizeNoiseBuf(boolean is3d) throws InvalidNoiseParamsException + { + //if (is3d) throw new UnsupportedOperationException("need to port 3d noise functions"); + + //maximum possible spread value factor + float ofactor = (np.lacunarity > 1.0) ? + (float)Math.pow(np.lacunarity, np.octaves - 1) : + np.lacunarity; + + // noise lattice point count + // (int)(sz * spread * ofactor) is # of lattice points crossed due to length + float num_noise_points_x = sx * ofactor / np.spread.x; + float num_noise_points_y = sy * ofactor / np.spread.y; + float num_noise_points_z = sz * ofactor / np.spread.z; + + // protect against obviously invalid parameters + if (num_noise_points_x > 1000000000.f || + num_noise_points_y > 1000000000.f || + num_noise_points_z > 1000000000.f) + throw new InvalidNoiseParamsException(); + + // + 2 for the two initial endpoints + // + 1 for potentially crossing a boundary due to offset + int nlx = (int)Math.ceil(num_noise_points_x) + 3; + int nly = (int)Math.ceil(num_noise_points_y) + 3; + int nlz = is3d ? (int)Math.ceil(num_noise_points_z) + 3 : 1; + + try { + noise_buf = new float[nlx * nly * nlz]; + } catch (OutOfMemoryError e) { + throw new InvalidNoiseParamsException("out of memory"); + } + } + + + public static float NoisePerlin2D(NoiseParams np, float x, float y, int seed) + { + float a = 0; + float f = 1.0f; + float g = 1.0f; + + x /= np.spread.x; + y /= np.spread.y; + seed += np.seed; + + for (int i = 0; i < np.octaves; i++) { + float noiseval = noise2d_gradient(x * f, y * f, seed + i, + (np.flags & (FLAG_DEFAULTS | FLAG_EASED)) > 0); + + if ((np.flags & FLAG_ABSVALUE) > 0) + noiseval = Math.abs(noiseval); + + a += g * noiseval; + f *= np.lacunarity; + g *= np.persist; + } + + return np.offset + a * np.scale; + } + + static float noise2d(int x, int y, int seed) + { + // n is an unsigned int, which Java does not possess, so + // divide and shift operations on it must be performed unsigned + // + // Note that in two's complement arithmetic, the arithmetic operations of + // add, subtract, and multiply are bit-wise identical if the two operands + // are regarded as both being signed or both being unsigned. + // + // unsigned int n = (MAGIC_X * x + MAGIC_Y * y + MAGIC_SEED * seed) & 0x7fffffff; + // n = (n >> 13) ^ n; + // n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + // return 1.f - (float)(int)n / 0x40000000; + int n = (MAGIC_X * x + MAGIC_Y * y + MAGIC_SEED * seed) & 0x7fffffff; + n = (n >>> 13) ^ n; + n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return 1.f - (float)(int)n / 0x40000000; // ?? check this + } + + static float noise2d_gradient(float x, float y, int seed, boolean eased) + { + // Calculate the integer coordinates + int x0 = ((x) < 0.0 ? (int)(x) - 1 : (int)(x)); // x0 = myfloor(x) + int y0 = ((y) < 0.0 ? (int)(y) - 1 : (int)(y)); // y0 = myfloor(y) + // Calculate the remaining part of the coordinates + float xl = x - (float)x0; + float yl = y - (float)y0; + // Get values for corners of square + float v00 = noise2d(x0, y0, seed); + float v10 = noise2d(x0+1, y0, seed); + float v01 = noise2d(x0, y0+1, seed); + float v11 = noise2d(x0+1, y0+1, seed); + // Interpolate + if (eased) { + return biLinearInterpolation(v00, v10, v01, v11, xl, yl); + } + + return biLinearInterpolationNoEase(v00, v10, v01, v11, xl, yl); + } + + static float biLinearInterpolation( + float v00, float v10, + float v01, float v11, + float x, float y) + { + float tx = x * x * x * (x * (6.f * x - 15.f) + 10.f); // easeCurve(x); + float ty = y * y * y * (y * (6.f * y - 15.f) + 10.f); // easeCurve(y); + float u = v00 + (v10 - v00) * x; // linearInterpolation(v00, v10, x); + float v = v01 + (v11 - v01) * x; // linearInterpolation(v01, v11, x); + return u + (v - u) * y; // linearInterpolation(u, v, y); + } + + + static float biLinearInterpolationNoEase( + float v00, float v10, + float v01, float v11, + float x, float y) + { + float u = v00 + (v10 - v00) * x; // linearInterpolation(v00, v10, x); + float v = v01 + (v11 - v01) * x; // linearInterpolation(v01, v11, x); + return u + (v - u) * y; // linearInterpolation(u, v, y); + } +} diff --git a/src/main/java/amidst/minetest/world/mapgen/NoiseParams.java b/src/main/java/amidst/minetest/world/mapgen/NoiseParams.java new file mode 100644 index 00000000..cbee28c4 --- /dev/null +++ b/src/main/java/amidst/minetest/world/mapgen/NoiseParams.java @@ -0,0 +1,38 @@ +package amidst.minetest.world.mapgen; + +import javax.vecmath.Vector3f; + +public class NoiseParams { + + float offset = 0.0f; + float scale = 1.0f; + Vector3f spread = new Vector3f(250, 250, 250); + int seed = 12345; + short octaves = 3; + float persist = 0.6f; + float lacunarity = 2.0f; + int flags = Noise.FLAG_DEFAULTS; // Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers + + + public NoiseParams() { } + + public NoiseParams(float offset_, float scale_, Vector3f spread_, int seed_, + short octaves_, float persist_, float lacunarity_) + { + this(offset_, scale_, spread_, seed_, octaves_, persist_, lacunarity_, Noise.FLAG_DEFAULTS); + } + + public NoiseParams(float offset_, float scale_, Vector3f spread_, int seed_, + short octaves_, float persist_, float lacunarity_, + int flags_) + { + offset = offset_; + scale = scale_; + spread = spread_; + seed = seed_; + octaves = octaves_; + persist = persist_; + lacunarity = lacunarity_; + flags = flags_; + } +} diff --git a/src/main/java/amidst/minetest/world/mapgen/Numeric.java b/src/main/java/amidst/minetest/world/mapgen/Numeric.java new file mode 100644 index 00000000..21b476fc --- /dev/null +++ b/src/main/java/amidst/minetest/world/mapgen/Numeric.java @@ -0,0 +1,81 @@ +package amidst.minetest.world.mapgen; + +import java.nio.charset.Charset; +import java.util.AbstractMap.SimpleEntry; + +import amidst.mojangapi.world.WorldSeed; + +public class Numeric { + + /** + * @return A pair of values: the seed as a long, and whether it was + * parsed as a numeric or text string + */ + public static SimpleEntry stringToSeed(String input) + { + long seed; + boolean fromText = false; + + try { + if (input.startsWith("0x")) { + seed = Long.decode(input); + } else { + seed = Long.parseLong(input); + } + } catch (NumberFormatException err) { + byte[] stringAsBytes = input.getBytes(Charset.forName("UTF-8")); + seed = murmurhash2_hash64(stringAsBytes, stringAsBytes.length, 0x1337); + fromText = true; + } + return new SimpleEntry(seed, fromText); + } + + /** + * Generates 64 bit hash from byte array of the given length and seed. + * + * @param data byte array to hash + * @param length length of the array to hash + * @param seed initial seed value + * @return 64 bit hash of the given array + */ + public static long murmurhash2_hash64(final byte[] data, int length, int seed) { + final long m = 0xc6a4a7935bd1e995L; + final int r = 47; + + long h = (seed&0xffffffffl)^(length*m); + + int length8 = length/8; + + for (int i=0; i>> r; + k *= m; + + h ^= k; + h *= m; + } + + switch (length%8) { + case 7: h ^= (long)(data[(length&~7)+6]&0xff) << 48; + case 6: h ^= (long)(data[(length&~7)+5]&0xff) << 40; + case 5: h ^= (long)(data[(length&~7)+4]&0xff) << 32; + case 4: h ^= (long)(data[(length&~7)+3]&0xff) << 24; + case 3: h ^= (long)(data[(length&~7)+2]&0xff) << 16; + case 2: h ^= (long)(data[(length&~7)+1]&0xff) << 8; + case 1: h ^= (long)(data[length&~7]&0xff); + h *= m; + }; + + h ^= h >>> r; + h *= m; + h ^= h >>> r; + + return h; + } +} diff --git a/src/main/java/amidst/minetest/world/oracle/BiomeDataOracle.java b/src/main/java/amidst/minetest/world/oracle/BiomeDataOracle.java new file mode 100644 index 00000000..9a7db470 --- /dev/null +++ b/src/main/java/amidst/minetest/world/oracle/BiomeDataOracle.java @@ -0,0 +1,112 @@ +package amidst.minetest.world.oracle; + +import java.util.Random; + +import amidst.documentation.Immutable; +import amidst.fragment.Fragment; +import amidst.fragment.IBiomeDataOracle; +import amidst.logging.AmidstLogger; +import amidst.logging.AmidstMessageBox; +import amidst.minetest.world.mapgen.InvalidNoiseParamsException; +import amidst.minetest.world.mapgen.MapgenV7Params; +import amidst.minetest.world.mapgen.Noise; +import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException; +import amidst.mojangapi.world.coordinates.CoordinatesInWorld; +import amidst.mojangapi.world.coordinates.Resolution; + +@Immutable +public class BiomeDataOracle implements IBiomeDataOracle { + private final int seed; + private final MapgenV7Params params; + + private Noise noise_terrain_alt; + private Noise noise_ridge_uwater; + private Noise noise_mountain; + private Noise noise_ridge; + + + public static final int BITPLANE_RIVER = 0x4000; + public static final int BITPLANE_OCEAN = 0x2000; + public static final int BITPLANE_MOUNTAIN = 0x1000; + public static final int MASK_BITPLANES = ~(BITPLANE_RIVER | BITPLANE_OCEAN | BITPLANE_MOUNTAIN); + + + public BiomeDataOracle(MapgenV7Params params, long seed) throws InvalidNoiseParamsException { + //this.seed = (int)(seed & 0xFFFFFFFFL); + this.seed = (int)seed; + this.params = params; + + if ((params.spflags & MapgenV7Params.FLAG_V7_RIDGES) > 0) { + noise_ridge_uwater = new Noise(params.np_ridge_uwater, this.seed, params.chunk_length_x, params.chunk_length_z); + + // 3D noise, 1-up 1-down overgeneration + noise_ridge = new Noise(params.np_ridge, this.seed, params.chunk_length_x, params.chunk_length_y + 2, params.chunk_length_z); + } + + // 3D noise, 1 up, 1 down overgeneration + if ((params.spflags & (MapgenV7Params.FLAG_V7_MOUNTAINS | MapgenV7Params.FLAG_V7_FLOATLANDS)) > 0) { + noise_mountain = new Noise(params.np_mountain, this.seed, params.chunk_length_x, params.chunk_length_y + 2, params.chunk_length_z); + } + } + + public short populateArray(CoordinatesInWorld corner, short[][] result, boolean useQuarterResolution) { + Resolution resolution = Resolution.from(useQuarterResolution); + int width = result.length; + if (width > 0) { + int height = result[0].length; + int left = (int) corner.getX(); + int top = (int) corner.getY(); + int shift = resolution.getShift(); + int step = resolution.getStep(); + float river_width = 0.2f; + int world_y; + int world_x; + short biomeValue; + + try { + for (int y = 0; y < height; y++) { + + world_y = top + (y << shift); + world_x = left; + + for (int x = 0; x < width; x++) { + + biomeValue = 0; + + // add the river bitplane + float uwatern = Noise.NoisePerlin2D(noise_ridge_uwater.np, world_x, world_y, seed) * 2; + if (Math.abs(uwatern) <= river_width) biomeValue |= BITPLANE_RIVER; + + + result[x][y] = biomeValue; + world_x += step; + } + } + + + //copyToResult(result, width, height, getBiomeData(left, top, width, height, useQuarterResolution)); + } catch (Exception e) { + AmidstLogger.error(e); + AmidstMessageBox.displayError("Error", e); + } + } + return MASK_BITPLANES; + } + + /* + public static void copyToResult(short[][] result, int width, int height, int[] biomeData) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + result[x][y] = (short) biomeData[getBiomeDataIndex(x, y, width)]; + } + } + } + + private int[] getBiomeData(int x, int y, int width, int height, boolean useQuarterResolution) + throws UnsupportedOperationException { + + // return minecraftInterface.getBiomeData(x, y, width, height, useQuarterResolution); + throw new UnsupportedOperationException("getBiomeData (minetest)"); + }*/ + +} diff --git a/src/main/java/amidst/minetest/world/oracle/HeuristicWorldSpawnOracle.java b/src/main/java/amidst/minetest/world/oracle/HeuristicWorldSpawnOracle.java new file mode 100644 index 00000000..c0570608 --- /dev/null +++ b/src/main/java/amidst/minetest/world/oracle/HeuristicWorldSpawnOracle.java @@ -0,0 +1,23 @@ +package amidst.minetest.world.oracle; + +import amidst.documentation.ThreadSafe; +import amidst.minetest.world.mapgen.MapgenV7Params; +import amidst.mojangapi.world.coordinates.CoordinatesInWorld; +import amidst.mojangapi.world.oracle.WorldSpawnOracle; + +@ThreadSafe +public class HeuristicWorldSpawnOracle implements WorldSpawnOracle { + private final int seed; + private final MapgenV7Params params; + + public HeuristicWorldSpawnOracle(MapgenV7Params params, long seed) { + this.seed = (int)(seed & 0xFFFFFFFFL); + this.params = params; + } + + @Override + public CoordinatesInWorld get() { + // Not implemented + return CoordinatesInWorld.origin(); + } +} diff --git a/src/main/java/amidst/mojangapi/RunningLauncherProfile.java b/src/main/java/amidst/mojangapi/RunningLauncherProfile.java index 58819ff9..570a0e16 100644 --- a/src/main/java/amidst/mojangapi/RunningLauncherProfile.java +++ b/src/main/java/amidst/mojangapi/RunningLauncherProfile.java @@ -3,6 +3,9 @@ package amidst.mojangapi; import java.io.IOException; import amidst.documentation.ThreadSafe; +import amidst.gameengineabstraction.GameEngineType; +import amidst.minetest.MinetestLauncherProfile; +import amidst.minetest.MinetestMapgenV7Interface; import amidst.mojangapi.file.LauncherProfile; import amidst.mojangapi.file.SaveGame; import amidst.mojangapi.minecraftinterface.MinecraftInterface; @@ -20,10 +23,18 @@ import amidst.mojangapi.world.WorldType; public class RunningLauncherProfile { public static RunningLauncherProfile from(WorldBuilder worldBuilder, LauncherProfile launcherProfile) throws LocalMinecraftInterfaceCreationException { + + MinecraftInterface mapgenInterface; + + if (launcherProfile instanceof MinetestLauncherProfile) { + mapgenInterface = new MinetestMapgenV7Interface(((MinetestLauncherProfile)launcherProfile).getMapGenParams()); + } else { + mapgenInterface = LocalMinecraftInterface.create(DefaultClassTranslator.INSTANCE.get(), launcherProfile); + } return new RunningLauncherProfile( worldBuilder, launcherProfile, - LocalMinecraftInterface.create(DefaultClassTranslator.INSTANCE.get(), launcherProfile)); + mapgenInterface); } private final WorldBuilder worldBuilder; @@ -48,6 +59,10 @@ public class RunningLauncherProfile { return minecraftInterface.getRecognisedVersion(); } + public GameEngineType getGameEngineType() { + return minecraftInterface.getGameEngineType(); + } + public RunningLauncherProfile createSilentPlayerlessCopy() { try { return RunningLauncherProfile.from(WorldBuilder.createSilentPlayerless(), launcherProfile); diff --git a/src/main/java/amidst/mojangapi/file/MinecraftInstallation.java b/src/main/java/amidst/mojangapi/file/MinecraftInstallation.java index 8a874546..b21d9cc7 100644 --- a/src/main/java/amidst/mojangapi/file/MinecraftInstallation.java +++ b/src/main/java/amidst/mojangapi/file/MinecraftInstallation.java @@ -8,6 +8,8 @@ import java.util.Optional; import java.util.stream.Collectors; import amidst.documentation.Immutable; +import amidst.gameengineabstraction.file.IGameInstallation; +import amidst.gameengineabstraction.file.IUnresolvedLauncherProfile; import amidst.logging.AmidstLogger; import amidst.mojangapi.file.directory.DotMinecraftDirectory; import amidst.mojangapi.file.directory.SaveDirectory; @@ -19,7 +21,7 @@ import amidst.parsing.FormatException; import amidst.parsing.json.JsonReader; @Immutable -public class MinecraftInstallation { +public class MinecraftInstallation implements IGameInstallation { public static MinecraftInstallation newCustomMinecraftInstallation( File libraries, File saves, @@ -60,13 +62,13 @@ public class MinecraftInstallation { return result; } - public List readLauncherProfiles() throws FormatException, IOException { + public List readLauncherProfiles() throws FormatException, IOException { return dotMinecraftDirectoryService .readLauncherProfilesFrom(dotMinecraftDirectory) .getProfiles() .values() .stream() - .map(p -> new UnresolvedLauncherProfile(dotMinecraftDirectory, p)) + .map(p -> (IUnresolvedLauncherProfile)new UnresolvedLauncherProfile(dotMinecraftDirectory, p)) .collect(Collectors.toList()); } diff --git a/src/main/java/amidst/mojangapi/file/UnresolvedLauncherProfile.java b/src/main/java/amidst/mojangapi/file/UnresolvedLauncherProfile.java index ec146a6a..bf3a40a8 100644 --- a/src/main/java/amidst/mojangapi/file/UnresolvedLauncherProfile.java +++ b/src/main/java/amidst/mojangapi/file/UnresolvedLauncherProfile.java @@ -3,6 +3,7 @@ package amidst.mojangapi.file; import java.io.IOException; import amidst.documentation.Immutable; +import amidst.gameengineabstraction.file.IUnresolvedLauncherProfile; import amidst.mojangapi.file.directory.DotMinecraftDirectory; import amidst.mojangapi.file.directory.ProfileDirectory; import amidst.mojangapi.file.directory.VersionDirectory; @@ -13,7 +14,7 @@ import amidst.parsing.FormatException; import amidst.parsing.json.JsonReader; @Immutable -public class UnresolvedLauncherProfile { +public class UnresolvedLauncherProfile implements IUnresolvedLauncherProfile { private final DotMinecraftDirectoryService dotMinecraftDirectoryService = new DotMinecraftDirectoryService(); private final DotMinecraftDirectory dotMinecraftDirectory; private final LauncherProfileJson launcherProfileJson; diff --git a/src/main/java/amidst/mojangapi/file/json/version/VersionJson.java b/src/main/java/amidst/mojangapi/file/json/version/VersionJson.java index 56ad5cb7..a321bcd1 100644 --- a/src/main/java/amidst/mojangapi/file/json/version/VersionJson.java +++ b/src/main/java/amidst/mojangapi/file/json/version/VersionJson.java @@ -16,6 +16,11 @@ public class VersionJson { public VersionJson() { } + public VersionJson(String id, String inheritsFrom) { + this.id = id; + this.inheritsFrom = inheritsFrom; + } + public String getId() { return id; } diff --git a/src/main/java/amidst/mojangapi/minecraftinterface/MinecraftInterface.java b/src/main/java/amidst/mojangapi/minecraftinterface/MinecraftInterface.java index ee328d98..a9d05348 100644 --- a/src/main/java/amidst/mojangapi/minecraftinterface/MinecraftInterface.java +++ b/src/main/java/amidst/mojangapi/minecraftinterface/MinecraftInterface.java @@ -1,6 +1,7 @@ package amidst.mojangapi.minecraftinterface; import amidst.documentation.ThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.mojangapi.world.WorldType; /** @@ -37,4 +38,6 @@ public interface MinecraftInterface { public void createWorld(long seed, WorldType worldType, String generatorOptions) throws MinecraftInterfaceException; public RecognisedVersion getRecognisedVersion(); + + public GameEngineType getGameEngineType(); } diff --git a/src/main/java/amidst/mojangapi/minecraftinterface/RecognisedVersion.java b/src/main/java/amidst/mojangapi/minecraftinterface/RecognisedVersion.java index 0b9ae6c7..e51609c4 100644 --- a/src/main/java/amidst/mojangapi/minecraftinterface/RecognisedVersion.java +++ b/src/main/java/amidst/mojangapi/minecraftinterface/RecognisedVersion.java @@ -23,6 +23,8 @@ public enum RecognisedVersion { // TODO: Remove these versions before V1_0? // TODO: stronghold reset on V1_9pre4? UNKNOWN, + Minetest_v7 ("Minetest mapgen v7", ""), + _1_12_pre7 ("1.12-pre7", "ujrjoxmsrw[Lom;pj[J[[Jpf"), // matches the launcher version id: 1.12-pre7 1.12-pre6 1.12-pre5 1.12-pre4 1.12-pre3 _1_12_pre2 ("1.12-pre2", "uhrhovmqru[Lok;ph[J[[Jpd"), // matches the launcher version id: 1.12-pre2 _1_12_pre1 ("1.12-pre1", "ugrgoumprt[Loj;pg[J[[Jpc"), // matches the launcher version id: 1.12-pre1 @@ -132,6 +134,7 @@ public enum RecognisedVersion { _a1_0_15 ("a1.0.15", "hfazigcjebebmdferjsbdgiifbbljcnlufinqmc[Jmaap"), // matches the launcher version id: a1.0.15 _a1_0_14 ("a1.0.14", "hcazidcjebebmdfeqjpbdghicbblfcnlpfhnmly[Jlwap"), // matches the launcher version id: a1.0.14 _a1_0_11 ("a1.0.11", "haaziacjebebmddenjlbdgfhzbbkzcnljfenels[Jlqap"); // matches the launcher version id: a1.0.11 + // @formatter:on @NotNull diff --git a/src/main/java/amidst/mojangapi/minecraftinterface/local/LocalMinecraftInterface.java b/src/main/java/amidst/mojangapi/minecraftinterface/local/LocalMinecraftInterface.java index 92c8f43a..b96b3728 100644 --- a/src/main/java/amidst/mojangapi/minecraftinterface/local/LocalMinecraftInterface.java +++ b/src/main/java/amidst/mojangapi/minecraftinterface/local/LocalMinecraftInterface.java @@ -6,6 +6,7 @@ import amidst.clazz.symbolic.SymbolicClass; import amidst.clazz.symbolic.SymbolicObject; import amidst.clazz.translator.ClassTranslator; import amidst.documentation.ThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.logging.AmidstLogger; import amidst.mojangapi.file.LauncherProfile; import amidst.mojangapi.minecraftinterface.MinecraftInterface; @@ -147,4 +148,9 @@ public class LocalMinecraftInterface implements MinecraftInterface { public RecognisedVersion getRecognisedVersion() { return recognisedVersion; } + + @Override + public GameEngineType getGameEngineType() { + return GameEngineType.MINECRAFT; + } } diff --git a/src/main/java/amidst/mojangapi/world/World.java b/src/main/java/amidst/mojangapi/world/World.java index 6891a38b..12f5fdf1 100644 --- a/src/main/java/amidst/mojangapi/world/World.java +++ b/src/main/java/amidst/mojangapi/world/World.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.function.Consumer; import amidst.documentation.ThreadSafe; +import amidst.fragment.IBiomeDataOracle; import amidst.mojangapi.minecraftinterface.RecognisedVersion; import amidst.mojangapi.world.icon.WorldIcon; import amidst.mojangapi.world.icon.producer.CachedWorldIconProducer; @@ -26,7 +27,7 @@ public class World { private final RecognisedVersion recognisedVersion; private final VersionFeatures versionFeatures; - private final BiomeDataOracle biomeDataOracle; + private final IBiomeDataOracle biomeDataOracle; private final EndIslandOracle endIslandOracle; private final SlimeChunkOracle slimeChunkOracle; private final CachedWorldIconProducer spawnProducer; @@ -47,7 +48,7 @@ public class World { MovablePlayerList movablePlayerList, RecognisedVersion recognisedVersion, VersionFeatures versionFeatures, - BiomeDataOracle biomeDataOracle, + IBiomeDataOracle biomeDataOracle, EndIslandOracle endIslandOracle, SlimeChunkOracle slimeChunkOracle, CachedWorldIconProducer spawnProducer, @@ -104,7 +105,7 @@ public class World { return versionFeatures; } - public BiomeDataOracle getBiomeDataOracle() { + public IBiomeDataOracle getBiomeDataOracle() { return biomeDataOracle; } diff --git a/src/main/java/amidst/mojangapi/world/WorldBuilder.java b/src/main/java/amidst/mojangapi/world/WorldBuilder.java index ba11182d..c0cf24be 100644 --- a/src/main/java/amidst/mojangapi/world/WorldBuilder.java +++ b/src/main/java/amidst/mojangapi/world/WorldBuilder.java @@ -4,6 +4,10 @@ import java.io.IOException; import java.util.function.Consumer; import amidst.documentation.Immutable; +import amidst.fragment.IBiomeDataOracle; +import amidst.logging.AmidstLogger; +import amidst.minetest.MinetestMapgenV7Interface; +import amidst.minetest.world.mapgen.InvalidNoiseParamsException; import amidst.mojangapi.file.ImmutablePlayerInformationProvider; import amidst.mojangapi.file.PlayerInformationProvider; import amidst.mojangapi.file.SaveGame; @@ -55,14 +59,36 @@ public class WorldBuilder { } public World fromSeed( - MinecraftInterface minecraftInterface, + MinecraftInterface gameCodeInterface, Consumer onDisposeWorld, WorldSeed worldSeed, WorldType worldType) throws MinecraftInterfaceException { - BiomeDataOracle biomeDataOracle = new BiomeDataOracle(minecraftInterface); - VersionFeatures versionFeatures = DefaultVersionFeatures.create(minecraftInterface.getRecognisedVersion()); + + VersionFeatures versionFeatures = DefaultVersionFeatures.create(gameCodeInterface.getRecognisedVersion()); + + IBiomeDataOracle biomeDataOracle; + WorldSpawnOracle spawnOracle; + + if (gameCodeInterface instanceof MinetestMapgenV7Interface) { + MinetestMapgenV7Interface mapgen = (MinetestMapgenV7Interface)gameCodeInterface; + try { + biomeDataOracle = new amidst.minetest.world.oracle.BiomeDataOracle(mapgen.params, worldSeed.getLong()); + } catch (InvalidNoiseParamsException e) { + AmidstLogger.error("Invalid param from Minetest game."); + e.printStackTrace(); + biomeDataOracle = null; + } + spawnOracle = new amidst.minetest.world.oracle.HeuristicWorldSpawnOracle(mapgen.params, worldSeed.getLong()); + } else{ + biomeDataOracle = new BiomeDataOracle(gameCodeInterface); + spawnOracle = new HeuristicWorldSpawnOracle( + worldSeed.getLong(), + (BiomeDataOracle)biomeDataOracle, + versionFeatures.getValidBiomesForStructure_Spawn() + ); + } return create( - minecraftInterface, + gameCodeInterface, onDisposeWorld, worldSeed, worldType, @@ -70,10 +96,7 @@ public class WorldBuilder { MovablePlayerList.dummy(), versionFeatures, biomeDataOracle, - new HeuristicWorldSpawnOracle( - worldSeed.getLong(), - biomeDataOracle, - versionFeatures.getValidBiomesForStructure_Spawn())); + spawnOracle); } public World fromSaveGame(MinecraftInterface minecraftInterface, Consumer onDisposeWorld, SaveGame saveGame) @@ -88,7 +111,7 @@ public class WorldBuilder { return create( minecraftInterface, onDisposeWorld, - WorldSeed.fromSaveGame(saveGame.getSeed()), + WorldSeed.fromSaveGame(saveGame.getSeed(), minecraftInterface.getGameEngineType()), saveGame.getWorldType(), saveGame.getGeneratorOptions(), movablePlayerList, @@ -105,12 +128,16 @@ public class WorldBuilder { String generatorOptions, MovablePlayerList movablePlayerList, VersionFeatures versionFeatures, - BiomeDataOracle biomeDataOracle, + IBiomeDataOracle biomeDataOracle, WorldSpawnOracle worldSpawnOracle) throws MinecraftInterfaceException { RecognisedVersion recognisedVersion = minecraftInterface.getRecognisedVersion(); seedHistoryLogger.log(recognisedVersion, worldSeed); long seed = worldSeed.getLong(); minecraftInterface.createWorld(seed, worldType, generatorOptions); + + amidst.mojangapi.world.oracle.BiomeDataOracle minecraftBiomeOrNull = + (biomeDataOracle instanceof amidst.mojangapi.world.oracle.BiomeDataOracle) ? (amidst.mojangapi.world.oracle.BiomeDataOracle)biomeDataOracle : null; + return new World( onDisposeWorld, worldSeed, @@ -125,7 +152,7 @@ public class WorldBuilder { new SpawnProducer(worldSpawnOracle), versionFeatures.getStrongholdProducerFactory().apply( seed, - biomeDataOracle, + minecraftBiomeOrNull, versionFeatures.getValidBiomesAtMiddleOfChunk_Stronghold()), new PlayerProducer(movablePlayerList), new StructureProducer<>( @@ -133,7 +160,7 @@ public class WorldBuilder { 4, new VillageLocationChecker( seed, - biomeDataOracle, + minecraftBiomeOrNull, versionFeatures.getValidBiomesForStructure_Village()), new ImmutableWorldIconTypeProvider(DefaultWorldIconTypes.VILLAGE), Dimension.OVERWORLD, @@ -143,9 +170,9 @@ public class WorldBuilder { 8, new TempleLocationChecker( seed, - biomeDataOracle, + minecraftBiomeOrNull, versionFeatures.getValidBiomesAtMiddleOfChunk_Temple()), - new TempleWorldIconTypeProvider(biomeDataOracle), + new TempleWorldIconTypeProvider(minecraftBiomeOrNull), Dimension.OVERWORLD, false), new StructureProducer<>( @@ -160,7 +187,7 @@ public class WorldBuilder { 8, versionFeatures.getOceanMonumentLocationCheckerFactory().apply( seed, - biomeDataOracle, + minecraftBiomeOrNull, versionFeatures.getValidBiomesAtMiddleOfChunk_OceanMonument(), versionFeatures.getValidBiomesForStructure_OceanMonument()), new ImmutableWorldIconTypeProvider(DefaultWorldIconTypes.OCEAN_MONUMENT), diff --git a/src/main/java/amidst/mojangapi/world/WorldSeed.java b/src/main/java/amidst/mojangapi/world/WorldSeed.java index 03a39ffd..f3483c8b 100644 --- a/src/main/java/amidst/mojangapi/world/WorldSeed.java +++ b/src/main/java/amidst/mojangapi/world/WorldSeed.java @@ -1,8 +1,11 @@ package amidst.mojangapi.world; import java.util.Random; +import java.util.AbstractMap.SimpleEntry; import amidst.documentation.Immutable; +import amidst.gameengineabstraction.GameEngineType; +import amidst.minetest.world.mapgen.Numeric; @Immutable public class WorldSeed { @@ -20,52 +23,69 @@ public class WorldSeed { this.labelPrefix = labelPrefix; } - private String getLabel(long seed, String text) { + private String getLabel(long seed, String text, GameEngineType gameEngine) { + + String seedValue = Long.toString(seed); + if (gameEngine != GameEngineType.MINECRAFT) { + seedValue = Long.toUnsignedString(seed); + } + if (this == TEXT) { - return labelPrefix + ": '" + text + "' (" + seed + ")"; + return labelPrefix + ": '" + text + "' (" + seedValue + ")"; } else { - return labelPrefix + ": " + seed; + return labelPrefix + ": " + seedValue; } } } - public static WorldSeed random() { - return new WorldSeed(new Random().nextLong(), null, WorldSeedType.RANDOM); + public static WorldSeed random(GameEngineType game_engine_type) { + return new WorldSeed(new Random().nextLong(), null, WorldSeedType.RANDOM, game_engine_type); } - public static WorldSeed fromUserInput(String input) { + public static WorldSeed fromUserInput(String input, GameEngineType engine_type) { if (input.isEmpty()) { - return random(); + return random(engine_type); } - try { - long seed = Long.parseLong(input); - return new WorldSeed(seed, null, WorldSeedType.NUMERIC); - } catch (NumberFormatException err) { - int seed = input.hashCode(); - return new WorldSeed(seed, input, WorldSeedType.TEXT); + if (engine_type == GameEngineType.MINETESTv7) { + SimpleEntry covertedSeed = Numeric.stringToSeed(input); + return new WorldSeed( + covertedSeed.getKey(), + input, + covertedSeed.getValue() ? WorldSeedType.TEXT : WorldSeedType.NUMERIC, + engine_type); + } else { + try { + long seed = Long.parseLong(input); + return new WorldSeed(seed, null, WorldSeedType.NUMERIC, engine_type); + } catch (NumberFormatException err) { + int seed = input.hashCode(); + return new WorldSeed(seed, input, WorldSeedType.TEXT, engine_type); + } } } - public static WorldSeed fromSaveGame(long seed) { - return new WorldSeed(seed, null, WorldSeedType.SAVE_GAME); + public static WorldSeed fromSaveGame(long seed, GameEngineType game_engine_type) { + return new WorldSeed(seed, null, WorldSeedType.SAVE_GAME, game_engine_type); } private final long seed; private final String text; private final WorldSeedType type; private final String label; + private final GameEngineType gameEngineType; - private WorldSeed(long seed, String text, WorldSeedType type) { + private WorldSeed(long seed, String text, WorldSeedType type, GameEngineType game_engine_type) { this.seed = seed; this.text = text; this.type = type; - this.label = type.getLabel(seed, text); + this.gameEngineType = game_engine_type; + this.label = type.getLabel(seed, text, game_engine_type); } public long getLong() { return seed; } - + public String getText() { return text; } diff --git a/src/main/java/amidst/mojangapi/world/coordinates/Resolution.java b/src/main/java/amidst/mojangapi/world/coordinates/Resolution.java index c93ebec8..a9c0730c 100644 --- a/src/main/java/amidst/mojangapi/world/coordinates/Resolution.java +++ b/src/main/java/amidst/mojangapi/world/coordinates/Resolution.java @@ -29,6 +29,10 @@ public enum Resolution { return 1 << shift; } + public int getShift() { + return shift; + } + public int getStepsPerFragment() { return 1 << (FRAGMENT.shift - shift); } diff --git a/src/main/java/amidst/mojangapi/world/icon/locationchecker/StructureBiomeLocationChecker.java b/src/main/java/amidst/mojangapi/world/icon/locationchecker/StructureBiomeLocationChecker.java index 153cb27c..968f3ae7 100644 --- a/src/main/java/amidst/mojangapi/world/icon/locationchecker/StructureBiomeLocationChecker.java +++ b/src/main/java/amidst/mojangapi/world/icon/locationchecker/StructureBiomeLocationChecker.java @@ -3,6 +3,7 @@ package amidst.mojangapi.world.icon.locationchecker; import java.util.List; import amidst.documentation.ThreadSafe; +import amidst.logging.AmidstLogger; import amidst.mojangapi.world.biome.Biome; import amidst.mojangapi.world.oracle.BiomeDataOracle; @@ -20,6 +21,10 @@ public class StructureBiomeLocationChecker implements LocationChecker { @Override public boolean isValidLocation(int x, int y) { + if (biomeDataOracle == null) { + AmidstLogger.warn("isValidLocation asked with null biome - LocationCheckers not suitable for the current biome may be in use!"); + return false; + } return biomeDataOracle.isValidBiomeForStructureAtMiddleOfChunk(x, y, size, validBiomes); } } diff --git a/src/main/java/amidst/mojangapi/world/oracle/BiomeDataOracle.java b/src/main/java/amidst/mojangapi/world/oracle/BiomeDataOracle.java index 2608450e..c3cf1972 100644 --- a/src/main/java/amidst/mojangapi/world/oracle/BiomeDataOracle.java +++ b/src/main/java/amidst/mojangapi/world/oracle/BiomeDataOracle.java @@ -12,16 +12,17 @@ import amidst.mojangapi.world.biome.Biome; import amidst.mojangapi.world.biome.UnknownBiomeIndexException; import amidst.mojangapi.world.coordinates.CoordinatesInWorld; import amidst.mojangapi.world.coordinates.Resolution; +import amidst.fragment.IBiomeDataOracle; @ThreadSafe -public class BiomeDataOracle { +public class BiomeDataOracle implements IBiomeDataOracle { private final MinecraftInterface minecraftInterface; public BiomeDataOracle(MinecraftInterface minecraftInterface) { this.minecraftInterface = minecraftInterface; } - public void populateArray(CoordinatesInWorld corner, short[][] result, boolean useQuarterResolution) { + public short populateArray(CoordinatesInWorld corner, short[][] result, boolean useQuarterResolution) { Resolution resolution = Resolution.from(useQuarterResolution); int width = result.length; if (width > 0) { @@ -35,6 +36,7 @@ public class BiomeDataOracle { AmidstMessageBox.displayError("Error", e); } } + return (short)0xffff; } public static void copyToResult(short[][] result, int width, int height, int[] biomeData) { diff --git a/src/main/java/amidst/mojangapi/world/versionfeatures/DefaultVersionFeatures.java b/src/main/java/amidst/mojangapi/world/versionfeatures/DefaultVersionFeatures.java index 391e0296..038de27e 100644 --- a/src/main/java/amidst/mojangapi/world/versionfeatures/DefaultVersionFeatures.java +++ b/src/main/java/amidst/mojangapi/world/versionfeatures/DefaultVersionFeatures.java @@ -25,20 +25,38 @@ public enum DefaultVersionFeatures { INSTANCE; public static VersionFeatures create(RecognisedVersion version) { - return new VersionFeatures( - INSTANCE.enabledLayers.getValue(version), - INSTANCE.validBiomesForStructure_Spawn.getValue(version), - INSTANCE.validBiomesAtMiddleOfChunk_Stronghold.getValue(version), - INSTANCE.strongholdProducerFactory.getValue(version), - INSTANCE.validBiomesForStructure_Village.getValue(version), - INSTANCE.validBiomesAtMiddleOfChunk_Temple.getValue(version), - INSTANCE.mineshaftAlgorithmFactory.getValue(version), - INSTANCE.oceanMonumentLocationCheckerFactory.getValue(version), - INSTANCE.validBiomesAtMiddleOfChunk_OceanMonument.getValue(version), - INSTANCE.validBiomesForStructure_OceanMonument.getValue(version)); + + if (version == RecognisedVersion.Minetest_v7) { + // Minetest + return new VersionFeatures( + INSTANCE.enabledLayers_Minetest.getValue(version), + null, + null, + (seed, biomeOracle, validBiomes) -> null, + null, + null, + seed -> null, + (seed, biomeOracle, validCenterBiomes, validBiomes) -> null, + null, + null); + } else { + // Minecraft + return new VersionFeatures( + ((version == RecognisedVersion.Minetest_v7) ? INSTANCE.enabledLayers_Minetest : INSTANCE.enabledLayers_Minecraft).getValue(version), + INSTANCE.validBiomesForStructure_Spawn.getValue(version), + INSTANCE.validBiomesAtMiddleOfChunk_Stronghold.getValue(version), + INSTANCE.strongholdProducerFactory.getValue(version), + INSTANCE.validBiomesForStructure_Village.getValue(version), + INSTANCE.validBiomesAtMiddleOfChunk_Temple.getValue(version), + INSTANCE.mineshaftAlgorithmFactory.getValue(version), + INSTANCE.oceanMonumentLocationCheckerFactory.getValue(version), + INSTANCE.validBiomesAtMiddleOfChunk_OceanMonument.getValue(version), + INSTANCE.validBiomesForStructure_OceanMonument.getValue(version)); + } } - private final VersionFeature> enabledLayers; + private final VersionFeature> enabledLayers_Minecraft; + private final VersionFeature> enabledLayers_Minetest; private final VersionFeature> validBiomesForStructure_Spawn; private final VersionFeature> validBiomesAtMiddleOfChunk_Stronghold; private final VersionFeature, StrongholdProducer_Base>> strongholdProducerFactory; @@ -51,13 +69,27 @@ public enum DefaultVersionFeatures { private DefaultVersionFeatures() { // @formatter:off - this.enabledLayers = VersionFeature. listBuilder() + + this.enabledLayers_Minetest = VersionFeature. listBuilder() .init( LayerIds.ALPHA, LayerIds.BIOME_DATA, LayerIds.BACKGROUND, - LayerIds.SLIME, LayerIds.GRID, + LayerIds.MINETEST_OCEAN, + LayerIds.MINETEST_RIVER, + LayerIds.MINETEST_MOUNTAIN, + LayerIds.SLIME + ).construct(); + + + this.enabledLayers_Minecraft = VersionFeature. listBuilder() + .init( + LayerIds.ALPHA, + LayerIds.BIOME_DATA, + LayerIds.BACKGROUND, + LayerIds.GRID, + LayerIds.SLIME, LayerIds.SPAWN, LayerIds.STRONGHOLD, LayerIds.PLAYER, diff --git a/src/main/java/amidst/mojangapi/world/versionfeatures/ListVersionFeatureBuilder.java b/src/main/java/amidst/mojangapi/world/versionfeatures/ListVersionFeatureBuilder.java index 773cc6fc..07329971 100644 --- a/src/main/java/amidst/mojangapi/world/versionfeatures/ListVersionFeatureBuilder.java +++ b/src/main/java/amidst/mojangapi/world/versionfeatures/ListVersionFeatureBuilder.java @@ -40,8 +40,8 @@ public class ListVersionFeatureBuilder { } @SafeVarargs - public final ListVersionFeatureBuilder exact(RecognisedVersion since, V... values) { - return since(since, Arrays.asList(values)); + public final ListVersionFeatureBuilder exact(RecognisedVersion version, V... values) { + return exact(version, Arrays.asList(values)); } public ListVersionFeatureBuilder exact(RecognisedVersion version, List value) { diff --git a/src/main/java/amidst/threading/ThreadMaster.java b/src/main/java/amidst/threading/ThreadMaster.java index a4eef2b8..05d77888 100644 --- a/src/main/java/amidst/threading/ThreadMaster.java +++ b/src/main/java/amidst/threading/ThreadMaster.java @@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit; import amidst.documentation.AmidstThread; import amidst.documentation.CalledOnlyBy; import amidst.documentation.ThreadSafe; +import amidst.logging.AmidstLogger; @ThreadSafe public class ThreadMaster { @@ -91,7 +92,11 @@ public class ThreadMaster { @CalledOnlyBy(AmidstThread.FRAGMENT_LOADER) @Override public void run() { - onFragmentLoadTick.run(); + try { + onFragmentLoadTick.run(); + } catch (Exception e) { + AmidstLogger.error("Error in fragemnt loader thread: " + e.getMessage()); + } } }, 0, 20, TimeUnit.MILLISECONDS); } diff --git a/src/test/java/amidst/mojangapi/mocking/FakeMinecraftInterface.java b/src/test/java/amidst/mojangapi/mocking/FakeMinecraftInterface.java index 2d46ab2a..48bd2bd6 100644 --- a/src/test/java/amidst/mojangapi/mocking/FakeMinecraftInterface.java +++ b/src/test/java/amidst/mojangapi/mocking/FakeMinecraftInterface.java @@ -1,6 +1,7 @@ package amidst.mojangapi.mocking; import amidst.documentation.ThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.mojangapi.minecraftinterface.MinecraftInterface; import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException; import amidst.mojangapi.minecraftinterface.RecognisedVersion; @@ -58,4 +59,9 @@ public class FakeMinecraftInterface implements MinecraftInterface { public RecognisedVersion getRecognisedVersion() { return worldMetadataJson.getRecognisedVersion(); } + + @Override + public GameEngineType getGameEngineType() { + return GameEngineType.MINECRAFT; + } } diff --git a/src/test/java/amidst/mojangapi/mocking/FakeWorldBuilder.java b/src/test/java/amidst/mojangapi/mocking/FakeWorldBuilder.java index e9b384bd..0502b290 100644 --- a/src/test/java/amidst/mojangapi/mocking/FakeWorldBuilder.java +++ b/src/test/java/amidst/mojangapi/mocking/FakeWorldBuilder.java @@ -59,10 +59,13 @@ public class FakeWorldBuilder { WorldMetadataJson worldMetadata, BiomeDataJson quarterBiomeData, BiomeDataJson fullBiomeData) throws MinecraftInterfaceException { + + FakeMinecraftInterface fakeMinecraftInterface = createFakeMinecraftInterface(worldMetadata, quarterBiomeData, fullBiomeData); + return builder.fromSeed( - createFakeMinecraftInterface(worldMetadata, quarterBiomeData, fullBiomeData), + fakeMinecraftInterface, NOOP, - WorldSeed.fromUserInput(worldMetadata.getSeed() + ""), + WorldSeed.fromUserInput(worldMetadata.getSeed() + "", fakeMinecraftInterface.getGameEngineType()), worldMetadata.getWorldType()); } diff --git a/src/test/java/amidst/mojangapi/mocking/RequestStoringMinecraftInterface.java b/src/test/java/amidst/mojangapi/mocking/RequestStoringMinecraftInterface.java index 9257b282..abd55614 100644 --- a/src/test/java/amidst/mojangapi/mocking/RequestStoringMinecraftInterface.java +++ b/src/test/java/amidst/mojangapi/mocking/RequestStoringMinecraftInterface.java @@ -1,6 +1,7 @@ package amidst.mojangapi.mocking; import amidst.documentation.ThreadSafe; +import amidst.gameengineabstraction.GameEngineType; import amidst.mojangapi.minecraftinterface.MinecraftInterface; import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException; import amidst.mojangapi.minecraftinterface.RecognisedVersion; @@ -38,4 +39,9 @@ public class RequestStoringMinecraftInterface implements MinecraftInterface { public synchronized RecognisedVersion getRecognisedVersion() { return realMinecraftInterface.getRecognisedVersion(); } + + @Override + public GameEngineType getGameEngineType() { + return realMinecraftInterface.getGameEngineType(); + } } diff --git a/src/test/java/amidst/mojangapi/world/testworld/TestWorldDeclaration.java b/src/test/java/amidst/mojangapi/world/testworld/TestWorldDeclaration.java index 29022e60..403f1da0 100644 --- a/src/test/java/amidst/mojangapi/world/testworld/TestWorldDeclaration.java +++ b/src/test/java/amidst/mojangapi/world/testworld/TestWorldDeclaration.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.List; import amidst.documentation.Immutable; +import amidst.gameengineabstraction.GameEngineType; import amidst.mojangapi.minecraftinterface.RecognisedVersion; import amidst.mojangapi.world.WorldSeed; import amidst.mojangapi.world.WorldType; @@ -79,7 +80,7 @@ public enum TestWorldDeclaration { WorldType worldType, String... supported) { this.recognisedVersion = recognisedVersion; - this.worldSeed = WorldSeed.fromUserInput(seed); + this.worldSeed = WorldSeed.fromUserInput(seed, GameEngineType.MINECRAFT); this.worldType = worldType; this.supportedEntryNames = Collections.unmodifiableList(Arrays.asList(supported)); this.directory = Paths.get(