Minetest support - initial commit

Rivers don't match the game, but Amidst can now draw maps made with a different engine than Minecraft
master
Treer 2018-03-10 18:48:03 +11:00
parent 196a2bca7b
commit 969f26e406
60 changed files with 1403 additions and 109 deletions

View File

@ -130,5 +130,10 @@
<scope>provided</scope>
<type>maven-plugin</type>
</dependency>
<dependency>
<groupId>javax.vecmath</groupId>
<artifactId>vecmath</artifactId>
<version>1.5.2</version>
</dependency>
</dependencies>
</project>

View File

@ -26,6 +26,9 @@ public class AmidstSettings {
public final Setting<Boolean> showOceanMonuments;
public final Setting<Boolean> showNetherFortresses;
public final Setting<Boolean> showEndCities;
public final Setting<Boolean> showMinetestRivers;
public final Setting<Boolean> showMinetestOceans;
public final Setting<Boolean> showMinetestMountains;
public final Setting<Boolean> enableAllLayers;
public final Setting<Boolean> 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);

View File

@ -11,6 +11,9 @@ import amidst.documentation.ThreadSafe;
@ThreadSafe
public class CommandLineParameters {
// @formatter:off
@Option(name = "-mtpath", usage = "location of the minetest directory.", metaVar = "<directory>")
public volatile String minetestDirectory;
@Option(name = "-mcpath", usage = "location of the '.minecraft' directory.", metaVar = "<directory>")
public volatile String dotMinecraftDirectory;

View File

@ -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;
}

View File

@ -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<LauncherProfile> 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);
}

View File

@ -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<EndIsland> endIslands;
private final AtomicReferenceArray<BufferedImage> images;
private final AtomicReferenceArray<List<WorldIcon>> 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<EndIsland> endIslands) {
this.endIslands = endIslands;
}

View File

@ -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
);
}

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -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),

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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<IUnresolvedLauncherProfile> readLauncherProfiles() throws FormatException, IOException;
public SaveGame newSaveGame(File location) throws IOException, FormatException;
}

View File

@ -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;
}

View File

@ -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<ViewerFacade> 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<ViewerFacade> 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)

View File

@ -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)

View File

@ -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<World, Actions, ViewerFacade> 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);

View File

