introduced new facade class SaveGame
parent
4c1a9b1048
commit
cf3f7c7bf1
|
@ -12,7 +12,6 @@ import amidst.mojangapi.file.MojangApiParsingException;
|
|||
import amidst.mojangapi.file.facade.LauncherProfile;
|
||||
import amidst.mojangapi.file.facade.MinecraftInstallation;
|
||||
import amidst.mojangapi.file.json.versionlist.VersionListJson;
|
||||
import amidst.mojangapi.file.service.SaveDirectoryService;
|
||||
import amidst.mojangapi.file.service.VersionListService;
|
||||
import amidst.mojangapi.minecraftinterface.MinecraftInterface;
|
||||
import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException;
|
||||
|
@ -128,7 +127,7 @@ public class MojangApi {
|
|||
MojangApiParsingException {
|
||||
MinecraftInterface minecraftInterface = this.minecraftInterface;
|
||||
if (minecraftInterface != null) {
|
||||
return worldBuilder.fromSaveGame(minecraftInterface, new SaveDirectoryService().newSaveDirectory(file));
|
||||
return worldBuilder.fromSaveGame(minecraftInterface, minecraftInstallation.newSaveGame(file));
|
||||
} else {
|
||||
throw new IllegalStateException("cannot create a world without a minecraft interface");
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ import amidst.logging.AmidstLogger;
|
|||
import amidst.mojangapi.file.DotMinecraftDirectoryNotFoundException;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
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;
|
||||
|
||||
|
@ -83,4 +85,10 @@ public class MinecraftInstallation {
|
|||
throw new MojangApiParsingException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public SaveGame newSaveGame(File location) throws IOException, MojangApiParsingException {
|
||||
SaveDirectoryService saveDirectoryService = new SaveDirectoryService();
|
||||
SaveDirectory saveDirectory = saveDirectoryService.newSaveDirectory(location);
|
||||
return new SaveGame(saveDirectory, saveDirectoryService.createLevelDat(saveDirectory));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package amidst.mojangapi.file.facade;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.LevelDatNbt;
|
||||
import amidst.mojangapi.file.service.SaveDirectoryService;
|
||||
import amidst.mojangapi.world.WorldType;
|
||||
import amidst.mojangapi.world.coordinates.CoordinatesInWorld;
|
||||
|
||||
@Immutable
|
||||
public class SaveGame {
|
||||
private final SaveDirectoryService saveDirectoryService = new SaveDirectoryService();
|
||||
private final SaveDirectory saveDirectory;
|
||||
private final LevelDatNbt levelDatNbt;
|
||||
|
||||
public SaveGame(SaveDirectory saveDirectory, LevelDatNbt levelDatNbt) {
|
||||
this.saveDirectory = saveDirectory;
|
||||
this.levelDatNbt = levelDatNbt;
|
||||
}
|
||||
|
||||
public long getSeed() {
|
||||
return levelDatNbt.getSeed();
|
||||
}
|
||||
|
||||
public CoordinatesInWorld getWorldSpawn() {
|
||||
return levelDatNbt.getWorldSpawn();
|
||||
}
|
||||
|
||||
public WorldType getWorldType() {
|
||||
return levelDatNbt.getWorldType();
|
||||
}
|
||||
|
||||
public String getGeneratorOptions() {
|
||||
return levelDatNbt.getGeneratorOptions();
|
||||
}
|
||||
|
||||
public boolean hasSingleplayerPlayer() {
|
||||
return levelDatNbt.hasPlayer();
|
||||
}
|
||||
|
||||
public boolean hasMultiplayerPlayers() {
|
||||
return saveDirectory.hasMultiplayerPlayers();
|
||||
}
|
||||
|
||||
public Optional<SaveGamePlayer> tryReadSingleplayerPlayer() {
|
||||
return saveDirectoryService
|
||||
.tryReadSingleplayerPlayerNbt(saveDirectory)
|
||||
.map(p -> new SaveGamePlayer(saveDirectory, p));
|
||||
}
|
||||
|
||||
public List<SaveGamePlayer> tryReadMultiplayerPlayers() {
|
||||
return saveDirectoryService
|
||||
.tryReadMultiplayerPlayerNbts(saveDirectory)
|
||||
.stream()
|
||||
.map(p -> new SaveGamePlayer(saveDirectory, p))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<SaveGamePlayer> tryReadAllPlayers() {
|
||||
List<SaveGamePlayer> result = new LinkedList<>();
|
||||
result.addAll(tryReadSingleplayerPlayer().map(Collections::singletonList).orElseGet(Collections::emptyList));
|
||||
result.addAll(tryReadMultiplayerPlayers());
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package amidst.mojangapi.file.facade;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerNbt;
|
||||
import amidst.mojangapi.file.service.SaveDirectoryService;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
||||
@Immutable
|
||||
public class SaveGamePlayer {
|
||||
private final SaveDirectoryService saveDirectoryService = new SaveDirectoryService();
|
||||
private final SaveDirectory saveDirectory;
|
||||
private final PlayerNbt playerNbt;
|
||||
|
||||
public SaveGamePlayer(SaveDirectory saveDirectory, PlayerNbt playerNbt) {
|
||||
this.saveDirectory = saveDirectory;
|
||||
this.playerNbt = playerNbt;
|
||||
}
|
||||
|
||||
public PlayerCoordinates getPlayerCoordinates() {
|
||||
return playerNbt.getPlayerCoordinates();
|
||||
}
|
||||
|
||||
public boolean tryBackupAndWritePlayerCoordinates(PlayerCoordinates coordinates) {
|
||||
return saveDirectoryService.tryBackup(saveDirectory, playerNbt)
|
||||
&& saveDirectoryService.tryWriteCoordinates(saveDirectory, playerNbt, coordinates);
|
||||
}
|
||||
|
||||
public <R> R map(Supplier<R> ifIsLevelDat, Function<String, R> ifIsPlayerdata, Function<String, R> ifIsPlayers) {
|
||||
return playerNbt.map(ifIsLevelDat, ifIsPlayerdata, ifIsPlayers);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package amidst.mojangapi.file.nbt.player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.NBTUtils;
|
||||
import amidst.mojangapi.file.service.AmidstBackupService;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
||||
@Immutable
|
||||
public class LevelDatPlayerNbt extends PlayerNbt {
|
||||
private final SaveDirectory saveDirectory;
|
||||
|
||||
public LevelDatPlayerNbt(SaveDirectory saveDirectory) {
|
||||
this.saveDirectory = saveDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean tryBackup() {
|
||||
return new AmidstBackupService().tryBackupLevelDat(saveDirectory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWriteCoordinates(PlayerCoordinates coordinates) throws MojangApiParsingException {
|
||||
PlayerLocationSaver.writeToLevelDat(coordinates, saveDirectory.getLevelDat());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerCoordinates readCoordinates() throws IOException, MojangApiParsingException {
|
||||
return PlayerLocationLoader.readFromLevelDat(NBTUtils.readTagFromFile(saveDirectory.getLevelDat()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R map(Supplier<R> ifIsLevelDat, Function<String, R> ifIsPlayerdata, Function<String, R> ifIsPlayers) {
|
||||
return ifIsLevelDat.get();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
package amidst.mojangapi.file.nbt.player;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jnbt.CompoundTag;
|
||||
import org.jnbt.IntTag;
|
||||
|
@ -8,27 +11,28 @@ import org.jnbt.ListTag;
|
|||
import org.jnbt.Tag;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.file.nbt.NBTTagKeys;
|
||||
import amidst.mojangapi.file.nbt.NBTUtils;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
||||
@Immutable
|
||||
public enum PlayerLocationLoader {
|
||||
;
|
||||
|
||||
public static PlayerCoordinates readFromPlayerFile(CompoundTag file) throws MojangApiParsingException {
|
||||
public static Optional<PlayerCoordinates> tryReadFromPlayerFile(File file) throws IOException {
|
||||
try {
|
||||
return readPlayerCoordinates(file);
|
||||
return Optional.of(readPlayerCoordinates(NBTUtils.readTagFromFile(file)));
|
||||
} catch (NullPointerException e) {
|
||||
throw new MojangApiParsingException("cannot read player coordinates", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static PlayerCoordinates readFromLevelDat(CompoundTag file) throws MojangApiParsingException {
|
||||
public static Optional<PlayerCoordinates> tryReadFromLevelDat(File file) throws IOException {
|
||||
try {
|
||||
return readPlayerCoordinates(getSinglePlayerPlayerTag(getTagRootTag(file)));
|
||||
return Optional
|
||||
.of(readPlayerCoordinates(getSinglePlayerPlayerTag(getTagRootTag(NBTUtils.readTagFromFile(file)))));
|
||||
} catch (NullPointerException e) {
|
||||
throw new MojangApiParsingException("cannot read player coordinates", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import org.jnbt.ListTag;
|
|||
import org.jnbt.Tag;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.file.nbt.NBTTagKeys;
|
||||
import amidst.mojangapi.file.nbt.NBTUtils;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
@ -22,23 +21,25 @@ import amidst.mojangapi.world.player.PlayerCoordinates;
|
|||
public enum PlayerLocationSaver {
|
||||
;
|
||||
|
||||
public static void writeToPlayerFile(PlayerCoordinates coordinates, File file) throws MojangApiParsingException {
|
||||
public static boolean tryWriteToPlayerFile(PlayerCoordinates coordinates, File file) throws IOException {
|
||||
try {
|
||||
CompoundTag dataTag = NBTUtils.readTagFromFile(file);
|
||||
CompoundTag modifiedDataTag = modifyPositionInDataTagMultiPlayer(dataTag, coordinates);
|
||||
NBTUtils.writeTagToFile(file, modifiedDataTag);
|
||||
} catch (IOException | NullPointerException e) {
|
||||
throw new MojangApiParsingException("cannot write player coordinates", e);
|
||||
return true;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeToLevelDat(PlayerCoordinates coordinates, File file) throws MojangApiParsingException {
|
||||
public static boolean tryWriteToLevelDat(PlayerCoordinates coordinates, File file) throws IOException {
|
||||
try {
|
||||
CompoundTag baseTag = NBTUtils.readTagFromFile(file);
|
||||
CompoundTag modifiedBaseTag = modifyPositionInBaseTagSinglePlayer(baseTag, coordinates);
|
||||
NBTUtils.writeTagToFile(file, modifiedBaseTag);
|
||||
} catch (IOException | NullPointerException e) {
|
||||
throw new MojangApiParsingException("cannot write player coordinates", e);
|
||||
return true;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,22 @@
|
|||
package amidst.mojangapi.file.nbt.player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
||||
@Immutable
|
||||
public abstract class PlayerNbt {
|
||||
public boolean tryWriteCoordinates(PlayerCoordinates coordinates) throws MojangApiParsingException {
|
||||
if (tryBackup()) {
|
||||
doWriteCoordinates(coordinates);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
private final PlayerCoordinates playerCoordinates;
|
||||
|
||||
public PlayerNbt(PlayerCoordinates playerCoordinates) {
|
||||
this.playerCoordinates = playerCoordinates;
|
||||
}
|
||||
|
||||
protected abstract boolean tryBackup();
|
||||
|
||||
protected abstract void doWriteCoordinates(PlayerCoordinates coordinates) throws MojangApiParsingException;
|
||||
|
||||
public abstract PlayerCoordinates readCoordinates() throws IOException, MojangApiParsingException;
|
||||
public PlayerCoordinates getPlayerCoordinates() {
|
||||
return playerCoordinates;
|
||||
}
|
||||
|
||||
public abstract <R> R map(
|
||||
Supplier<R> ifIsLevelDat,
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
package amidst.mojangapi.file.nbt.player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.NBTUtils;
|
||||
import amidst.mojangapi.file.service.AmidstBackupService;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
||||
@Immutable
|
||||
public class PlayerdataPlayerNbt extends PlayerNbt {
|
||||
private final SaveDirectory saveDirectory;
|
||||
private final String playerUUID;
|
||||
|
||||
public PlayerdataPlayerNbt(SaveDirectory saveDirectory, String playerUUID) {
|
||||
this.saveDirectory = saveDirectory;
|
||||
this.playerUUID = playerUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean tryBackup() {
|
||||
return new AmidstBackupService().tryBackupPlayerdataFile(saveDirectory, playerUUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWriteCoordinates(PlayerCoordinates coordinates) throws MojangApiParsingException {
|
||||
PlayerLocationSaver.writeToPlayerFile(coordinates, saveDirectory.getPlayerdataFile(playerUUID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerCoordinates readCoordinates() throws IOException, MojangApiParsingException {
|
||||
return PlayerLocationLoader
|
||||
.readFromPlayerFile(NBTUtils.readTagFromFile(saveDirectory.getPlayerdataFile(playerUUID)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R map(Supplier<R> ifIsLevelDat, Function<String, R> ifIsPlayerdata, Function<String, R> ifIsPlayers) {
|
||||
return ifIsPlayerdata.apply(playerUUID);
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package amidst.mojangapi.file.nbt.player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.NBTUtils;
|
||||
import amidst.mojangapi.file.service.AmidstBackupService;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
||||
@Immutable
|
||||
public class PlayersPlayerNbt extends PlayerNbt {
|
||||
private final SaveDirectory saveDirectory;
|
||||
private final String playerName;
|
||||
|
||||
public PlayersPlayerNbt(SaveDirectory saveDirectory, String playerName) {
|
||||
this.saveDirectory = saveDirectory;
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean tryBackup() {
|
||||
return new AmidstBackupService().tryBackupPlayersFile(saveDirectory, playerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWriteCoordinates(PlayerCoordinates coordinates) throws MojangApiParsingException {
|
||||
PlayerLocationSaver.writeToPlayerFile(coordinates, saveDirectory.getPlayersFile(playerName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerCoordinates readCoordinates() throws IOException, MojangApiParsingException {
|
||||
return PlayerLocationLoader
|
||||
.readFromPlayerFile(NBTUtils.readTagFromFile(saveDirectory.getPlayersFile(playerName)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R map(Supplier<R> ifIsLevelDat, Function<String, R> ifIsPlayerdata, Function<String, R> ifIsPlayers) {
|
||||
return ifIsPlayers.apply(playerName);
|
||||
}
|
||||
}
|
|
@ -3,9 +3,13 @@ package amidst.mojangapi.file.service;
|
|||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.documentation.NotNull;
|
||||
|
@ -14,13 +18,15 @@ import amidst.mojangapi.file.MojangApiParsingException;
|
|||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.LevelDatNbt;
|
||||
import amidst.mojangapi.file.nbt.NBTUtils;
|
||||
import amidst.mojangapi.file.nbt.player.LevelDatPlayerNbt;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerLocationLoader;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerLocationSaver;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerNbt;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerdataPlayerNbt;
|
||||
import amidst.mojangapi.file.nbt.player.PlayersPlayerNbt;
|
||||
import amidst.mojangapi.world.player.PlayerCoordinates;
|
||||
|
||||
@Immutable
|
||||
public class SaveDirectoryService {
|
||||
private final AmidstBackupService amidstBackupService = new AmidstBackupService();
|
||||
|
||||
/**
|
||||
* Returns a new valid instance of the class SaveDirectory. It tries to use
|
||||
* the given file. If that is not valid it tires to use its parent file. If
|
||||
|
@ -78,9 +84,9 @@ public class SaveDirectoryService {
|
|||
* the map is used as singleplayer map.
|
||||
*/
|
||||
@NotNull
|
||||
public List<PlayerNbt> createSingleplayerPlayerNbts(SaveDirectory saveDirectory) {
|
||||
public Optional<PlayerNbt> tryReadSingleplayerPlayerNbt(SaveDirectory saveDirectory) {
|
||||
AmidstLogger.info("using player from level.dat");
|
||||
return Arrays.asList(new LevelDatPlayerNbt(saveDirectory));
|
||||
return tryReadCoordinatesFromLevelDat(saveDirectory).map(this::createLevelDatPlayerNbt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,53 +94,175 @@ public class SaveDirectoryService {
|
|||
* and uses the player uuid as filename.
|
||||
*/
|
||||
@NotNull
|
||||
public List<PlayerNbt> createMultiplayerPlayerNbts(SaveDirectory saveDirectory) {
|
||||
List<PlayerNbt> result = new ArrayList<>();
|
||||
for (File playerdataFile : getPlayerdataFiles(saveDirectory)) {
|
||||
if (playerdataFile.isFile()) {
|
||||
result.add(new PlayerdataPlayerNbt(saveDirectory, getPlayerUUIDFromPlayerdataFile(playerdataFile)));
|
||||
}
|
||||
}
|
||||
if (!result.isEmpty()) {
|
||||
public List<PlayerNbt> tryReadMultiplayerPlayerNbts(SaveDirectory saveDirectory) {
|
||||
List<PlayerNbt> playerdataPlayers = listFiles(saveDirectory.getPlayerdata())
|
||||
.stream()
|
||||
.filter(File::isFile)
|
||||
.map(f -> createPlayerdataPlayerNbt(saveDirectory, f))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toList());
|
||||
if (!playerdataPlayers.isEmpty()) {
|
||||
AmidstLogger.info("using players from the playerdata directory");
|
||||
return result;
|
||||
}
|
||||
for (File playersFile : getPlayersFiles(saveDirectory)) {
|
||||
if (playersFile.isFile()) {
|
||||
result.add(new PlayersPlayerNbt(saveDirectory, getPlayerNameFromPlayersFile(playersFile)));
|
||||
return playerdataPlayers;
|
||||
} else {
|
||||
List<PlayerNbt> playersPlayers = listFiles(saveDirectory.getPlayers())
|
||||
.stream()
|
||||
.filter(File::isFile)
|
||||
.map(f -> createPlayersPlayerNbt(saveDirectory, f))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toList());
|
||||
if (!playersPlayers.isEmpty()) {
|
||||
AmidstLogger.info("using players from the players directory");
|
||||
return playersPlayers;
|
||||
} else {
|
||||
AmidstLogger.info("no multiplayer players found");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (!result.isEmpty()) {
|
||||
AmidstLogger.info("using players from the players directory");
|
||||
return result;
|
||||
}
|
||||
AmidstLogger.info("no multiplayer players found");
|
||||
return result;
|
||||
}
|
||||
|
||||
private File[] getPlayerdataFiles(SaveDirectory saveDirectory) {
|
||||
File[] files = saveDirectory.getPlayerdata().listFiles();
|
||||
if (files == null) {
|
||||
return new File[0];
|
||||
private List<File> listFiles(File file) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
return Arrays.asList(files);
|
||||
} else {
|
||||
return files;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private File[] getPlayersFiles(SaveDirectory saveDirectory) {
|
||||
File[] files = saveDirectory.getPlayers().listFiles();
|
||||
if (files == null) {
|
||||
return new File[0];
|
||||
} else {
|
||||
return files;
|
||||
}
|
||||
private Optional<PlayerNbt> createPlayerdataPlayerNbt(SaveDirectory saveDirectory, File playerdataFile) {
|
||||
String playerUUID = getPlayerUUIDFromPlayerdataFile(playerdataFile);
|
||||
return tryReadCoordinatesFromPlayerdata(saveDirectory, playerUUID)
|
||||
.map(c -> createPlayerdataPlayerNbt(playerUUID, c));
|
||||
}
|
||||
|
||||
private String getPlayerUUIDFromPlayerdataFile(File playerdataFile) {
|
||||
return playerdataFile.getName().split("\\.")[0];
|
||||
}
|
||||
|
||||
private Optional<PlayerNbt> createPlayersPlayerNbt(SaveDirectory saveDirectory, File playersFile) {
|
||||
String playerName = getPlayerNameFromPlayersFile(playersFile);
|
||||
return tryReadCoordinatesFromPlayers(saveDirectory, playerName).map(c -> createPlayersPlayerNbt(playerName, c));
|
||||
}
|
||||
|
||||
private String getPlayerNameFromPlayersFile(File playersFile) {
|
||||
return playersFile.getName().split("\\.")[0];
|
||||
}
|
||||
|
||||
private PlayerNbt createLevelDatPlayerNbt(PlayerCoordinates playerCoordinates) {
|
||||
return new PlayerNbt(playerCoordinates) {
|
||||
@Override
|
||||
public <R> R map(
|
||||
Supplier<R> ifIsLevelDat,
|
||||
Function<String, R> ifIsPlayerdata,
|
||||
Function<String, R> ifIsPlayers) {
|
||||
return ifIsLevelDat.get();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private PlayerNbt createPlayerdataPlayerNbt(String playerUUID, PlayerCoordinates playerCoordinates) {
|
||||
return new PlayerNbt(playerCoordinates) {
|
||||
@Override
|
||||
public <R> R map(
|
||||
Supplier<R> ifIsLevelDat,
|
||||
Function<String, R> ifIsPlayerdata,
|
||||
Function<String, R> ifIsPlayers) {
|
||||
return ifIsPlayerdata.apply(playerUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private PlayerNbt createPlayersPlayerNbt(String playerName, PlayerCoordinates playerCoordinates) {
|
||||
return new PlayerNbt(playerCoordinates) {
|
||||
@Override
|
||||
public <R> R map(
|
||||
Supplier<R> ifIsLevelDat,
|
||||
Function<String, R> ifIsPlayerdata,
|
||||
Function<String, R> ifIsPlayers) {
|
||||
return ifIsPlayers.apply(playerName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Optional<PlayerCoordinates> tryReadCoordinatesFromLevelDat(SaveDirectory saveDirectory) {
|
||||
try {
|
||||
return PlayerLocationLoader.tryReadFromLevelDat(saveDirectory.getLevelDat());
|
||||
} catch (IOException e) {
|
||||
AmidstLogger.warn(e, "error while reading player coordinates from level.dat");
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<PlayerCoordinates> tryReadCoordinatesFromPlayerdata(
|
||||
SaveDirectory saveDirectory,
|
||||
String playerUUID) {
|
||||
try {
|
||||
return PlayerLocationLoader.tryReadFromPlayerFile(saveDirectory.getPlayerdataFile(playerUUID));
|
||||
} catch (IOException e) {
|
||||
AmidstLogger.warn(e, "error while reading player coordinates for player " + playerUUID);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<PlayerCoordinates> tryReadCoordinatesFromPlayers(SaveDirectory saveDirectory, String playerName) {
|
||||
try {
|
||||
return PlayerLocationLoader.tryReadFromPlayerFile(saveDirectory.getPlayersFile(playerName));
|
||||
} catch (IOException e) {
|
||||
AmidstLogger.warn(e, "error while reading player coordinates for player " + playerName);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryBackup(SaveDirectory saveDirectory, PlayerNbt playerNbt) {
|
||||
return playerNbt.map(
|
||||
() -> amidstBackupService.tryBackupLevelDat(saveDirectory),
|
||||
playerUUID -> amidstBackupService.tryBackupPlayerdataFile(saveDirectory, playerUUID),
|
||||
playerName -> amidstBackupService.tryBackupPlayersFile(saveDirectory, playerName));
|
||||
}
|
||||
|
||||
public boolean tryWriteCoordinates(
|
||||
SaveDirectory saveDirectory,
|
||||
PlayerNbt playerNbt,
|
||||
PlayerCoordinates coordinates) {
|
||||
return playerNbt.map(
|
||||
() -> tryWriteCoordinatesToLevelDat(saveDirectory, coordinates),
|
||||
playerUUID -> tryWriteCoordinatesToPlayerdata(saveDirectory, playerUUID, coordinates),
|
||||
playerName -> tryWriteCoordinatesToPlayers(saveDirectory, playerName, coordinates));
|
||||
}
|
||||
|
||||
private boolean tryWriteCoordinatesToLevelDat(SaveDirectory saveDirectory, PlayerCoordinates coordinates) {
|
||||
try {
|
||||
return PlayerLocationSaver.tryWriteToLevelDat(coordinates, saveDirectory.getLevelDat());
|
||||
} catch (IOException e) {
|
||||
AmidstLogger.warn(e, "error while writing player coordinates to level.dat");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryWriteCoordinatesToPlayerdata(
|
||||
SaveDirectory saveDirectory,
|
||||
String playerUUID,
|
||||
PlayerCoordinates coordinates) {
|
||||
try {
|
||||
return PlayerLocationSaver.tryWriteToPlayerFile(coordinates, saveDirectory.getPlayerdataFile(playerUUID));
|
||||
} catch (IOException e) {
|
||||
AmidstLogger.warn(e, "error while writing player coordinates for player " + playerUUID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryWriteCoordinatesToPlayers(
|
||||
SaveDirectory saveDirectory,
|
||||
String playerName,
|
||||
PlayerCoordinates coordinates) {
|
||||
try {
|
||||
return PlayerLocationSaver.tryWriteToPlayerFile(coordinates, saveDirectory.getPlayersFile(playerName));
|
||||
} catch (IOException e) {
|
||||
AmidstLogger.warn(e, "error while writing player coordinates for player " + playerName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,7 @@ import java.io.IOException;
|
|||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.LevelDatNbt;
|
||||
import amidst.mojangapi.file.service.SaveDirectoryService;
|
||||
import amidst.mojangapi.file.facade.SaveGame;
|
||||
import amidst.mojangapi.minecraftinterface.MinecraftInterface;
|
||||
import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException;
|
||||
import amidst.mojangapi.minecraftinterface.RecognisedVersion;
|
||||
|
@ -74,26 +72,25 @@ public class WorldBuilder {
|
|||
versionFeatures.getValidBiomesForStructure_Spawn()));
|
||||
}
|
||||
|
||||
public World fromSaveGame(MinecraftInterface minecraftInterface, SaveDirectory saveDirectory)
|
||||
public World fromSaveGame(MinecraftInterface minecraftInterface, SaveGame saveGame)
|
||||
throws IOException,
|
||||
MinecraftInterfaceException,
|
||||
MojangApiParsingException {
|
||||
VersionFeatures versionFeatures = DefaultVersionFeatures.create(minecraftInterface.getRecognisedVersion());
|
||||
LevelDatNbt levelDat = new SaveDirectoryService().createLevelDat(saveDirectory);
|
||||
MovablePlayerList movablePlayerList = new MovablePlayerList(
|
||||
playerInformationCache,
|
||||
saveDirectory,
|
||||
saveGame,
|
||||
true,
|
||||
WorldPlayerType.from(saveDirectory, levelDat));
|
||||
WorldPlayerType.from(saveGame));
|
||||
return create(
|
||||
minecraftInterface,
|
||||
WorldSeed.fromSaveGame(levelDat.getSeed()),
|
||||
levelDat.getWorldType(),
|
||||
levelDat.getGeneratorOptions(),
|
||||
WorldSeed.fromSaveGame(saveGame.getSeed()),
|
||||
saveGame.getWorldType(),
|
||||
saveGame.getGeneratorOptions(),
|
||||
movablePlayerList,
|
||||
versionFeatures,
|
||||
new BiomeDataOracle(minecraftInterface),
|
||||
new ImmutableWorldSpawnOracle(levelDat.getWorldSpawn()));
|
||||
new ImmutableWorldSpawnOracle(saveGame.getWorldSpawn()));
|
||||
}
|
||||
|
||||
private World create(
|
||||
|
|
|
@ -7,8 +7,8 @@ import amidst.documentation.AmidstThread;
|
|||
import amidst.documentation.CalledOnlyBy;
|
||||
import amidst.documentation.ThreadSafe;
|
||||
import amidst.logging.AmidstLogger;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerNbt;
|
||||
import amidst.mojangapi.file.facade.SaveGame;
|
||||
import amidst.mojangapi.file.facade.SaveGamePlayer;
|
||||
import amidst.threading.WorkerExecutor;
|
||||
|
||||
@ThreadSafe
|
||||
|
@ -20,7 +20,7 @@ public class MovablePlayerList implements Iterable<Player> {
|
|||
}
|
||||
|
||||
private final PlayerInformationCache playerInformationCache;
|
||||
private final SaveDirectory saveDirectory;
|
||||
private final SaveGame saveGame;
|
||||
private final boolean isSaveEnabled;
|
||||
|
||||
private volatile WorldPlayerType worldPlayerType;
|
||||
|
@ -28,11 +28,11 @@ public class MovablePlayerList implements Iterable<Player> {
|
|||
|
||||
public MovablePlayerList(
|
||||
PlayerInformationCache playerInformationCache,
|
||||
SaveDirectory saveDirectory,
|
||||
SaveGame saveGame,
|
||||
boolean isSaveEnabled,
|
||||
WorldPlayerType worldPlayerType) {
|
||||
this.playerInformationCache = playerInformationCache;
|
||||
this.saveDirectory = saveDirectory;
|
||||
this.saveGame = saveGame;
|
||||
this.isSaveEnabled = isSaveEnabled;
|
||||
this.worldPlayerType = worldPlayerType;
|
||||
}
|
||||
|
@ -46,11 +46,11 @@ public class MovablePlayerList implements Iterable<Player> {
|
|||
}
|
||||
|
||||
public boolean canLoad() {
|
||||
return saveDirectory != null;
|
||||
return saveGame != null;
|
||||
}
|
||||
|
||||
public void load(WorkerExecutor workerExecutor, Runnable onPlayerFinishedLoading) {
|
||||
if (saveDirectory != null) {
|
||||
if (saveGame != null) {
|
||||
AmidstLogger.info("loading player locations");
|
||||
ConcurrentLinkedQueue<Player> players = new ConcurrentLinkedQueue<>();
|
||||
this.players = players;
|
||||
|
@ -70,20 +70,17 @@ public class MovablePlayerList implements Iterable<Player> {
|
|||
WorkerExecutor workerExecutor,
|
||||
ConcurrentLinkedQueue<Player> players,
|
||||
Runnable onPlayerFinishedLoading) {
|
||||
for (PlayerNbt playerNbt : worldPlayerType.createPlayerNbts(saveDirectory)) {
|
||||
workerExecutor.run(() -> loadPlayer(players, playerNbt), onPlayerFinishedLoading);
|
||||
for (SaveGamePlayer saveGamePlayer : worldPlayerType.tryReadPlayers(saveGame)) {
|
||||
workerExecutor.run(() -> loadPlayer(players, saveGamePlayer), onPlayerFinishedLoading);
|
||||
}
|
||||
}
|
||||
|
||||
@CalledOnlyBy(AmidstThread.WORKER)
|
||||
private void loadPlayer(ConcurrentLinkedQueue<Player> players, PlayerNbt playerNbt) {
|
||||
Player player = playerNbt.map(
|
||||
() -> new Player(PlayerInformation.theSingleplayerPlayer(), playerNbt),
|
||||
playerUUID -> new Player(playerInformationCache.getByUUID(playerUUID), playerNbt),
|
||||
playerName -> new Player(playerInformationCache.getByName(playerName), playerNbt));
|
||||
if (player.tryLoadLocation()) {
|
||||
players.offer(player);
|
||||
}
|
||||
private void loadPlayer(ConcurrentLinkedQueue<Player> players, SaveGamePlayer saveGamePlayer) {
|
||||
players.offer(saveGamePlayer.map(
|
||||
() -> new Player(PlayerInformation.theSingleplayerPlayer(), saveGamePlayer),
|
||||
playerUUID -> new Player(playerInformationCache.getByUUID(playerUUID), saveGamePlayer),
|
||||
playerName -> new Player(playerInformationCache.getByName(playerName), saveGamePlayer)));
|
||||
}
|
||||
|
||||
public boolean canSave() {
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
package amidst.mojangapi.world.player;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import amidst.documentation.ThreadSafe;
|
||||
import amidst.logging.AmidstLogger;
|
||||
import amidst.mojangapi.file.MojangApiParsingException;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerNbt;
|
||||
import amidst.mojangapi.file.facade.SaveGamePlayer;
|
||||
import amidst.mojangapi.world.Dimension;
|
||||
import amidst.mojangapi.world.coordinates.CoordinatesInWorld;
|
||||
import amidst.mojangapi.world.icon.WorldIconImage;
|
||||
|
@ -13,13 +10,15 @@ import amidst.mojangapi.world.icon.WorldIconImage;
|
|||
@ThreadSafe
|
||||
public class Player {
|
||||
private final PlayerInformation playerInformation;
|
||||
private final PlayerNbt playerNbt;
|
||||
private final SaveGamePlayer saveGamePlayer;
|
||||
private volatile PlayerCoordinates savedCoordinates;
|
||||
private volatile PlayerCoordinates currentCoordinates;
|
||||
|
||||
public Player(PlayerInformation playerInformation, PlayerNbt playerNbt) {
|
||||
public Player(PlayerInformation playerInformation, SaveGamePlayer saveGamePlayer) {
|
||||
this.playerInformation = playerInformation;
|
||||
this.playerNbt = playerNbt;
|
||||
this.saveGamePlayer = saveGamePlayer;
|
||||
this.savedCoordinates = saveGamePlayer.getPlayerCoordinates();
|
||||
this.currentCoordinates = savedCoordinates;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
|
@ -38,52 +37,22 @@ public class Player {
|
|||
this.currentCoordinates = new PlayerCoordinates(coordinates, height, dimension);
|
||||
}
|
||||
|
||||
public boolean trySaveLocation() {
|
||||
try {
|
||||
if (saveLocation()) {
|
||||
return true;
|
||||
} else {
|
||||
AmidstLogger.warn(
|
||||
"skipping to save player location, because the backup file cannot be created for player: "
|
||||
+ getPlayerName());
|
||||
return false;
|
||||
}
|
||||
} catch (MojangApiParsingException e) {
|
||||
AmidstLogger.warn(e, "error while writing player location for player: " + getPlayerName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the player was not moved or the new location was
|
||||
* successfully saved.
|
||||
*/
|
||||
public synchronized boolean saveLocation() throws MojangApiParsingException {
|
||||
public synchronized boolean trySaveLocation() {
|
||||
PlayerCoordinates currentCoordinates = this.currentCoordinates;
|
||||
if (savedCoordinates != currentCoordinates) {
|
||||
if (playerNbt.tryWriteCoordinates(currentCoordinates)) {
|
||||
if (saveGamePlayer.tryBackupAndWritePlayerCoordinates(currentCoordinates)) {
|
||||
savedCoordinates = currentCoordinates;
|
||||
return true;
|
||||
} else {
|
||||
AmidstLogger.warn("error while writing player location for player: " + getPlayerName());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryLoadLocation() {
|
||||
try {
|
||||
loadLocation();
|
||||
return true;
|
||||
} catch (IOException | MojangApiParsingException e) {
|
||||
AmidstLogger.warn(e, "error while reading player location for player: " + getPlayerName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void loadLocation() throws IOException, MojangApiParsingException {
|
||||
this.savedCoordinates = playerNbt.readCoordinates();
|
||||
this.currentCoordinates = savedCoordinates;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package amidst.mojangapi.world.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import amidst.documentation.Immutable;
|
||||
import amidst.documentation.NotNull;
|
||||
import amidst.mojangapi.file.directory.SaveDirectory;
|
||||
import amidst.mojangapi.file.nbt.LevelDatNbt;
|
||||
import amidst.mojangapi.file.nbt.player.PlayerNbt;
|
||||
import amidst.mojangapi.file.service.SaveDirectoryService;
|
||||
import amidst.mojangapi.file.facade.SaveGame;
|
||||
import amidst.mojangapi.file.facade.SaveGamePlayer;
|
||||
|
||||
@Immutable
|
||||
public enum WorldPlayerType {
|
||||
|
@ -27,9 +24,9 @@ public enum WorldPlayerType {
|
|||
return SELECTABLE;
|
||||
}
|
||||
|
||||
public static WorldPlayerType from(SaveDirectory saveDirectory, LevelDatNbt levelDat) {
|
||||
boolean hasSingleplayerPlayer = levelDat.hasPlayer();
|
||||
boolean hasMultiplayerPlayers = saveDirectory.hasMultiplayerPlayers();
|
||||
public static WorldPlayerType from(SaveGame saveGame) {
|
||||
boolean hasSingleplayerPlayer = saveGame.hasSingleplayerPlayer();
|
||||
boolean hasMultiplayerPlayers = saveGame.hasMultiplayerPlayers();
|
||||
if (hasSingleplayerPlayer && hasMultiplayerPlayers) {
|
||||
return BOTH;
|
||||
} else if (hasSingleplayerPlayer) {
|
||||
|
@ -52,17 +49,16 @@ public enum WorldPlayerType {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
public List<PlayerNbt> createPlayerNbts(SaveDirectory saveDirectory) {
|
||||
SaveDirectoryService saveDirectoryService = new SaveDirectoryService();
|
||||
public List<SaveGamePlayer> tryReadPlayers(SaveGame saveGame) {
|
||||
if (this == BOTH) {
|
||||
List<PlayerNbt> result = new ArrayList<>();
|
||||
result.addAll(saveDirectoryService.createSingleplayerPlayerNbts(saveDirectory));
|
||||
result.addAll(saveDirectoryService.createMultiplayerPlayerNbts(saveDirectory));
|
||||
return result;
|
||||
return saveGame.tryReadAllPlayers();
|
||||
} else if (this == SINGLEPLAYER) {
|
||||
return saveDirectoryService.createSingleplayerPlayerNbts(saveDirectory);
|
||||
return saveGame
|
||||
.tryReadSingleplayerPlayer()
|
||||
.map(Collections::singletonList)
|
||||
.orElseGet(Collections::emptyList);
|
||||
} else if (this == MULTIPLAYER) {
|
||||
return saveDirectoryService.createMultiplayerPlayerNbts(saveDirectory);
|
||||
return saveGame.tryReadMultiplayerPlayers();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue