mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-22 02:26:00 +01:00
Refactor Map-Storage to be more modular in preparation for SQL-storage
This commit is contained in:
parent
3608c050ac
commit
49e956ed66
@ -35,6 +35,8 @@
|
||||
import de.bluecolored.bluemap.core.mca.MCAWorld;
|
||||
import de.bluecolored.bluemap.core.resourcepack.ParseResourceException;
|
||||
import de.bluecolored.bluemap.core.resourcepack.ResourcePack;
|
||||
import de.bluecolored.bluemap.core.storage.FileStorage;
|
||||
import de.bluecolored.bluemap.core.storage.Storage;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
@ -164,11 +166,16 @@ private synchronized void loadWorldsAndMaps() throws IOException, InterruptedExc
|
||||
}
|
||||
}
|
||||
|
||||
Storage storage = new FileStorage(
|
||||
getRenderConfig().getWebRoot().toPath().resolve("data"),
|
||||
mapConfig.getCompression()
|
||||
);
|
||||
|
||||
BmMap map = new BmMap(
|
||||
id,
|
||||
name,
|
||||
world,
|
||||
getRenderConfig().getWebRoot().toPath().resolve("data").resolve(id),
|
||||
storage,
|
||||
getResourcePack(),
|
||||
mapConfig
|
||||
);
|
||||
|
@ -35,7 +35,6 @@
|
||||
import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask;
|
||||
import de.bluecolored.bluemap.common.rendermanager.RenderManager;
|
||||
import de.bluecolored.bluemap.common.rendermanager.WorldRegionRenderTask;
|
||||
import de.bluecolored.bluemap.core.map.BmMap;
|
||||
import de.bluecolored.bluemap.core.world.Grid;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -96,7 +95,7 @@ public boolean scheduleMapUpdateTask(BlueMapMap map, Collection<Vector2i> region
|
||||
@Override
|
||||
public boolean scheduleMapPurgeTask(BlueMapMap map) throws IOException {
|
||||
BlueMapMapImpl cmap = castMap(map);
|
||||
return renderManager.scheduleRenderTask(new MapPurgeTask(cmap.getMapType()));
|
||||
return renderManager.scheduleRenderTask(MapPurgeTask.create(cmap.getMapType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,7 +64,6 @@
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
@ -810,41 +809,33 @@ public int purgeCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
// parse map argument
|
||||
String mapId = context.getArgument("map", String.class);
|
||||
String mapString = context.getArgument("map", String.class);
|
||||
BmMap map = parseMap(mapString).orElse(null);
|
||||
|
||||
if (map == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There is no ", helper.mapHelperHover(), " with this name: ", TextColor.WHITE, mapString));
|
||||
return 0;
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Path mapFolder = plugin.getRenderConfig().getWebRoot().toPath().resolve("data").resolve(mapId);
|
||||
if (!Files.isDirectory(mapFolder)) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There is no map-data to purge for the map-id '" + mapId + "'!"));
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<BmMap> optMap = parseMap(mapId);
|
||||
|
||||
// delete map
|
||||
MapPurgeTask purgeTask;
|
||||
if (optMap.isPresent()){
|
||||
purgeTask = new MapPurgeTask(optMap.get());
|
||||
} else {
|
||||
purgeTask = new MapPurgeTask(mapFolder);
|
||||
}
|
||||
MapPurgeTask purgeTask = MapPurgeTask.create(map);
|
||||
|
||||
plugin.getRenderManager().scheduleRenderTaskNext(purgeTask);
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Created new Task to purge map '" + mapId + "'"));
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Created new Task to purge map '" + map.getId() + "'"));
|
||||
|
||||
// if map is loaded, reset it and start updating it after the purge
|
||||
if (optMap.isPresent()) {
|
||||
RenderTask updateTask = new MapUpdateTask(optMap.get());
|
||||
plugin.getRenderManager().scheduleRenderTask(updateTask);
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Created new Update-Task for map '" + mapId + "'"));
|
||||
source.sendMessage(Text.of(TextColor.GRAY, "If you don't want to render this map again, you need to remove it from your configuration first!"));
|
||||
}
|
||||
// reset the map and start updating it after the purge
|
||||
RenderTask updateTask = new MapUpdateTask(map);
|
||||
plugin.getRenderManager().scheduleRenderTask(updateTask);
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Created new Update-Task for map '" + map.getId() + "'"));
|
||||
source.sendMessage(Text.of(TextColor.GRAY, "If you don't this map to render again after the purge, use ",
|
||||
TextColor.DARK_GRAY, "/bluemap freeze " + map.getId(), TextColor.GRAY, " first!"));
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Use ", TextColor.GRAY, "/bluemap", TextColor.GREEN, " to see the progress."));
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There was an error trying to purge '" + mapId + "', see console for details."));
|
||||
Logger.global.logError("Failed to purge map '" + mapId + "'!", e);
|
||||
source.sendMessage(Text.of(TextColor.RED, "There was an error trying to purge '" + map.getId() + "', see console for details."));
|
||||
Logger.global.logError("Failed to purge map '" + map.getId() + "'!", e);
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
@ -26,96 +26,179 @@
|
||||
|
||||
import de.bluecolored.bluemap.core.debug.DebugDump;
|
||||
import de.bluecolored.bluemap.core.map.BmMap;
|
||||
import de.bluecolored.bluemap.core.storage.FileStorage;
|
||||
import de.bluecolored.bluemap.core.storage.Storage;
|
||||
import de.bluecolored.bluemap.core.util.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MapPurgeTask implements RenderTask {
|
||||
public abstract class MapPurgeTask implements RenderTask {
|
||||
|
||||
@DebugDump private final BmMap map;
|
||||
@DebugDump private final Path directory;
|
||||
@DebugDump private final int subFilesCount;
|
||||
private final LinkedList<Path> subFiles;
|
||||
|
||||
@DebugDump private volatile boolean hasMoreWork;
|
||||
@DebugDump private volatile boolean cancelled;
|
||||
|
||||
public MapPurgeTask(Path mapDirectory) throws IOException {
|
||||
this(null, mapDirectory);
|
||||
public static MapPurgeTask create(BmMap map) throws IOException {
|
||||
Storage storage = map.getStorage();
|
||||
if (storage instanceof FileStorage) {
|
||||
return new MapFilePurgeTask(map, (FileStorage) storage);
|
||||
} else {
|
||||
return new MapStoragePurgeTask(map);
|
||||
}
|
||||
}
|
||||
|
||||
public MapPurgeTask(BmMap map) throws IOException {
|
||||
this(map, map.getFileRoot());
|
||||
public static MapPurgeTask create(Path mapDirectory) throws IOException {
|
||||
return new MapFilePurgeTask(mapDirectory);
|
||||
}
|
||||
|
||||
private MapPurgeTask(BmMap map, Path directory) throws IOException {
|
||||
this.map = map;
|
||||
this.directory = directory;
|
||||
this.subFiles = Files.walk(directory, 3)
|
||||
.collect(Collectors.toCollection(LinkedList::new));
|
||||
this.subFilesCount = subFiles.size();
|
||||
this.hasMoreWork = true;
|
||||
this.cancelled = false;
|
||||
@DebugDump
|
||||
private static class MapFilePurgeTask extends MapPurgeTask {
|
||||
|
||||
private final BmMap map;
|
||||
private final Path directory;
|
||||
private final int subFilesCount;
|
||||
private final LinkedList<Path> subFiles;
|
||||
|
||||
private volatile boolean hasMoreWork;
|
||||
private volatile boolean cancelled;
|
||||
|
||||
public MapFilePurgeTask(Path mapDirectory) throws IOException {
|
||||
this(null, mapDirectory);
|
||||
}
|
||||
|
||||
public MapFilePurgeTask(BmMap map, FileStorage fileStorage) throws IOException {
|
||||
this(map, fileStorage.getFilePath(map.getId()));
|
||||
}
|
||||
|
||||
private MapFilePurgeTask(BmMap map, Path directory) throws IOException {
|
||||
this.map = map;
|
||||
this.directory = directory;
|
||||
this.subFiles = Files.walk(directory, 3)
|
||||
.collect(Collectors.toCollection(LinkedList::new));
|
||||
this.subFilesCount = subFiles.size();
|
||||
this.hasMoreWork = true;
|
||||
this.cancelled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork() throws Exception {
|
||||
synchronized (this) {
|
||||
if (!this.hasMoreWork) return;
|
||||
this.hasMoreWork = false;
|
||||
}
|
||||
|
||||
try {
|
||||
// delete subFiles first to be able to track the progress and cancel
|
||||
while (!subFiles.isEmpty()) {
|
||||
Path subFile = subFiles.getLast();
|
||||
FileUtils.delete(subFile.toFile());
|
||||
subFiles.removeLast();
|
||||
if (this.cancelled) return;
|
||||
}
|
||||
|
||||
// make sure everything is deleted
|
||||
FileUtils.delete(directory.toFile());
|
||||
} finally {
|
||||
// reset map render state
|
||||
if (this.map != null) {
|
||||
this.map.getRenderState().reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreWork() {
|
||||
return this.hasMoreWork;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DebugDump
|
||||
public double estimateProgress() {
|
||||
return 1d - (subFiles.size() / (double) subFilesCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.cancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(RenderTask task) {
|
||||
if (task == this) return true;
|
||||
if (task instanceof MapFilePurgeTask) {
|
||||
return ((MapFilePurgeTask) task).directory.toAbsolutePath().normalize()
|
||||
.startsWith(this.directory.toAbsolutePath().normalize());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Purge Map " + directory.getFileName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork() throws Exception {
|
||||
synchronized (this) {
|
||||
if (!this.hasMoreWork) return;
|
||||
@DebugDump
|
||||
private static class MapStoragePurgeTask extends MapPurgeTask {
|
||||
|
||||
private final BmMap map;
|
||||
|
||||
private volatile boolean hasMoreWork;
|
||||
|
||||
public MapStoragePurgeTask(BmMap map) {
|
||||
this.map = Objects.requireNonNull(map);
|
||||
this.hasMoreWork = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork() throws Exception {
|
||||
synchronized (this) {
|
||||
if (!this.hasMoreWork) return;
|
||||
this.hasMoreWork = false;
|
||||
}
|
||||
|
||||
try {
|
||||
map.getStorage().purgeMap(map.getId());
|
||||
} finally {
|
||||
// reset map render state
|
||||
map.getRenderState().reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreWork() {
|
||||
return this.hasMoreWork;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DebugDump
|
||||
public double estimateProgress() {
|
||||
return 0d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.hasMoreWork = false;
|
||||
}
|
||||
|
||||
try {
|
||||
// delete subFiles first to be able to track the progress and cancel
|
||||
while (!subFiles.isEmpty()) {
|
||||
Path subFile = subFiles.getLast();
|
||||
FileUtils.delete(subFile.toFile());
|
||||
subFiles.removeLast();
|
||||
if (this.cancelled) return;
|
||||
@Override
|
||||
public boolean contains(RenderTask task) {
|
||||
if (task == this) return true;
|
||||
if (task instanceof MapStoragePurgeTask) {
|
||||
return map.equals(((MapStoragePurgeTask) task).map);
|
||||
}
|
||||
|
||||
// make sure everything is deleted
|
||||
FileUtils.delete(directory.toFile());
|
||||
} finally {
|
||||
// reset map render state
|
||||
if (this.map != null) {
|
||||
this.map.getRenderState().reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreWork() {
|
||||
return this.hasMoreWork;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double estimateProgress() {
|
||||
return 1d - (subFiles.size() / (double) subFilesCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.cancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(RenderTask task) {
|
||||
if (task == this) return true;
|
||||
if (task instanceof MapPurgeTask) {
|
||||
return ((MapPurgeTask) task).directory.toAbsolutePath().normalize().startsWith(this.directory.toAbsolutePath().normalize());
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Purge Map " + map.getId();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Purge Map " + directory.getFileName();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import de.bluecolored.bluemap.core.debug.DebugDump;
|
||||
import de.bluecolored.bluemap.core.map.MapSettings;
|
||||
import de.bluecolored.bluemap.core.storage.Compression;
|
||||
import de.bluecolored.bluemap.core.util.ConfigUtils;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
|
||||
@ -53,7 +54,7 @@ public class MapConfig implements MapSettings {
|
||||
private Vector3i min, max;
|
||||
private boolean renderEdges;
|
||||
|
||||
private boolean useGzip;
|
||||
private Compression compression;
|
||||
private boolean ignoreMissingLightData;
|
||||
|
||||
private int hiresTileSize;
|
||||
@ -106,7 +107,7 @@ public MapConfig(ConfigurationNode node) throws IOException {
|
||||
this.renderEdges = node.node("renderEdges").getBoolean(true);
|
||||
|
||||
//useCompression
|
||||
this.useGzip = node.node("useCompression").getBoolean(true);
|
||||
this.compression = node.node("useCompression").getBoolean(true) ? Compression.GZIP : Compression.NONE;
|
||||
|
||||
//ignoreMissingLightData
|
||||
this.ignoreMissingLightData = node.node("ignoreMissingLightData").getBoolean(false);
|
||||
@ -142,6 +143,10 @@ public int getSkyColor() {
|
||||
return skyColor;
|
||||
}
|
||||
|
||||
public Compression getCompression() {
|
||||
return compression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAmbientLight() {
|
||||
return ambientLight;
|
||||
@ -196,9 +201,4 @@ public boolean isRenderEdges() {
|
||||
return renderEdges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useGzipCompression() {
|
||||
return useGzip;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,10 +35,10 @@
|
||||
@DebugDump
|
||||
public class RenderConfig {
|
||||
|
||||
private File webRoot = new File("web");
|
||||
private File webRoot;
|
||||
private boolean useCookies;
|
||||
private boolean enableFreeFlight;
|
||||
private List<MapConfig> mapConfigs = new ArrayList<>();
|
||||
private List<MapConfig> mapConfigs;
|
||||
|
||||
public RenderConfig(ConfigurationNode node) throws IOException {
|
||||
|
||||
|
@ -28,16 +28,19 @@
|
||||
import de.bluecolored.bluemap.core.debug.DebugDump;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.map.hires.HiresModelManager;
|
||||
import de.bluecolored.bluemap.core.map.lowres.LowresModelManager;
|
||||
import de.bluecolored.bluemap.core.map.hires.HiresTileMeta;
|
||||
import de.bluecolored.bluemap.core.map.lowres.LowresModelManager;
|
||||
import de.bluecolored.bluemap.core.resourcepack.ResourcePack;
|
||||
import de.bluecolored.bluemap.core.storage.*;
|
||||
import de.bluecolored.bluemap.core.world.Grid;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@DebugDump
|
||||
@ -46,7 +49,7 @@ public class BmMap {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final World world;
|
||||
private final Path fileRoot;
|
||||
private final Storage storage;
|
||||
|
||||
private final MapRenderState renderState;
|
||||
|
||||
@ -58,38 +61,37 @@ public class BmMap {
|
||||
private long renderTimeSumNanos;
|
||||
private long tilesRendered;
|
||||
|
||||
public BmMap(String id, String name, World world, Path fileRoot, ResourcePack resourcePack, MapSettings settings) throws IOException {
|
||||
public BmMap(String id, String name, World world, Storage storage, ResourcePack resourcePack, MapSettings settings) throws IOException {
|
||||
this.id = Objects.requireNonNull(id);
|
||||
this.name = Objects.requireNonNull(name);
|
||||
this.world = Objects.requireNonNull(world);
|
||||
this.fileRoot = Objects.requireNonNull(fileRoot);
|
||||
this.storage = Objects.requireNonNull(storage);
|
||||
|
||||
Objects.requireNonNull(resourcePack);
|
||||
Objects.requireNonNull(settings);
|
||||
|
||||
this.renderState = new MapRenderState();
|
||||
|
||||
File rstateFile = getRenderStateFile();
|
||||
if (rstateFile.exists()) {
|
||||
try {
|
||||
this.renderState.load(rstateFile);
|
||||
Optional<InputStream> rstateData = storage.readMeta(id, MetaType.RENDER_STATE);
|
||||
if (rstateData.isPresent()) {
|
||||
try (InputStream in = rstateData.get()){
|
||||
this.renderState.load(in);
|
||||
} catch (IOException ex) {
|
||||
Logger.global.logWarning("Failed to load render-state for map '" + getId() + "': " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.hiresModelManager = new HiresModelManager(
|
||||
fileRoot.resolve("hires"),
|
||||
storage.tileStorage(id, TileType.HIRES),
|
||||
resourcePack,
|
||||
settings,
|
||||
new Grid(settings.getHiresTileSize(), 2)
|
||||
);
|
||||
|
||||
this.lowresModelManager = new LowresModelManager(
|
||||
fileRoot.resolve("lowres"),
|
||||
storage.tileStorage(id, TileType.LOWRES),
|
||||
new Vector2i(settings.getLowresPointsPerLowresTile(), settings.getLowresPointsPerLowresTile()),
|
||||
new Vector2i(settings.getLowresPointsPerHiresTile(), settings.getLowresPointsPerHiresTile()),
|
||||
settings.useGzipCompression()
|
||||
new Vector2i(settings.getLowresPointsPerHiresTile(), settings.getLowresPointsPerHiresTile())
|
||||
);
|
||||
|
||||
this.tileFilter = t -> true;
|
||||
@ -116,17 +118,13 @@ public void renderTile(Vector2i tile) {
|
||||
public synchronized void save() {
|
||||
lowresModelManager.save();
|
||||
|
||||
try {
|
||||
this.renderState.save(getRenderStateFile());
|
||||
try (OutputStream out = storage.writeMeta(id, MetaType.RENDER_STATE)) {
|
||||
this.renderState.save(out);
|
||||
} catch (IOException ex){
|
||||
Logger.global.logError("Failed to save render-state for map: '" + this.id + "'!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public File getRenderStateFile() {
|
||||
return fileRoot.resolve(".rstate").toFile();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@ -139,8 +137,8 @@ public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public Path getFileRoot() {
|
||||
return fileRoot;
|
||||
public Storage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public MapRenderState getRenderState() {
|
||||
@ -189,7 +187,7 @@ public String toString() {
|
||||
"id='" + id + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", world=" + world +
|
||||
", fileRoot=" + fileRoot +
|
||||
", storage=" + storage +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import de.bluecolored.bluemap.core.debug.DebugDump;
|
||||
import de.bluecolored.bluemap.core.util.AtomicFileHelper;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
@ -57,12 +56,9 @@ public synchronized void reset() {
|
||||
regionRenderTimes.clear();
|
||||
}
|
||||
|
||||
public synchronized void save(File file) throws IOException {
|
||||
OutputStream fOut = AtomicFileHelper.createFilepartOutputStream(file);
|
||||
GZIPOutputStream gOut = new GZIPOutputStream(fOut);
|
||||
|
||||
public synchronized void save(OutputStream out) throws IOException {
|
||||
try (
|
||||
DataOutputStream dOut = new DataOutputStream(gOut)
|
||||
DataOutputStream dOut = new DataOutputStream(new GZIPOutputStream(out))
|
||||
) {
|
||||
dOut.writeInt(regionRenderTimes.size());
|
||||
|
||||
@ -79,13 +75,11 @@ public synchronized void save(File file) throws IOException {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void load(File file) throws IOException {
|
||||
public synchronized void load(InputStream in) throws IOException {
|
||||
regionRenderTimes.clear();
|
||||
|
||||
try (
|
||||
FileInputStream fIn = new FileInputStream(file);
|
||||
GZIPInputStream gIn = new GZIPInputStream(fIn);
|
||||
DataInputStream dIn = new DataInputStream(gIn)
|
||||
DataInputStream dIn = new DataInputStream(new GZIPInputStream(in))
|
||||
) {
|
||||
int size = dIn.readInt();
|
||||
|
||||
@ -98,7 +92,7 @@ public synchronized void load(File file) throws IOException {
|
||||
|
||||
regionRenderTimes.put(regionPos, renderTime);
|
||||
}
|
||||
}
|
||||
} catch (EOFException ignore){} // ignoring a sudden end of stream, since it is save to only read as many as we can
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,34 +28,27 @@
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.resourcepack.ResourcePack;
|
||||
import de.bluecolored.bluemap.core.util.AtomicFileHelper;
|
||||
import de.bluecolored.bluemap.core.util.FileUtils;
|
||||
import de.bluecolored.bluemap.core.storage.Storage;
|
||||
import de.bluecolored.bluemap.core.world.Grid;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class HiresModelManager {
|
||||
|
||||
private final Path fileRoot;
|
||||
private final Storage.TileStorage storage;
|
||||
private final HiresModelRenderer renderer;
|
||||
private final Grid tileGrid;
|
||||
private final boolean useGzip;
|
||||
|
||||
public HiresModelManager(Path fileRoot, ResourcePack resourcePack, RenderSettings renderSettings, Grid tileGrid) {
|
||||
this(fileRoot, new HiresModelRenderer(resourcePack, renderSettings), tileGrid, renderSettings.useGzipCompression());
|
||||
public HiresModelManager(Storage.TileStorage storage, ResourcePack resourcePack, RenderSettings renderSettings, Grid tileGrid) {
|
||||
this(storage, new HiresModelRenderer(resourcePack, renderSettings), tileGrid);
|
||||
}
|
||||
|
||||
public HiresModelManager(Path fileRoot, HiresModelRenderer renderer, Grid tileGrid, boolean useGzip) {
|
||||
this.fileRoot = fileRoot;
|
||||
public HiresModelManager(Storage.TileStorage storage, HiresModelRenderer renderer, Grid tileGrid) {
|
||||
this.storage = storage;
|
||||
this.renderer = renderer;
|
||||
|
||||
this.tileGrid = tileGrid;
|
||||
|
||||
this.useGzip = useGzip;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,25 +72,10 @@ public HiresTileMeta render(World world, Vector2i tile) {
|
||||
}
|
||||
|
||||
private void save(final HiresTileModel model, Vector2i tile) {
|
||||
File file = getFile(tile, useGzip);
|
||||
|
||||
OutputStream os = null;
|
||||
try {
|
||||
os = AtomicFileHelper.createFilepartOutputStream(file);
|
||||
os = new BufferedOutputStream(os);
|
||||
if (useGzip) os = new GZIPOutputStream(os);
|
||||
|
||||
try (OutputStream os = storage.write(tile)) {
|
||||
model.writeBufferGeometryJson(os);
|
||||
} catch (IOException e){
|
||||
Logger.global.logError("Failed to save hires model: " + file, e);
|
||||
} finally {
|
||||
try {
|
||||
if (os != null) {
|
||||
os.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logger.global.logError("Failed to close file: " + file, e);
|
||||
}
|
||||
Logger.global.logError("Failed to save hires model: " + tile, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,11 +86,4 @@ public Grid getTileGrid() {
|
||||
return tileGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file for a tile
|
||||
*/
|
||||
public File getFile(Vector2i tilePos, boolean gzip){
|
||||
return FileUtils.coordsToFile(fileRoot, tilePos, "json" + (gzip ? ".gz" : ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -73,13 +73,6 @@ default boolean isRenderEdges() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If gzip compression will be used to compress the generated files
|
||||
*/
|
||||
default boolean useGzipCompression() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean isInsideRenderBoundaries(int x, int z) {
|
||||
Vector3i min = getMin();
|
||||
Vector3i max = getMax();
|
||||
|
@ -26,16 +26,17 @@
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import de.bluecolored.bluemap.core.storage.Storage;
|
||||
import de.bluecolored.bluemap.core.threejs.BufferGeometry;
|
||||
import de.bluecolored.bluemap.core.util.AtomicFileHelper;
|
||||
import de.bluecolored.bluemap.core.util.MathUtils;
|
||||
import de.bluecolored.bluemap.core.util.ModelUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class LowresModel {
|
||||
|
||||
@ -79,7 +80,7 @@ public void update(Vector2i point, float height, Vector3f color){
|
||||
* Saves this model to its file
|
||||
* @param force if this is false, the model is only saved if it has any changes
|
||||
*/
|
||||
public void save(File file, boolean force, boolean useGzip) throws IOException {
|
||||
public void save(Storage.TileStorage storage, Vector2i tile, boolean force) throws IOException {
|
||||
if (!force && !hasUnsavedChanges) return;
|
||||
this.hasUnsavedChanges = false;
|
||||
|
||||
@ -91,11 +92,9 @@ public void save(File file, boolean force, boolean useGzip) throws IOException {
|
||||
}
|
||||
|
||||
synchronized (fileLock) {
|
||||
OutputStream os = new BufferedOutputStream(AtomicFileHelper.createFilepartOutputStream(file));
|
||||
if (useGzip) os = new GZIPOutputStream(os);
|
||||
OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8);
|
||||
try (
|
||||
PrintWriter pw = new PrintWriter(osw)
|
||||
PrintWriter pw = new PrintWriter(
|
||||
new OutputStreamWriter(storage.write(tile), StandardCharsets.UTF_8))
|
||||
){
|
||||
pw.print(json);
|
||||
}
|
||||
|
@ -28,42 +28,36 @@
|
||||
import com.flowpowered.math.vector.Vector3f;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.map.hires.HiresTileMeta;
|
||||
import de.bluecolored.bluemap.core.storage.Storage;
|
||||
import de.bluecolored.bluemap.core.threejs.BufferGeometry;
|
||||
import de.bluecolored.bluemap.core.util.FileUtils;
|
||||
import de.bluecolored.bluemap.core.util.math.Color;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class LowresModelManager {
|
||||
|
||||
private final Path fileRoot;
|
||||
private final Storage.TileStorage storage;
|
||||
private final Vector2i pointsPerLowresTile;
|
||||
private final Vector2i pointsPerHiresTile;
|
||||
private final boolean useGzip;
|
||||
|
||||
private final Map<File, CachedModel> models;
|
||||
private final Map<Vector2i, CachedModel> models;
|
||||
|
||||
public LowresModelManager(Path fileRoot, Vector2i pointsPerLowresTile, Vector2i pointsPerHiresTile, boolean useGzip) {
|
||||
this.fileRoot = fileRoot;
|
||||
public LowresModelManager(Storage.TileStorage storage, Vector2i pointsPerLowresTile, Vector2i pointsPerHiresTile) {
|
||||
this.storage = storage;
|
||||
|
||||
this.pointsPerLowresTile = pointsPerLowresTile;
|
||||
this.pointsPerHiresTile = pointsPerHiresTile;
|
||||
|
||||
models = new ConcurrentHashMap<>();
|
||||
|
||||
this.useGzip = useGzip;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,7 +110,7 @@ public void render(HiresTileMeta tileMeta) {
|
||||
* Saves all unsaved changes to the models to disk
|
||||
*/
|
||||
public synchronized void save(){
|
||||
for (Entry<File, CachedModel> entry : models.entrySet()){
|
||||
for (Entry<Vector2i, CachedModel> entry : models.entrySet()){
|
||||
saveModel(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
@ -159,47 +153,39 @@ public void update(int px, int pz, float height, Color color) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file for a tile
|
||||
*/
|
||||
public File getFile(Vector2i tile, boolean useGzip){
|
||||
return FileUtils.coordsToFile(fileRoot, tile, "json" + (useGzip ? ".gz" : ""));
|
||||
}
|
||||
|
||||
private LowresModel getModel(Vector2i tile) {
|
||||
|
||||
File modelFile = getFile(tile, useGzip);
|
||||
CachedModel model = models.get(modelFile);
|
||||
CachedModel model = models.get(tile);
|
||||
|
||||
if (model == null){
|
||||
synchronized (this) {
|
||||
model = models.get(modelFile);
|
||||
model = models.get(tile);
|
||||
if (model == null){
|
||||
|
||||
if (modelFile.exists()){
|
||||
try (FileInputStream fis = new FileInputStream(modelFile)) {
|
||||
InputStream is = fis;
|
||||
if (useGzip) is = new GZIPInputStream(is);
|
||||
try {
|
||||
Optional<InputStream> optIs = storage.read(tile);
|
||||
if (optIs.isPresent()){
|
||||
try (InputStream is = optIs.get()) {
|
||||
String json = IOUtils.toString(is, StandardCharsets.UTF_8);
|
||||
|
||||
String json = IOUtils.toString(is, StandardCharsets.UTF_8);
|
||||
|
||||
model = new CachedModel(BufferGeometry.fromJson(json));
|
||||
} catch (IllegalArgumentException | IOException ex){
|
||||
Logger.global.logWarning("Failed to load lowres model '" + modelFile + "': " + ex);
|
||||
|
||||
try {
|
||||
FileUtils.delete(modelFile);
|
||||
} catch (IOException ex2) {
|
||||
Logger.global.logError("Failed to delete lowres-file: " + modelFile, ex2);
|
||||
model = new CachedModel(BufferGeometry.fromJson(json));
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException | IOException ex){
|
||||
Logger.global.logWarning("Failed to load lowres model '" + tile + "': " + ex);
|
||||
|
||||
try {
|
||||
storage.delete(tile);
|
||||
} catch (IOException ex2) {
|
||||
Logger.global.logError("Failed to delete lowres-file: " + tile, ex2);
|
||||
}
|
||||
}
|
||||
|
||||
if (model == null){
|
||||
model = new CachedModel(pointsPerLowresTile);
|
||||
}
|
||||
|
||||
models.put(modelFile, model);
|
||||
models.put(tile, model);
|
||||
|
||||
tidyUpModelCache();
|
||||
}
|
||||
@ -217,12 +203,12 @@ private LowresModel getModel(Vector2i tile) {
|
||||
* This method gets automatically called if the cache grows, but if you want to ensure model will be saved after 2 minutes, you could e.g call this method every second.<br>
|
||||
*/
|
||||
public synchronized void tidyUpModelCache() {
|
||||
List<Entry<File, CachedModel>> entries = new ArrayList<>(models.size());
|
||||
List<Entry<Vector2i, CachedModel>> entries = new ArrayList<>(models.size());
|
||||
entries.addAll(models.entrySet());
|
||||
entries.sort((e1, e2) -> (int) Math.signum(e1.getValue().cacheTime - e2.getValue().cacheTime));
|
||||
|
||||
int size = entries.size();
|
||||
for (Entry<File, CachedModel> e : entries) {
|
||||
for (Entry<Vector2i, CachedModel> e : entries) {
|
||||
if (size > 10) {
|
||||
saveAndRemoveModel(e.getKey(), e.getValue());
|
||||
continue;
|
||||
@ -234,22 +220,22 @@ public synchronized void tidyUpModelCache() {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void saveAndRemoveModel(File modelFile, CachedModel model) {
|
||||
models.remove(modelFile);
|
||||
private synchronized void saveAndRemoveModel(Vector2i tile, CachedModel model) {
|
||||
models.remove(tile);
|
||||
try {
|
||||
model.save(modelFile, false, useGzip);
|
||||
model.save(storage, tile,false);
|
||||
//logger.logDebug("Saved and unloaded lowres tile: " + model.getTile());
|
||||
} catch (IOException ex) {
|
||||
Logger.global.logError("Failed to save and unload lowres-model: " + modelFile, ex);
|
||||
Logger.global.logError("Failed to save and unload lowres-model: " + tile, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveModel(File modelFile, CachedModel model) {
|
||||
private void saveModel(Vector2i tile, CachedModel model) {
|
||||
try {
|
||||
model.save(modelFile, false, useGzip);
|
||||
model.save(storage, tile, false);
|
||||
//logger.logDebug("Saved lowres tile: " + model.getTile());
|
||||
} catch (IOException ex) {
|
||||
Logger.global.logError("Failed to save lowres-model: " + modelFile, ex);
|
||||
Logger.global.logError("Failed to save lowres-model: " + tile, ex);
|
||||
}
|
||||
|
||||
model.resetCacheTime();
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package de.bluecolored.bluemap.core.storage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public enum Compression {
|
||||
|
||||
NONE("") {
|
||||
@Override
|
||||
public OutputStream compress(OutputStream out) {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream decompress(InputStream in) {
|
||||
return in;
|
||||
}
|
||||
},
|
||||
|
||||
GZIP(".gz"){
|
||||
|
||||
@Override
|
||||
public OutputStream compress(OutputStream out) throws IOException {
|
||||
return new GZIPOutputStream(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream decompress(InputStream in) throws IOException {
|
||||
return new GZIPInputStream(in);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final String fileSuffix;
|
||||
|
||||
Compression(String fileSuffix) {
|
||||
this.fileSuffix = fileSuffix;
|
||||
}
|
||||
|
||||
public String getFileSuffix() {
|
||||
return fileSuffix;
|
||||
}
|
||||
|
||||
public abstract OutputStream compress(OutputStream out) throws IOException;
|
||||
|
||||
public abstract InputStream decompress(InputStream in) throws IOException;
|
||||
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package de.bluecolored.bluemap.core.storage;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import de.bluecolored.bluemap.core.debug.DebugDump;
|
||||
import de.bluecolored.bluemap.core.util.AtomicFileHelper;
|
||||
import de.bluecolored.bluemap.core.util.FileUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.*;
|
||||
|
||||
@DebugDump
|
||||
public class FileStorage extends Storage {
|
||||
|
||||
private static final EnumMap<MetaType, String> metaTypeFileNames = new EnumMap<>(MetaType.class);
|
||||
static {
|
||||
metaTypeFileNames.put(MetaType.TEXTURES, "../textures.json");
|
||||
metaTypeFileNames.put(MetaType.SETTINGS, "../settings.json");
|
||||
metaTypeFileNames.put(MetaType.MARKERS, "../markers.json");
|
||||
metaTypeFileNames.put(MetaType.RENDER_STATE, ".rstate");
|
||||
}
|
||||
|
||||
private final Path root;
|
||||
private final Compression compression;
|
||||
|
||||
public FileStorage(Path root, Compression compression) {
|
||||
this.root = root;
|
||||
this.compression = compression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream writeMapTile(String mapId, TileType tileType, Vector2i tile) throws IOException {
|
||||
Path file = getFilePath(mapId, tileType, tile);
|
||||
|
||||
OutputStream os = AtomicFileHelper.createFilepartOutputStream(file);
|
||||
os = new BufferedOutputStream(os);
|
||||
os = compression.compress(os);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InputStream> readMapTile(String mapId, TileType tileType, Vector2i tile) throws IOException {
|
||||
Path file = getFilePath(mapId, tileType, tile);
|
||||
|
||||
if (!Files.exists(file)) return Optional.empty();
|
||||
|
||||
InputStream is = Files.newInputStream(file, StandardOpenOption.READ);
|
||||
is = new BufferedInputStream(is);
|
||||
|
||||
return Optional.of(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMapTile(String mapId, TileType tileType, Vector2i tile) throws IOException {
|
||||
Path file = getFilePath(mapId, tileType, tile);
|
||||
FileUtils.delete(file.toFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream writeMeta(String mapId, MetaType metaType) throws IOException {
|
||||
Path file = getFilePath(mapId).resolve(getFilename(metaType));
|
||||
|
||||
OutputStream os = AtomicFileHelper.createFilepartOutputStream(file);
|
||||
os = new BufferedOutputStream(os);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InputStream> readMeta(String mapId, MetaType metaType) throws IOException {
|
||||
Path file = getFilePath(mapId).resolve(getFilename(metaType));
|
||||
|
||||
if (!Files.exists(file)) return Optional.empty();
|
||||
|
||||
InputStream is = Files.newInputStream(file, StandardOpenOption.READ);
|
||||
is = new BufferedInputStream(is);
|
||||
|
||||
return Optional.of(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeMap(String mapId) throws IOException {
|
||||
FileUtils.delete(getFilePath(mapId).toFile());
|
||||
}
|
||||
|
||||
public Path getFilePath(String mapId, TileType tileType, Vector2i tile){
|
||||
String path = "x" + tile.getX() + "z" + tile.getY();
|
||||
char[] cs = path.toCharArray();
|
||||
List<String> folders = new ArrayList<>();
|
||||
StringBuilder folder = new StringBuilder();
|
||||
for (char c : cs){
|
||||
folder.append(c);
|
||||
if (c >= '0' && c <= '9'){
|
||||
folders.add(folder.toString());
|
||||
folder.delete(0, folder.length());
|
||||
}
|
||||
}
|
||||
String fileName = folders.remove(folders.size() - 1);
|
||||
|
||||
Path p = getFilePath(mapId).resolve(tileType.getTypeId());
|
||||
for (String s : folders){
|
||||
p = p.resolve(s);
|
||||
}
|
||||
|
||||
return p.resolve(fileName + ".json" + compression.getFileSuffix());
|
||||
}
|
||||
|
||||
public Path getFilePath(String mapId) {
|
||||
return root.resolve(mapId);
|
||||
}
|
||||
|
||||
private static String getFilename(MetaType metaType) {
|
||||
return metaTypeFileNames.getOrDefault(metaType, metaType.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package de.bluecolored.bluemap.core.storage;
|
||||
|
||||
public enum MetaType {
|
||||
|
||||
TEXTURES,
|
||||
SETTINGS,
|
||||
MARKERS,
|
||||
RENDER_STATE
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package de.bluecolored.bluemap.core.storage;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class Storage {
|
||||
|
||||
public abstract OutputStream writeMapTile(String mapId, TileType tileType, Vector2i tile) throws IOException;
|
||||
|
||||
public abstract Optional<InputStream> readMapTile(String mapId, TileType tileType, Vector2i tile) throws IOException;
|
||||
|
||||
public abstract void deleteMapTile(String mapId, TileType tileType, Vector2i tile) throws IOException;
|
||||
|
||||
public abstract OutputStream writeMeta(String mapId, MetaType metaType) throws IOException;
|
||||
|
||||
public abstract Optional<InputStream> readMeta(String mapId, MetaType metaType) throws IOException;
|
||||
|
||||
public abstract void purgeMap(String mapId) throws IOException;
|
||||
|
||||
public TileStorage tileStorage(final String mapId, final TileType tileType) {
|
||||
return new TileStorage(mapId, tileType);
|
||||
}
|
||||
|
||||
public class TileStorage {
|
||||
|
||||
private final String mapId;
|
||||
private final TileType tileType;
|
||||
|
||||
private TileStorage(String mapId, TileType tileType) {
|
||||
this.mapId = mapId;
|
||||
this.tileType = tileType;
|
||||
}
|
||||
|
||||
public OutputStream write(Vector2i tile) throws IOException {
|
||||
return Storage.this.writeMapTile(mapId, tileType, tile);
|
||||
}
|
||||
|
||||
public Optional<InputStream> read(Vector2i tile) throws IOException {
|
||||
return Storage.this.readMapTile(mapId, tileType, tile);
|
||||
}
|
||||
|
||||
public void delete(Vector2i tile) throws IOException {
|
||||
deleteMapTile(mapId, tileType, tile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package de.bluecolored.bluemap.core.storage;
|
||||
|
||||
public enum TileType {
|
||||
|
||||
HIRES ("hires"),
|
||||
LOWRES ("lowres");
|
||||
|
||||
private final String typeId;
|
||||
|
||||
TileType(String typeId) {
|
||||
this.typeId = typeId;
|
||||
}
|
||||
|
||||
public String getTypeId() {
|
||||
return typeId;
|
||||
}
|
||||
}
|
@ -31,8 +31,6 @@
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FileUtils {
|
||||
|
@ -47,6 +47,7 @@
|
||||
import org.spongepowered.api.config.ConfigDir;
|
||||
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.block.TickBlockEvent;
|
||||
import org.spongepowered.api.event.lifecycle.RefreshGameEvent;
|
||||
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
|
||||
import org.spongepowered.api.event.lifecycle.StartedEngineEvent;
|
||||
|
Loading…
Reference in New Issue
Block a user