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(