@ -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(" ")) {

View File

@ -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<World, ViewerFacade> viewerFacadeFactory;
private final ThreadMaster threadMaster;
@ -41,7 +41,7 @@ public class WorldSwitcher {
@CalledOnlyBy(AmidstThread.EDT)
public WorldSwitcher(
MinecraftInstallation minecraftInstallation,
IGameInstallation minecraftInstallation,
RunningLauncherProfile runningLauncherProfile,
Factory1<World, ViewerFacade> 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);
}

View File

@ -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

View File

@ -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"),

View File

@ -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) {

View File

@ -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;

View File

@ -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<UnresolvedLauncherProfile> scanAndLoadProfiles() throws FormatException, IOException {
private List<IUnresolvedLauncherProfile> scanAndLoadProfiles() throws FormatException, IOException {
AmidstLogger.info("Scanning for profiles.");
List<UnresolvedLauncherProfile> launcherProfiles = minecraftInstallation.readLauncherProfiles();
List<IUnresolvedLauncherProfile> launcherProfiles = gameInstallation.readLauncherProfiles();
AmidstLogger.info("Successfully loaded profile list.");
return launcherProfiles;
}
@CalledOnlyBy(AmidstThread.EDT)
private void displayProfiles(List<UnresolvedLauncherProfile> launcherProfiles) {
private void displayProfiles(List<IUnresolvedLauncherProfile> launcherProfiles) {
createProfileComponentsIfNecessary(launcherProfiles);
restoreSelection();
frame.pack();
}
@CalledOnlyBy(AmidstThread.EDT)
private void createProfileComponentsIfNecessary(List<UnresolvedLauncherProfile> launcherProfiles) {
private void createProfileComponentsIfNecessary(List<IUnresolvedLauncherProfile> 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<UnresolvedLauncherProfile> launcherProfiles) {
for (UnresolvedLauncherProfile profile : launcherProfiles) {
private void createProfileComponents(List<IUnresolvedLauncherProfile> launcherProfiles) {
for (IUnresolvedLauncherProfile profile : launcherProfiles) {
profileSelectPanel.addProfile(
new LocalProfileComponent(
application,

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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<LauncherProfile> 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<IUnresolvedLauncherProfile> readLauncherProfiles()
throws FormatException, IOException {
// TODO Auto-generated method stub
ArrayList<IUnresolvedLauncherProfile> result = new ArrayList<IUnresolvedLauncherProfile>();
result.add(new UnresolvedLauncherProfile());
return result;
}
/*
public List<LauncherProfile> readInstalledVersionsAsLauncherProfiles() throws FormatException, IOException {
List<LauncherProfile> result = new LinkedList<>();
for (VersionDirectory versionDirectory : minetestDirectoryService
.findInstalledValidVersionDirectories(minetestDirectory)) {
result.add(newLauncherProfile(versionDirectory));
}
return result;
}
public List<UnresolvedLauncherProfile> 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<LauncherProfile> 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();
}
}
*/
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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_;
}
}

View File

@ -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<Long, Boolean> 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<Long, Boolean>(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<length8; i++) {
final int i8 = i*8;
long k = ((long)data[i8+0]&0xff) +(((long)data[i8+1]&0xff)<<8)
+(((long)data[i8+2]&0xff)<<16) +(((long)data[i8+3]&0xff)<<24)
+(((long)data[i8+4]&0xff)<<32) +(((long)data[i8+5]&0xff)<<40)
+(((long)data[i8+6]&0xff)<<48) +(((long)data[i8+7]&0xff)<<56);
k *= m;
k ^= k >>> 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;
}
}

View File

@ -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)");
}*/
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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<UnresolvedLauncherProfile> readLauncherProfiles() throws FormatException, IOException {
public List<IUnresolvedLauncherProfile> 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());
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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<World> 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<World> 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),

View File

@ -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<Long, Boolean> 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;
}

View File

@ -29,6 +29,10 @@ public enum Resolution {
return 1 << shift;
}
public int getShift() {
return shift;
}
public int getStepsPerFragment() {
return 1 << (FRAGMENT.shift - shift);
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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<List<Integer>> enabledLayers;
private final VersionFeature<List<Integer>> enabledLayers_Minecraft;
private final VersionFeature<List<Integer>> enabledLayers_Minetest;
private final VersionFeature<List<Biome>> validBiomesForStructure_Spawn;
private final VersionFeature<List<Biome>> validBiomesAtMiddleOfChunk_Stronghold;
private final VersionFeature<TriFunction<Long, BiomeDataOracle, List<Biome>, StrongholdProducer_Base>> strongholdProducerFactory;
@ -51,13 +69,27 @@ public enum DefaultVersionFeatures {
private DefaultVersionFeatures() {
// @formatter:off
this.enabledLayers = VersionFeature.<Integer> listBuilder()
this.enabledLayers_Minetest = VersionFeature.<Integer> 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.<Integer> listBuilder()
.init(
LayerIds.ALPHA,
LayerIds.BIOME_DATA,
LayerIds.BACKGROUND,
LayerIds.GRID,
LayerIds.SLIME,
LayerIds.SPAWN,
LayerIds.STRONGHOLD,
LayerIds.PLAYER,

View File

@ -40,8 +40,8 @@ public class ListVersionFeatureBuilder<V> {
}
@SafeVarargs
public final ListVersionFeatureBuilder<V> exact(RecognisedVersion since, V... values) {
return since(since, Arrays.asList(values));
public final ListVersionFeatureBuilder<V> exact(RecognisedVersion version, V... values) {
return exact(version, Arrays.asList(values));
}
public ListVersionFeatureBuilder<V> exact(RecognisedVersion version, List<V> value) {

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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());
}

View File

@ -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();
}
}

View File

@ -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(