WIP - Restructuring configs and world-map mapping

This commit is contained in:
Lukas Rieger (Blue) 2023-11-18 13:50:13 +01:00
parent 32311faccb
commit 9e599f611e
No known key found for this signature in database
GPG Key ID: 2D09EC5ED2687FF2
37 changed files with 321 additions and 531 deletions

View File

@ -33,6 +33,9 @@ dependencies {
api ("de.bluecolored.bluemap.core:BlueMapCore")
compileOnly ("org.jetbrains:annotations:16.0.2")
compileOnly ("org.projectlombok:lombok:1.18.28")
annotationProcessor ("org.projectlombok:lombok:1.18.28")
testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2")
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2")

View File

@ -29,7 +29,7 @@ import de.bluecolored.bluemap.common.config.storage.StorageConfig;
import java.util.Map;
public interface BlueMapConfigProvider {
public interface BlueMapConfiguration {
CoreConfig getCoreConfig();
WebappConfig getWebappConfig();

View File

@ -36,8 +36,6 @@ import de.bluecolored.bluemap.common.config.ConfigurationException;
import de.bluecolored.bluemap.common.config.MapConfig;
import de.bluecolored.bluemap.common.config.storage.StorageConfig;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.MinecraftVersion;
import de.bluecolored.bluemap.core.debug.StateDumper;
import de.bluecolored.bluemap.core.logger.Logger;
@ -48,6 +46,7 @@ import de.bluecolored.bluemap.core.util.FileHelper;
import de.bluecolored.bluemap.core.util.Key;
import de.bluecolored.bluemap.core.world.World;
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
import lombok.EqualsAndHashCode;
import org.apache.commons.io.FileUtils;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.ConfigurateException;
@ -61,7 +60,6 @@ import java.lang.reflect.Type;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
@ -72,85 +70,25 @@ import java.util.stream.Stream;
@DebugDump
public class BlueMapService implements Closeable {
private final ServerInterface serverInterface;
private final BlueMapConfigProvider configs;
private final BlueMapConfiguration config;
private final WebFilesManager webFilesManager;
private final Map<Path, String> worldIds;
private final Map<WorldKey, World> worlds;
private final Map<String, BmMap> maps;
private final Map<String, Storage> storages;
private volatile WebFilesManager webFilesManager;
public BlueMapService(BlueMapConfiguration configuration) {
this.config = configuration;
this.webFilesManager = new WebFilesManager(config.getWebappConfig().getWebroot());
private Map<String, World> worlds;
private Map<String, BmMap> maps;
private ResourcePack resourcePack;
public BlueMapService(ServerInterface serverInterface, BlueMapConfigProvider configProvider, @Nullable ResourcePack preloadedResourcePack) {
this(serverInterface, configProvider);
if (preloadedResourcePack != null)
this.resourcePack = preloadedResourcePack;
}
public BlueMapService(ServerInterface serverInterface, BlueMapConfigProvider configProvider) {
this.serverInterface = serverInterface;
this.configs = configProvider;
this.worldIds = new ConcurrentHashMap<>();
this.storages = new HashMap<>();
this.worlds = new ConcurrentHashMap<>();
this.maps = new ConcurrentHashMap<>();
this.storages = new ConcurrentHashMap<>();
StateDumper.global().register(this);
}
public String getWorldId(Path worldFolder) throws IOException {
// fast-path
String id = worldIds.get(worldFolder);
if (id != null) return id;
// second try with normalized absolute path
worldFolder = worldFolder.toAbsolutePath().normalize();
id = worldIds.get(worldFolder);
if (id != null) return id;
// secure (slower) query with real path
worldFolder = worldFolder.toRealPath();
id = worldIds.get(worldFolder);
if (id != null) return id;
synchronized (worldIds) {
// check again if another thread has already added the world
id = worldIds.get(worldFolder);
if (id != null) return id;
Logger.global.logDebug("Loading world id for '" + worldFolder + "'...");
// now we can be sure it wasn't loaded yet .. load
Path idFile = worldFolder.resolve("bluemap.id");
if (!Files.exists(idFile)) {
id = this.serverInterface.getWorld(worldFolder)
.flatMap(ServerWorld::getId)
.orElse(UUID.randomUUID().toString());
Files.writeString(idFile, id, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
worldIds.put(worldFolder, id);
return id;
}
id = Files.readString(idFile);
worldIds.put(worldFolder, id);
return id;
}
}
public WebFilesManager getWebFilesManager() {
if (webFilesManager == null) {
synchronized (this) {
if (webFilesManager == null)
webFilesManager = new WebFilesManager(configs.getWebappConfig().getWebroot());
}
}
return webFilesManager;
}
@ -164,13 +102,13 @@ public class BlueMapService implements Closeable {
}
// update settings.json
if (!configs.getWebappConfig().isUpdateSettingsFile()) {
if (!config.getWebappConfig().isUpdateSettingsFile()) {
webFilesManager.loadSettings();
webFilesManager.addFrom(configs.getWebappConfig());
webFilesManager.addFrom(config.getWebappConfig());
} else {
webFilesManager.setFrom(configs.getWebappConfig());
webFilesManager.setFrom(config.getWebappConfig());
}
for (String mapId : configs.getMapConfigs().keySet()) {
for (String mapId : config.getMapConfigs().keySet()) {
webFilesManager.addMap(mapId);
}
webFilesManager.saveSettings();
@ -180,21 +118,21 @@ public class BlueMapService implements Closeable {
}
}
public synchronized Map<String, World> getWorlds() throws InterruptedException {
if (worlds == null) loadWorldsAndMaps();
return worlds;
public @Nullable Collection<World> getWorlds() {
return worlds.values();
}
public synchronized Map<String, BmMap> getMaps() throws InterruptedException {
if (maps == null) loadWorldsAndMaps();
public @Nullable Map<String, BmMap> getMaps() {
return maps;
}
public Map<String, BmMap> loadMaps() throws InterruptedException {
loadWorldsAndMaps();
return maps;
}
private synchronized void loadWorldsAndMaps() throws InterruptedException {
maps = new HashMap<>();
worlds = new HashMap<>();
for (var entry : configs.getMapConfigs().entrySet()) {
for (var entry : config.getMapConfigs().entrySet()) {
try {
loadMapConfig(entry.getKey(), entry.getValue());
} catch (ConfigurationException ex) {
@ -205,9 +143,6 @@ public class BlueMapService implements Closeable {
}
}
}
worlds = Collections.unmodifiableMap(worlds);
maps = Collections.unmodifiableMap(maps);
}
private synchronized void loadMapConfig(String id, MapConfig mapConfig) throws ConfigurationException, InterruptedException {
@ -215,6 +150,7 @@ public class BlueMapService implements Closeable {
if (name == null) name = id;
Path worldFolder = mapConfig.getWorld();
Key dimension = mapConfig.getDimension();
// if there is no world configured, we assume the map is static, or supplied from a different server
if (worldFolder == null) {
@ -228,25 +164,16 @@ public class BlueMapService implements Closeable {
"Check if the 'world' setting in the config-file for that map is correct, or remove the entire config-file if you don't want that map.");
}
String worldId;
try {
worldId = getWorldId(worldFolder);
} catch (IOException ex) {
throw new ConfigurationException(
"Could not load the ID for the world (" + worldFolder.toAbsolutePath().normalize() + ")!\n" +
"Make sure BlueMap has read and write access/permissions to the world-files for this map.",
ex);
}
World world = worlds.get(worldId);
WorldKey worldKey = new WorldKey(worldFolder, dimension);
World world = worlds.get(worldKey);
if (world == null) {
try {
Logger.global.logInfo("Loading world '" + worldId + "' (" + worldFolder.toAbsolutePath().normalize() + ")...");
world = MCAWorld.load(worldFolder, new Key("overworld")); //TODO
worlds.put(worldId, world);
Logger.global.logInfo("Loading world " + worldKey + " ...");
world = MCAWorld.load(worldFolder, dimension);
worlds.put(worldKey, world);
} catch (IOException ex) {
throw new ConfigurationException(
"Failed to load world '" + worldId + "' (" + worldFolder.toAbsolutePath().normalize() + ")!\n" +
"Failed to load world " + worldKey + "!\n" +
"Is the level.dat of that world present and not corrupted?",
ex);
}
@ -260,10 +187,9 @@ public class BlueMapService implements Closeable {
BmMap map = new BmMap(
id,
name,
worldId,
world,
storage,
getResourcePack(),
loadResourcePack(),
mapConfig
);
maps.put(id, map);
@ -299,7 +225,7 @@ public class BlueMapService implements Closeable {
if (storage == null) {
try {
StorageConfig storageConfig = getConfigs().getStorageConfigs().get(storageId);
StorageConfig storageConfig = getConfig().getStorageConfigs().get(storageId);
if (storageConfig == null) {
throw new ConfigurationException("There is no storage-configuration for '" + storageId + "'!\n" +
"You will either need to define that storage, or change the map-config to use a storage-config that exists.");
@ -332,12 +258,12 @@ public class BlueMapService implements Closeable {
return storage;
}
public synchronized ResourcePack getResourcePack() throws ConfigurationException, InterruptedException {
public synchronized ResourcePack loadResourcePack() throws ConfigurationException, InterruptedException {
if (resourcePack == null) {
MinecraftVersion minecraftVersion = serverInterface.getMinecraftVersion();
Path defaultResourceFile = configs.getCoreConfig().getData().resolve("minecraft-client-" + minecraftVersion.getResource().getVersion().getVersionString() + ".jar");
Path resourceExtensionsFile = configs.getCoreConfig().getData().resolve("resourceExtensions.zip");
Path defaultResourceFile = config.getCoreConfig().getData().resolve("minecraft-client-" + minecraftVersion.getResource().getVersion().getVersionString() + ".jar");
Path resourceExtensionsFile = config.getCoreConfig().getData().resolve("resourceExtensions.zip");
Path resourcePackFolder = serverInterface.getConfigFolder().resolve("resourcepacks");
@ -352,7 +278,7 @@ public class BlueMapService implements Closeable {
}
if (!Files.exists(defaultResourceFile)) {
if (configs.getCoreConfig().isAcceptDownload()) {
if (config.getCoreConfig().isAcceptDownload()) {
//download file
try {
Logger.global.logInfo("Downloading " + minecraftVersion.getResource().getClientUrl() + " to " + defaultResourceFile + " ...");
@ -398,7 +324,7 @@ public class BlueMapService implements Closeable {
.forEach(resourcePackRoots::add);
}
if (configs.getCoreConfig().isScanForModResources()) {
if (config.getCoreConfig().isScanForModResources()) {
// load from mods folder
Path modsFolder = serverInterface.getModsFolder().orElse(null);
@ -443,7 +369,7 @@ public class BlueMapService implements Closeable {
private Collection<Path> getWorldFolders() {
Set<Path> folders = new HashSet<>();
for (MapConfig mapConfig : configs.getMapConfigs().values()) {
for (MapConfig mapConfig : config.getMapConfigs().values()) {
Path folder = mapConfig.getWorld();
if (folder == null) continue;
folder = folder.toAbsolutePath().normalize();
@ -454,8 +380,8 @@ public class BlueMapService implements Closeable {
return folders;
}
public BlueMapConfigProvider getConfigs() {
return configs;
public BlueMapConfiguration getConfig() {
return config;
}
@Override
@ -477,4 +403,21 @@ public class BlueMapService implements Closeable {
throw exception;
}
@EqualsAndHashCode
private static class WorldKey {
private final Path worldFolder;
private final Key dimension;
public WorldKey(Path worldFolder, Key dimension) {
this.worldFolder = worldFolder;
this.dimension = dimension;
}
@Override
public String toString() {
return worldFolder + "[" + dimension + "]";
}
}
}

View File

@ -34,6 +34,7 @@ import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.map.BmMap;
import de.bluecolored.bluemap.core.world.World;
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
import java.io.IOException;
import java.util.*;
@ -121,29 +122,22 @@ public class BlueMapAPIImpl extends BlueMapAPI {
if (coreWorld != null) world = coreWorld;
}
if (world instanceof World) {
var coreWorld = (World) world;
try {
return Optional.of(new BlueMapWorldImpl(plugin, coreWorld));
} catch (IOException e) {
Logger.global.logError("[API] Failed to create BlueMapWorld for world " + coreWorld.getSaveFolder(), e);
}
return Optional.empty();
if (world instanceof MCAWorld) {
var coreWorld = (MCAWorld) world;
return Optional.of(new BlueMapWorldImpl(plugin, coreWorld));
}
var serverWorld = plugin.getServerInterface().getWorld(world).orElse(null);
if (serverWorld == null) return Optional.empty();
try {
String id = plugin.getBlueMap().getWorldId(serverWorld.getSaveFolder());
var coreWorld = worlds.get(id);
if (coreWorld == null) return Optional.empty();
String id = plugin.getBlueMap().getWorldId(serverWorld.getSaveFolder());
World coreWorld = worlds.get(id);
if (coreWorld == null) return Optional.empty();
return Optional.of(new BlueMapWorldImpl(plugin, coreWorld));
} catch (IOException e) {
Logger.global.logError("[API] Failed to create BlueMapWorld for world " + serverWorld.getSaveFolder(), e);
return Optional.empty();
}
if (coreWorld instanceof MCAWorld)
return Optional.of(new BlueMapWorldImpl(plugin, (MCAWorld) coreWorld));
return Optional.empty();
}

View File

@ -28,6 +28,7 @@ import de.bluecolored.bluemap.api.BlueMapMap;
import de.bluecolored.bluemap.api.BlueMapWorld;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.core.world.World;
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
import java.io.IOException;
import java.lang.ref.WeakReference;
@ -40,11 +41,11 @@ public class BlueMapWorldImpl implements BlueMapWorld {
private final WeakReference<Plugin> plugin;
private final String id;
private final WeakReference<World> world;
private final WeakReference<MCAWorld> world;
public BlueMapWorldImpl(Plugin plugin, World world) throws IOException {
public BlueMapWorldImpl(Plugin plugin, MCAWorld world) throws IOException {
this.plugin = new WeakReference<>(plugin);
this.id = plugin.getBlueMap().getWorldId(world.getSaveFolder());
this.id = plugin.getBlueMap().getWorldId(world.getDimensionFolder());
this.world = new WeakReference<>(world);
}
@ -59,7 +60,7 @@ public class BlueMapWorldImpl implements BlueMapWorld {
@Override
public Path getSaveFolder() {
return unpack(world).getSaveFolder();
return unpack(world).getDimensionFolder();
}
@Override

View File

@ -25,27 +25,28 @@
package de.bluecolored.bluemap.common.config;
import de.bluecolored.bluemap.api.debug.DebugDump;
import de.bluecolored.bluemap.common.BlueMapConfigProvider;
import de.bluecolored.bluemap.common.BlueMapConfiguration;
import de.bluecolored.bluemap.common.config.storage.StorageConfig;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.util.FileHelper;
import de.bluecolored.bluemap.core.util.Tristate;
import de.bluecolored.bluemap.core.util.Key;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.*;
import java.util.stream.Stream;
@DebugDump
public class BlueMapConfigs implements BlueMapConfigProvider {
@Getter
public class BlueMapConfigManager implements BlueMapConfiguration {
private final ServerInterface serverInterface;
private final ConfigManager configManager;
private final CoreConfig coreConfig;
@ -55,84 +56,49 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
private final Map<String, MapConfig> mapConfigs;
private final Map<String, StorageConfig> storageConfigs;
public BlueMapConfigs(ServerInterface serverInterface) throws ConfigurationException {
this(serverInterface, Path.of("bluemap"), Path.of("bluemap", "web"), true);
}
@Builder(buildMethodName = "")
private BlueMapConfigManager(
@NonNull Path configRoot,
@Nullable Path defaultDataFolder,
@Nullable Path defaultWebroot,
@Nullable Collection<ServerWorld> autoConfigWorlds,
@Nullable Boolean usePluginConfig,
@Nullable Boolean useMetricsConfig
) throws ConfigurationException {
// set defaults
if (defaultDataFolder == null) defaultDataFolder = Path.of("bluemap");
if (defaultWebroot == null) defaultWebroot = Path.of("bluemap", "web");
if (autoConfigWorlds == null) autoConfigWorlds = Collections.emptyList();
if (usePluginConfig == null) usePluginConfig = true;
if (useMetricsConfig == null) useMetricsConfig = true;
public BlueMapConfigs(ServerInterface serverInterface, Path defaultDataFolder, Path defaultWebroot, boolean usePluginConf) throws ConfigurationException {
this.serverInterface = serverInterface;
this.configManager = new ConfigManager(serverInterface.getConfigFolder());
this.coreConfig = loadCoreConfig(defaultDataFolder);
// load
this.configManager = new ConfigManager(configRoot);
this.coreConfig = loadCoreConfig(defaultDataFolder, useMetricsConfig);
this.webappConfig = loadWebappConfig(defaultWebroot);
this.webserverConfig = loadWebserverConfig(webappConfig.getWebroot(), coreConfig.getData());
this.pluginConfig = usePluginConf ? loadPluginConfig() : new PluginConfig();
this.pluginConfig = usePluginConfig ? loadPluginConfig() : new PluginConfig();
this.storageConfigs = Collections.unmodifiableMap(loadStorageConfigs(webappConfig.getWebroot()));
this.mapConfigs = Collections.unmodifiableMap(loadMapConfigs());
this.mapConfigs = Collections.unmodifiableMap(loadMapConfigs(autoConfigWorlds));
}
public ConfigManager getConfigManager() {
return configManager;
}
@Override
public CoreConfig getCoreConfig() {
return coreConfig;
}
@Override
public WebappConfig getWebappConfig() {
return webappConfig;
}
@Override
public WebserverConfig getWebserverConfig() {
return webserverConfig;
}
@Override
public PluginConfig getPluginConfig() {
return pluginConfig;
}
@Override
public Map<String, MapConfig> getMapConfigs() {
return mapConfigs;
}
@Override
public Map<String, StorageConfig> getStorageConfigs() {
return storageConfigs;
}
private synchronized CoreConfig loadCoreConfig(Path defaultDataFolder) throws ConfigurationException {
private synchronized CoreConfig loadCoreConfig(Path defaultDataFolder, boolean useMetricsConfig) throws ConfigurationException {
Path configFileRaw = Path.of("core");
Path configFile = configManager.findConfigPath(configFileRaw);
Path configFolder = configFile.getParent();
if (!Files.exists(configFile)) {
// determine render-thread preset (very pessimistic, rather let people increase it themselves)
Runtime runtime = Runtime.getRuntime();
int availableCores = runtime.availableProcessors();
long availableMemoryMiB = runtime.maxMemory() / 1024L / 1024L;
int presetRenderThreadCount = 1;
if (availableCores >= 6 && availableMemoryMiB >= 4096)
presetRenderThreadCount = 2;
if (availableCores >= 10 && availableMemoryMiB >= 8192)
presetRenderThreadCount = 3;
try {
FileHelper.createDirectories(configFolder);
Files.writeString(
configFolder.resolve("core.conf"),
configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/core.conf")
.setConditional("metrics", serverInterface.isMetricsEnabled() == Tristate.UNDEFINED)
.setConditional("metrics", useMetricsConfig)
.setVariable("timestamp", LocalDateTime.now().withNano(0).toString())
.setVariable("version", BlueMap.VERSION)
.setVariable("data", formatPath(defaultDataFolder))
.setVariable("implementation", "bukkit")
.setVariable("render-thread-count", Integer.toString(presetRenderThreadCount))
.setVariable("render-thread-count", Integer.toString(suggestRenderThreadCount()))
.setVariable("logfile", formatPath(defaultDataFolder.resolve("logs").resolve("debug.log")))
.setVariable("logfile-with-time", formatPath(defaultDataFolder.resolve("logs").resolve("debug_%1$tF_%1$tT.log")))
.build(),
@ -146,6 +112,21 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
return configManager.loadConfig(configFileRaw, CoreConfig.class);
}
/**
* determine render-thread preset (very pessimistic, rather let people increase it themselves)
*/
private int suggestRenderThreadCount() {
Runtime runtime = Runtime.getRuntime();
int availableCores = runtime.availableProcessors();
long availableMemoryMiB = runtime.maxMemory() / 1024L / 1024L;
int presetRenderThreadCount = 1;
if (availableCores >= 6 && availableMemoryMiB >= 4096)
presetRenderThreadCount = 2;
if (availableCores >= 10 && availableMemoryMiB >= 8192)
presetRenderThreadCount = 3;
return presetRenderThreadCount;
}
private synchronized WebserverConfig loadWebserverConfig(Path defaultWebroot, Path dataRoot) throws ConfigurationException {
Path configFileRaw = Path.of("webserver");
Path configFile = configManager.findConfigPath(configFileRaw);
@ -216,7 +197,7 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
return configManager.loadConfig(configFileRaw, PluginConfig.class);
}
private synchronized Map<String, MapConfig> loadMapConfigs() throws ConfigurationException {
private synchronized Map<String, MapConfig> loadMapConfigs(Collection<ServerWorld> autoConfigWorlds) throws ConfigurationException {
Map<String, MapConfig> mapConfigs = new HashMap<>();
Path mapFolder = Paths.get("maps");
@ -225,41 +206,54 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
if (!Files.exists(mapConfigFolder)){
try {
FileHelper.createDirectories(mapConfigFolder);
var worlds = serverInterface.getLoadedWorlds();
if (worlds.isEmpty()) {
if (autoConfigWorlds.isEmpty()) {
Files.writeString(
mapConfigFolder.resolve("overworld.conf"),
createOverworldMapTemplate("Overworld", Path.of("world"), 0).build(),
createOverworldMapTemplate("Overworld", Path.of("world"),
new Key("minecraft", "overworld"), 0).build(),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
);
Files.writeString(
mapConfigFolder.resolve("nether.conf"),
createNetherMapTemplate("Nether", Path.of("world", "DIM-1"), 0).build(),
createNetherMapTemplate("Nether", Path.of("world", "DIM-1"),
new Key("minecraft", "overworld"), 0).build(),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
);
Files.writeString(
mapConfigFolder.resolve("end.conf"),
createEndMapTemplate("End", Path.of("world", "DIM1"), 0).build(),
createEndMapTemplate("End", Path.of("world", "DIM1"),
new Key("minecraft", "overworld"), 0).build(),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
);
} else {
for (var world : worlds) {
String name = world.getName().orElse(world.getDimension().getName());
Path worldFolder = world.getSaveFolder();
for (var world : autoConfigWorlds) {
Path worldFolder = world.getWorldFolder();
Key dimension = world.getDimension();
Path configFile = mapConfigFolder.resolve(sanitiseMapId(name.toLowerCase(Locale.ROOT)) + ".conf");
String dimensionName = dimension.getNamespace().equals("minecraft") ?
dimension.getValue() : dimension.getFormatted();
String id = sanitiseMapId(worldFolder.getFileName() + "_" + dimensionName).toLowerCase(Locale.ROOT);
Path configFile = mapConfigFolder.resolve(id + ".conf");
int i = 1;
while (Files.exists(configFile)) {
configFile = mapConfigFolder.resolve(sanitiseMapId(name.toLowerCase(Locale.ROOT)) + '_' + (++i) + ".conf");
configFile = mapConfigFolder.resolve(id + '_' + (++i) + ".conf");
}
if (i > 1) name = name + " " + i;
String name = worldFolder.getFileName() + " - " + dimensionName;
if (i > 1) name = name + " (" + i + ")";
ConfigTemplate template;
switch (world.getDimension()) {
case NETHER: template = createNetherMapTemplate(name, worldFolder, i - 1); break;
case END: template = createEndMapTemplate(name, worldFolder, i - 1); break;
default: template = createOverworldMapTemplate(name, worldFolder, i - 1); break;
switch (world.getDimension().getFormatted()) {
case "minecraft:the_nether":
template = createNetherMapTemplate(name, worldFolder, dimension, i - 1);
break;
case "minecraft:the_end":
template = createEndMapTemplate(name, worldFolder, dimension, i - 1);
break;
default:
template = createOverworldMapTemplate(name, worldFolder, dimension, i - 1);
break;
}
Files.writeString(
@ -357,43 +351,43 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
return id.replaceAll("\\W", "_");
}
private ConfigTemplate createOverworldMapTemplate(String name, Path worldFolder, int index) throws IOException {
private ConfigTemplate createOverworldMapTemplate(String name, Path worldFolder, Key dimension, int index) throws IOException {
return configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/maps/map.conf")
.setVariable("name", name)
.setVariable("sorting", "" + index)
.setVariable("world", formatPath(worldFolder))
.setVariable("dimension", dimension.getFormatted())
.setVariable("sky-color", "#7dabff")
.setVariable("void-color", "#000000")
.setVariable("ambient-light", "0.1")
.setVariable("world-sky-light", "15")
.setVariable("remove-caves-below-y", "55")
.setConditional("max-y-comment", true)
.setVariable("max-y", "100");
}
private ConfigTemplate createNetherMapTemplate(String name, Path worldFolder, int index) throws IOException {
private ConfigTemplate createNetherMapTemplate(String name, Path worldFolder, Key dimension, int index) throws IOException {
return configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/maps/map.conf")
.setVariable("name", name)
.setVariable("sorting", "" + (100 + index))
.setVariable("world", formatPath(worldFolder))
.setVariable("dimension", dimension.getFormatted())
.setVariable("sky-color", "#290000")
.setVariable("void-color", "#000000")
.setVariable("ambient-light", "0.6")
.setVariable("world-sky-light", "0")
.setVariable("remove-caves-below-y", "-10000")
.setConditional("max-y-comment", false)
.setVariable("max-y", "90");
}
private ConfigTemplate createEndMapTemplate(String name, Path worldFolder, int index) throws IOException {
private ConfigTemplate createEndMapTemplate(String name, Path worldFolder, Key dimension, int index) throws IOException {
return configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/maps/map.conf")
.setVariable("name", name)
.setVariable("sorting", "" + (200 + index))
.setVariable("world", formatPath(worldFolder))
.setVariable("dimension", dimension.getFormatted())
.setVariable("sky-color", "#080010")
.setVariable("void-color", "#000000")
.setVariable("ambient-light", "0.6")
.setVariable("world-sky-light", "0")
.setVariable("remove-caves-below-y", "-10000")
.setConditional("max-y-comment", true)
.setVariable("max-y", "100");

View File

@ -28,43 +28,45 @@ import com.flowpowered.math.vector.Vector2i;
import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.api.debug.DebugDump;
import de.bluecolored.bluemap.core.map.MapSettings;
import de.bluecolored.bluemap.core.util.Key;
import lombok.AccessLevel;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import java.nio.file.Path;
import java.util.Optional;
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
@DebugDump
@ConfigSerializable
@Getter
public class MapConfig implements MapSettings {
private String name = null;
@Nullable private Path world = null;
@Nullable private Key dimension = null;
private Path world = null;
@Nullable private String name = null;
private int sorting = 0;
private Vector2i startPos = null;
@Nullable private Vector2i startPos = null;
private String skyColor = "#7dabff";
private String voidColor = "#000000";
private float ambientLight = 0;
private int worldSkyLight = 15;
private int removeCavesBelowY = 55;
private int caveDetectionOceanFloor = 10000;
private boolean caveDetectionUsesBlockLight = false;
private int minX = Integer.MIN_VALUE;
private int maxX = Integer.MAX_VALUE;
private int minZ = Integer.MIN_VALUE;
private int maxZ = Integer.MAX_VALUE;
private int minY = Integer.MIN_VALUE;
private int maxY = Integer.MAX_VALUE;
@Getter(AccessLevel.NONE) private int minX = Integer.MIN_VALUE;
@Getter(AccessLevel.NONE) private int maxX = Integer.MAX_VALUE;
@Getter(AccessLevel.NONE) private int minZ = Integer.MIN_VALUE;
@Getter(AccessLevel.NONE) private int maxZ = Integer.MAX_VALUE;
@Getter(AccessLevel.NONE) private int minY = Integer.MIN_VALUE;
@Getter(AccessLevel.NONE) private int maxY = Integer.MAX_VALUE;
private transient Vector3i min = null;
private transient Vector3i max = null;
@ -80,7 +82,7 @@ public class MapConfig implements MapSettings {
private boolean ignoreMissingLightData = false;
private ConfigurationNode markerSets = null;
@Nullable private ConfigurationNode markerSets = null;
// hidden config fields
private int hiresTileSize = 32;
@ -88,61 +90,6 @@ public class MapConfig implements MapSettings {
private int lodCount = 3;
private int lodFactor = 5;
@Nullable
public String getName() {
return name;
}
@Nullable
public Path getWorld() {
return world;
}
@Override
public int getSorting() {
return sorting;
}
@Override
public Optional<Vector2i> getStartPos() {
return Optional.ofNullable(startPos);
}
@Override
public String getSkyColor() {
return skyColor;
}
@Override
public String getVoidColor() {
return voidColor;
}
@Override
public float getAmbientLight() {
return ambientLight;
}
@Override
public int getWorldSkyLight() {
return worldSkyLight;
}
@Override
public int getRemoveCavesBelowY() {
return removeCavesBelowY;
}
@Override
public boolean isCaveDetectionUsesBlockLight() {
return caveDetectionUsesBlockLight;
}
@Override
public int getCaveDetectionOceanFloor() {
return caveDetectionOceanFloor;
}
public Vector3i getMinPos() {
if (min == null) min = new Vector3i(minX, minY, minZ);
return min;
@ -153,57 +100,4 @@ public class MapConfig implements MapSettings {
return max;
}
@Override
public long getMinInhabitedTime() {
return minInhabitedTime;
}
@Override
public int getMinInhabitedTimeRadius() {
return minInhabitedTimeRadius;
}
@Override
public boolean isRenderEdges() {
return renderEdges;
}
@Override
public boolean isSaveHiresLayer() {
return saveHiresLayer;
}
public String getStorage() {
return storage;
}
public boolean isIgnoreMissingLightData() {
return ignoreMissingLightData;
}
@Nullable
public ConfigurationNode getMarkerSets() {
return markerSets;
}
@Override
public int getHiresTileSize() {
return hiresTileSize;
}
@Override
public int getLowresTileSize() {
return lowresTileSize;
}
@Override
public int getLodCount() {
return lodCount;
}
@Override
public int getLodFactor() {
return lodFactor;
}
}

View File

@ -27,9 +27,9 @@ package de.bluecolored.bluemap.common.live;
import com.google.gson.stream.JsonWriter;
import de.bluecolored.bluemap.common.config.PluginConfig;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.logger.Logger;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.StringWriter;
@ -39,15 +39,15 @@ import java.util.function.Supplier;
public class LivePlayersDataSupplier implements Supplier<String> {
private final ServerInterface server;
private final Server server;
private final PluginConfig config;
@Nullable private final String worldId;
private final ServerWorld world;
private final Predicate<UUID> playerFilter;
public LivePlayersDataSupplier(ServerInterface server, PluginConfig config, @Nullable String worldId, Predicate<UUID> playerFilter) {
public LivePlayersDataSupplier(Server server, PluginConfig config, ServerWorld world, Predicate<UUID> playerFilter) {
this.server = server;
this.config = config;
this.worldId = worldId;
this.world = world;
this.playerFilter = playerFilter;
}
@ -61,9 +61,7 @@ public class LivePlayersDataSupplier implements Supplier<String> {
if (config.isLivePlayerMarkers()) {
for (Player player : this.server.getOnlinePlayers()) {
if (!player.isOnline()) continue;
boolean isCorrectWorld = player.getWorld().equals(this.worldId);
boolean isCorrectWorld = player.getWorld().equals(this.world);
if (config.isHideInvisible() && player.isInvisible()) continue;
if (config.isHideVanished() && player.isVanished()) continue;

View File

@ -25,7 +25,7 @@
package de.bluecolored.bluemap.common.plugin;
import de.bluecolored.bluemap.api.debug.DebugDump;
import de.bluecolored.bluemap.common.BlueMapConfigProvider;
import de.bluecolored.bluemap.common.BlueMapConfiguration;
import de.bluecolored.bluemap.common.BlueMapService;
import de.bluecolored.bluemap.common.InterruptableReentrantLock;
import de.bluecolored.bluemap.common.MissingResourcesException;
@ -36,7 +36,7 @@ import de.bluecolored.bluemap.common.plugin.skins.PlayerSkinUpdater;
import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask;
import de.bluecolored.bluemap.common.rendermanager.RenderManager;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.web.*;
import de.bluecolored.bluemap.common.web.http.HttpServer;
import de.bluecolored.bluemap.core.debug.StateDumper;
@ -78,15 +78,12 @@ public class Plugin implements ServerEventListener {
private final InterruptableReentrantLock loadingLock = new InterruptableReentrantLock();
private final String implementationType;
private final ServerInterface serverInterface;
private final Server serverInterface;
private BlueMapService blueMap;
private PluginState pluginState;
private Map<String, World> worlds;
private Map<String, BmMap> maps;
private RenderManager renderManager;
private HttpServer webServer;
private Logger webLogger;
@ -101,7 +98,7 @@ public class Plugin implements ServerEventListener {
private boolean loaded = false;
public Plugin(String implementationType, ServerInterface serverInterface) {
public Plugin(String implementationType, Server serverInterface) {
this.implementationType = implementationType.toLowerCase();
this.serverInterface = serverInterface;
@ -121,7 +118,7 @@ public class Plugin implements ServerEventListener {
unload(); //ensure nothing is left running (from a failed load or something)
//load configs
blueMap = new BlueMapService(serverInterface, new BlueMapConfigs(serverInterface), preloadedResourcePack);
blueMap = new BlueMapService(serverInterface, new BlueMapConfigManager(serverInterface), preloadedResourcePack);
CoreConfig coreConfig = getConfigs().getCoreConfig();
WebserverConfig webserverConfig = getConfigs().getWebserverConfig();
WebappConfig webappConfig = getConfigs().getWebappConfig();
@ -151,14 +148,14 @@ public class Plugin implements ServerEventListener {
//try load resources
try {
blueMap.getResourcePack();
blueMap.loadResourcePack();
} catch (MissingResourcesException ex) {
Logger.global.logWarning("BlueMap is missing important resources!");
Logger.global.logWarning("You must accept the required file download in order for BlueMap to work!");
BlueMapConfigProvider configProvider = blueMap.getConfigs();
if (configProvider instanceof BlueMapConfigs) {
Logger.global.logWarning("Please check: " + ((BlueMapConfigs) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize());
BlueMapConfiguration configProvider = blueMap.getConfig();
if (configProvider instanceof BlueMapConfigManager) {
Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize());
}
Logger.global.logInfo("If you have changed the config you can simply reload the plugin using: /bluemap reload");
@ -167,9 +164,8 @@ public class Plugin implements ServerEventListener {
return;
}
//load worlds and maps
worlds = blueMap.getWorlds();
maps = blueMap.getMaps();
//load maps
Map<String, BmMap> maps = blueMap.loadMaps();
//create and start webserver
if (webserverConfig.isEnabled()) {
@ -447,9 +443,6 @@ public class Plugin implements ServerEventListener {
Logger.global.remove(DEBUG_FILE_LOG_NAME);
//clear resources
worlds = null;
maps = null;
pluginState = null;
//done
@ -494,7 +487,7 @@ public class Plugin implements ServerEventListener {
if (pluginState != null) {
try {
GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
.path(blueMap.getConfigs().getCoreConfig().getData().resolve("pluginState.json"))
.path(blueMap.getConfig().getCoreConfig().getData().resolve("pluginState.json"))
.build();
loader.save(loader.createNode().set(PluginState.class, pluginState));
} catch (IOException ex) {
@ -502,6 +495,7 @@ public class Plugin implements ServerEventListener {
}
}
var maps = blueMap.getMaps();
if (maps != null) {
for (BmMap map : maps.values()) {
map.save();
@ -510,6 +504,7 @@ public class Plugin implements ServerEventListener {
}
public void saveMarkerStates() {
var maps = blueMap.getMaps();
if (maps != null) {
for (BmMap map : maps.values()) {
map.saveMarkerState();
@ -518,6 +513,7 @@ public class Plugin implements ServerEventListener {
}
public void savePlayerStates() {
var maps = blueMap.getMaps();
if (maps != null) {
for (BmMap map : maps.values()) {
var dataSupplier = new LivePlayersDataSupplier(
@ -604,7 +600,7 @@ public class Plugin implements ServerEventListener {
}
}
public ServerInterface getServerInterface() {
public Server getServerInterface() {
return serverInterface;
}
@ -612,22 +608,14 @@ public class Plugin implements ServerEventListener {
return blueMap;
}
public BlueMapConfigProvider getConfigs() {
return blueMap.getConfigs();
public BlueMapConfigManager getConfigs() {
return blueMap.getConfig();
}
public PluginState getPluginState() {
return pluginState;
}
public Map<String, World> getWorlds(){
return worlds;
}
public Map<String, BmMap> getMaps(){
return maps;
}
public RenderManager getRenderManager() {
return renderManager;
}
@ -649,9 +637,12 @@ public class Plugin implements ServerEventListener {
}
private void initFileWatcherTasks() {
for (BmMap map : maps.values()) {
if (pluginState.getMapState(map).isUpdateEnabled()) {
startWatchingMap(map);
var maps = blueMap.getMaps();
if (maps != null) {
for (BmMap map : maps.values()) {
if (pluginState.getMapState(map).isUpdateEnabled()) {
startWatchingMap(map);
}
}
}
}

View File

@ -868,7 +868,7 @@ public class Commands<S> {
CommandSource source = commandSourceInterface.apply(context.getSource());
source.sendMessage(Text.of(TextColor.BLUE, "Storages loaded by BlueMap:"));
for (var entry : plugin.getBlueMap().getConfigs().getStorageConfigs().entrySet()) {
for (var entry : plugin.getBlueMap().getConfig().getStorageConfigs().entrySet()) {
source.sendMessage(Text.of(TextColor.GRAY, " - ", TextColor.WHITE, entry.getKey())
.setHoverText(Text.of(entry.getValue().getStorageType().name()))
.setClickAction(Text.ClickAction.RUN_COMMAND, "/bluemap storages " + entry.getKey())

View File

@ -38,7 +38,7 @@ public class StorageSuggestionProvider<S> extends AbstractSuggestionProvider<S>
@Override
public Collection<String> getPossibleValues() {
return plugin.getBlueMap().getConfigs().getStorageConfigs().keySet();
return plugin.getBlueMap().getConfig().getStorageConfigs().keySet();
}
}

View File

@ -83,7 +83,7 @@ public class WorldRegionRenderTask implements RenderTask {
if (timestamp >= changesSince) chunks.add(new Vector2i(x, z));
});
} catch (IOException ex) {
Logger.global.logWarning("Failed to read region " + worldRegion + " from world " + map.getWorld().getWorldFolder() + " (" + ex + ")");
Logger.global.logWarning("Failed to read region " + worldRegion + " from world " + map.getWorld().getName() + " (" + ex + ")");
}
Grid tileGrid = map.getHiresModelManager().getTileGrid();

View File

@ -35,7 +35,7 @@ public interface Player {
Text getName();
String getWorld();
ServerWorld getWorld();
Vector3d getPosition();
@ -48,8 +48,6 @@ public interface Player {
int getBlockLight();
boolean isOnline();
/**
* Return <code>true</code> if the player is sneaking.
* <p><i>If the player is offline the value of this method is undetermined.</i></p>

View File

@ -24,44 +24,20 @@
*/
package de.bluecolored.bluemap.common.serverinterface;
import de.bluecolored.bluemap.core.MinecraftVersion;
import de.bluecolored.bluemap.api.debug.DebugDump;
import de.bluecolored.bluemap.core.MinecraftVersion;
import de.bluecolored.bluemap.core.util.Tristate;
import de.bluecolored.bluemap.core.world.World;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
public interface ServerInterface {
public interface Server {
@DebugDump
MinecraftVersion getMinecraftVersion();
/**
* Registers a ServerEventListener, every method of this interface should be called on the specified events
*/
void registerListener(ServerEventListener listener);
/**
* Removes all registered listeners
*/
void unregisterAllListeners();
default Optional<ServerWorld> getWorld(Path worldFolder) {
Path normalizedWorldFolder = worldFolder.toAbsolutePath().normalize();
return getLoadedWorlds().stream()
.filter(world -> world.getSaveFolder().toAbsolutePath().normalize().equals(normalizedWorldFolder))
.findAny();
}
default Optional<ServerWorld> getWorld(Object world) {
return Optional.empty();
}
@DebugDump
Collection<ServerWorld> getLoadedWorlds();
/**
* Returns the Folder containing the configurations for the plugin
*/
@ -82,6 +58,28 @@ public interface ServerInterface {
return Tristate.UNDEFINED;
}
/**
* Returns the correct {@link ServerWorld} for a {@link World} if there is any.
*/
Optional<ServerWorld> getWorld(World world);
/**
* Returns the correct {@link ServerWorld} for any Object if there is any, this should return the correct ServerWorld
* for any implementation-specific object that represent or identify a world in any way.<br>
* Used for the API implementation.
*/
default Optional<ServerWorld> getWorld(Object world) {
if (world instanceof World)
return getWorld((World) world);
return Optional.empty();
}
/**
* Returns all loaded worlds of this server.
*/
@DebugDump
Collection<ServerWorld> getLoadedWorlds();
/**
* Returns a collection of the states of players that are currently online
*/
@ -89,9 +87,13 @@ public interface ServerInterface {
Collection<Player> getOnlinePlayers();
/**
* Returns the state of the player with that UUID if present<br>
* this method is only guaranteed to return a {@link Player} if the player is currently online.
* Registers a ServerEventListener, every method of this interface should be called on the specified events
*/
Optional<Player> getPlayer(UUID uuid);
void registerListener(ServerEventListener listener);
/**
* Removes all registered listeners
*/
void unregisterAllListeners();
}

View File

@ -24,41 +24,21 @@
*/
package de.bluecolored.bluemap.common.serverinterface;
import de.bluecolored.bluemap.api.debug.DebugDump;
import de.bluecolored.bluemap.core.util.Key;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
public interface ServerWorld {
@DebugDump
default Optional<String> getId() {
return Optional.empty();
}
Path getWorldFolder();
@DebugDump
default Optional<String> getName() {
return Optional.empty();
}
@DebugDump
Path getSaveFolder();
@DebugDump
default Dimension getDimension() {
Path saveFolder = getSaveFolder();
String lastName = saveFolder.getFileName().toString();
if (lastName.equals("DIM-1")) return Dimension.NETHER;
if (lastName.equals("DIM1")) return Dimension.END;
return Dimension.OVERWORLD;
}
Key getDimension();
/**
* Attempts to persist all changes that have been made in a world to disk.
*
* @return <code>true</code> if the changes have been successfully persisted, <code>false</code> if this operation is not supported by the implementation
*
* @throws IOException if something went wrong trying to persist the changes
*/
default boolean persistWorldChanges() throws IOException {

View File

@ -27,7 +27,7 @@ package de.bluecolored.bluemap.common.web;
import de.bluecolored.bluemap.common.config.PluginConfig;
import de.bluecolored.bluemap.common.live.LiveMarkersDataSupplier;
import de.bluecolored.bluemap.common.live.LivePlayersDataSupplier;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.core.map.BmMap;
import de.bluecolored.bluemap.core.storage.Storage;
import org.jetbrains.annotations.Nullable;
@ -38,7 +38,7 @@ import java.util.function.Supplier;
public class MapRequestHandler extends RoutingRequestHandler {
public MapRequestHandler(BmMap map, ServerInterface serverInterface, PluginConfig pluginConfig, Predicate<UUID> playerFilter) {
public MapRequestHandler(BmMap map, Server serverInterface, PluginConfig pluginConfig, Predicate<UUID> playerFilter) {
this(map.getId(), map.getStorage(),
new LivePlayersDataSupplier(serverInterface, pluginConfig, map.getWorldId(), playerFilter),
new LiveMarkersDataSupplier(map.getMarkerSets()));

View File

@ -3,16 +3,20 @@
## Map-Config ##
## ##
# The name of this map
# This defines the display name of this map, you can change this at any time.
# Default is the id of this map
name: "${name}"
# The path to the save-folder of the world to render.
# (If this is not defined (commented out or removed), the map will be only registered to the web-server and the web-app
# but not rendered or loaded by BlueMap. This can be used to display a map that has been rendered somewhere else.)
world: "${world}"
# The dimension of the world. Can be "minecraft:overworld", "minecraft:the_nether", "minecraft:the_end"
# or any dimension-key introduced by a mod or datapack.
dimension: "${dimension}"
# The display-name of this map -> how this map will be named on the webapp.
# You can change this at any time.
# Default is the id of this map
name: "${name}"
# A lower value makes the map sorted first (in lists and menus), a higher value makes it sorted later.
# The value needs to be an integer but it can be negative.
# You can change this at any time.
@ -40,14 +44,6 @@ void-color: "${void-color}"
# Default is 0
ambient-light: ${ambient-light}
# Defines the skylight level that the sky of the world is emitting.
# This should always be equivalent to the maximum in-game sky-light for that world!
# If this is a normal overworld dimension, set this to 15 (max).
# If this is a normal nether or end dimension, set this to 0 (min).
# Changing this value requires a re-render of the map.
# Default is 15
world-sky-light: ${world-sky-light}
# BlueMap tries to omit all blocks that are below this Y-level and are not visible from above-ground.
# More specific: Block-Faces that have a sunlight/skylight value of 0 are removed.
# This improves the performance of the map on slower devices by a lot, but might cause some blocks to disappear that should normally be visible.

View File

@ -64,7 +64,6 @@ public class BmMap {
private final String id;
private final String name;
private final String worldId;
private final World world;
private final Storage storage;
private final MapSettings mapSettings;
@ -83,10 +82,9 @@ public class BmMap {
private long renderTimeSumNanos;
private long tilesRendered;
public BmMap(String id, String name, String worldId, World world, Storage storage, 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.worldId = Objects.requireNonNull(worldId);
this.world = Objects.requireNonNull(world);
this.storage = Objects.requireNonNull(storage);
this.resourcePack = Objects.requireNonNull(resourcePack);
@ -239,10 +237,6 @@ public class BmMap {
return name;
}
public String getWorldId() {
return worldId;
}
public World getWorld() {
return world;
}

View File

@ -26,14 +26,13 @@ package de.bluecolored.bluemap.core.map;
import com.flowpowered.math.vector.Vector2i;
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
public interface MapSettings extends RenderSettings {
int getSorting();
Optional<Vector2i> getStartPos();
@Nullable Vector2i getStartPos();
String getSkyColor();

View File

@ -33,6 +33,7 @@ import de.bluecolored.bluemap.core.map.lowres.LowresTileManager;
import de.bluecolored.bluemap.core.util.math.Color;
import java.lang.reflect.Type;
import java.util.Optional;
public class MapSettingsSerializer implements JsonSerializer<BmMap> {
@ -66,7 +67,7 @@ public class MapSettingsSerializer implements JsonSerializer<BmMap> {
root.add("lowres", lowres);
// startPos
Vector2i startPos = map.getMapSettings().getStartPos()
Vector2i startPos = Optional.ofNullable(map.getMapSettings().getStartPos())
.orElse(map.getWorld().getSpawnPoint().toVector2(true));
root.add("startPos", context.serialize(startPos));

View File

@ -65,11 +65,6 @@ public interface RenderSettings {
*/
float getAmbientLight();
/**
* The sky-light level of this world (0-15)
*/
int getWorldSkyLight();
/**
* The same as the maximum height, but blocks that are above this value are treated as AIR.<br>
* This leads to the top-faces being rendered instead of them being culled.

View File

@ -27,22 +27,17 @@ package de.bluecolored.bluemap.core.world;
import com.flowpowered.math.vector.Vector2i;
import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.core.util.Grid;
import de.bluecolored.bluemap.core.util.Key;
import java.nio.file.Path;
import java.util.Collection;
/**
* Represents a World on the Server<br>
* Represents a World on the Server.<br>
* This is usually one of the dimensions of a level.<br>
* <br>
* <i>The implementation of this class has to be thread-save!</i><br>
*/
public interface World {
Path getWorldFolder();
Key getDimension();
String getName();
Vector3i getSpawnPoint();

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -37,6 +38,7 @@ public class MCAWorld implements World {
private static final Vector2iCache VECTOR_2_I_CACHE = new Vector2iCache();
private final String id;
private final Path worldFolder;
private final Key dimension;
private final LevelData levelData;
@ -59,7 +61,8 @@ public class MCAWorld implements World {
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(this::loadChunk);
public MCAWorld(Path worldFolder, Key dimension, LevelData levelData, DataPack dataPack) {
public MCAWorld(String id, Path worldFolder, Key dimension, LevelData levelData, DataPack dataPack) {
this.id = id;
this.worldFolder = worldFolder;
this.dimension = dimension;
this.levelData = levelData;
@ -217,6 +220,16 @@ public class MCAWorld implements World {
}
public static MCAWorld load(Path worldFolder, Key dimension) throws IOException {
// load or create bluemap.id
Path idFile = worldFolder.resolve("bluemap.id");
String id;
if (!Files.exists(idFile)) {
id = UUID.randomUUID().toString();
Files.writeString(idFile, id, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
} else {
id = Files.readString(idFile);
}
id += "-" + dimension.getFormatted();
// load level.dat
Path levelFile = worldFolder.resolve("level.dat");
@ -240,7 +253,7 @@ public class MCAWorld implements World {
dataPack.bake();
// create world
return new MCAWorld(worldFolder, dimension, levelData, dataPack);
return new MCAWorld(id, worldFolder, dimension, levelData, dataPack);
}
private static Path resolveDimensionFolder(Path worldFolder, Key dimension) {

View File

@ -24,10 +24,10 @@
*/
package de.bluecolored.bluemap.cli;
import de.bluecolored.bluemap.common.BlueMapConfigProvider;
import de.bluecolored.bluemap.common.BlueMapConfiguration;
import de.bluecolored.bluemap.common.BlueMapService;
import de.bluecolored.bluemap.common.MissingResourcesException;
import de.bluecolored.bluemap.common.config.BlueMapConfigs;
import de.bluecolored.bluemap.common.config.BlueMapConfigManager;
import de.bluecolored.bluemap.common.config.ConfigurationException;
import de.bluecolored.bluemap.common.config.CoreConfig;
import de.bluecolored.bluemap.common.config.WebserverConfig;
@ -37,7 +37,7 @@ import de.bluecolored.bluemap.common.rendermanager.RenderManager;
import de.bluecolored.bluemap.common.rendermanager.RenderTask;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.common.web.*;
import de.bluecolored.bluemap.common.web.http.HttpRequestHandler;
@ -65,7 +65,7 @@ import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
public class BlueMapCLI implements ServerInterface {
public class BlueMapCLI implements Server {
private MinecraftVersion minecraftVersion = MinecraftVersion.LATEST_SUPPORTED;
private Path configFolder;
@ -73,13 +73,13 @@ public class BlueMapCLI implements ServerInterface {
public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRender, boolean forceGenerateWebapp) throws ConfigurationException, IOException, InterruptedException {
//metrics report
if (blueMap.getConfigs().getCoreConfig().isMetrics()) Metrics.sendReportAsync("cli");
if (blueMap.getConfig().getCoreConfig().isMetrics()) Metrics.sendReportAsync("cli");
if (blueMap.getConfigs().getWebappConfig().isEnabled())
if (blueMap.getConfig().getWebappConfig().isEnabled())
blueMap.createOrUpdateWebApp(forceGenerateWebapp);
//try load resources
blueMap.getResourcePack();
blueMap.loadResourcePack();
//create renderManager
RenderManager renderManager = new RenderManager();
@ -113,7 +113,7 @@ public class BlueMapCLI implements ServerInterface {
Logger.global.logInfo("Start updating " + maps.size() + " maps (" + totalRegions + " regions, ~" + totalRegions * 1024L + " chunks)...");
// start rendering
renderManager.start(blueMap.getConfigs().getCoreConfig().resolveRenderThreadCount());
renderManager.start(blueMap.getConfig().getCoreConfig().resolveRenderThreadCount());
Timer timer = new Timer("BlueMap-CLI-Timer", true);
TimerTask updateInfoTask = new TimerTask() {
@ -187,7 +187,7 @@ public class BlueMapCLI implements ServerInterface {
public void startWebserver(BlueMapService blueMap, boolean verbose) throws IOException, ConfigurationException, InterruptedException {
Logger.global.logInfo("Starting webserver ...");
WebserverConfig config = blueMap.getConfigs().getWebserverConfig();
WebserverConfig config = blueMap.getConfig().getWebserverConfig();
FileHelper.createDirectories(config.getWebroot());
RoutingRequestHandler routingRequestHandler = new RoutingRequestHandler();
@ -196,7 +196,7 @@ public class BlueMapCLI implements ServerInterface {
routingRequestHandler.register(".*", new FileRequestHandler(config.getWebroot()));
// map route
for (var mapConfigEntry : blueMap.getConfigs().getMapConfigs().entrySet()) {
for (var mapConfigEntry : blueMap.getConfig().getMapConfigs().entrySet()) {
Storage storage = blueMap.getStorage(mapConfigEntry.getValue().getStorage());
routingRequestHandler.register(
@ -334,7 +334,7 @@ public class BlueMapCLI implements ServerInterface {
}
}
BlueMapConfigs configs = new BlueMapConfigs(cli, Path.of("data"), Path.of("web"), false);
BlueMapConfigManager configs = new BlueMapConfigManager(cli, Path.of("data"), Path.of("web"), false);
//apply new file-logger config
CoreConfig coreConfig = configs.getCoreConfig();
@ -390,9 +390,9 @@ public class BlueMapCLI implements ServerInterface {
Logger.global.logWarning("BlueMap is missing important resources!");
Logger.global.logWarning("You must accept the required file download in order for BlueMap to work!");
if (blueMap != null) {
BlueMapConfigProvider configProvider = blueMap.getConfigs();
if (configProvider instanceof BlueMapConfigs) {
Logger.global.logWarning("Please check: " + ((BlueMapConfigs) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize());
BlueMapConfiguration configProvider = blueMap.getConfig();
if (configProvider instanceof BlueMapConfigManager) {
Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize());
}
}
System.exit(2);

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -51,7 +51,7 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class FabricMod implements ModInitializer, ServerInterface {
public class FabricMod implements ModInitializer, Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -53,7 +53,7 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class FabricMod implements ModInitializer, ServerInterface {
public class FabricMod implements ModInitializer, Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -53,7 +53,7 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class FabricMod implements ModInitializer, ServerInterface {
public class FabricMod implements ModInitializer, Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -53,7 +53,7 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class FabricMod implements ModInitializer, ServerInterface {
public class FabricMod implements ModInitializer, Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -54,7 +54,7 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class FabricMod implements ModInitializer, ServerInterface {
public class FabricMod implements ModInitializer, Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -54,7 +54,7 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class FabricMod implements ModInitializer, ServerInterface {
public class FabricMod implements ModInitializer, Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -63,7 +63,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Mod(Plugin.PLUGIN_ID)
public class ForgeMod implements ServerInterface {
public class ForgeMod implements Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -63,7 +63,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Mod(Plugin.PLUGIN_ID)
public class ForgeMod implements ServerInterface {
public class ForgeMod implements Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -64,7 +64,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Mod(Plugin.PLUGIN_ID)
public class ForgeMod implements ServerInterface {
public class ForgeMod implements Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -30,7 +30,7 @@ import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -64,7 +64,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Mod(Plugin.PLUGIN_ID)
public class ForgeMod implements ServerInterface {
public class ForgeMod implements Server {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;

View File

@ -29,7 +29,7 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -56,7 +56,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BukkitPlugin extends JavaPlugin implements ServerInterface, Listener {
public class BukkitPlugin extends JavaPlugin implements Server, Listener {
private static BukkitPlugin instance;

View File

@ -29,7 +29,7 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -55,7 +55,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BukkitPlugin extends JavaPlugin implements ServerInterface, Listener {
public class BukkitPlugin extends JavaPlugin implements Server, Listener {
private static BukkitPlugin instance;

View File

@ -33,7 +33,7 @@ import com.google.inject.Inject;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.Server;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
@ -42,7 +42,6 @@ import de.bluecolored.bluemap.sponge.SpongeCommands.SpongeCommandProxy;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.spongepowered.api.Platform;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Server;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.Command;
import org.spongepowered.api.config.ConfigDir;
@ -66,7 +65,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
@org.spongepowered.plugin.builtin.jvm.Plugin(Plugin.PLUGIN_ID)
public class SpongePlugin implements ServerInterface {
public class SpongePlugin implements Server {
private static SpongePlugin instance;
private final PluginContainer pluginContainer;
@ -131,7 +130,7 @@ public class SpongePlugin implements ServerInterface {
}
@Listener
public void onServerStart(StartedEngineEvent<Server> evt) {
public void onServerStart(StartedEngineEvent<org.spongepowered.api.Server> evt) {
asyncExecutor = evt.game().asyncScheduler().executor(pluginContainer);
syncExecutor = evt.engine().scheduler().executor(pluginContainer);
@ -156,7 +155,7 @@ public class SpongePlugin implements ServerInterface {
}
@Listener
public void onServerStop(StoppingEngineEvent<Server> evt) {
public void onServerStop(StoppingEngineEvent<org.spongepowered.api.Server> evt) {
Logger.global.logInfo("Stopping...");
evt.engine().scheduler().tasks(pluginContainer).forEach(ScheduledTask::cancel);
pluginInstance.unload();