Reorganize and expose some config files to create the abillity to integrate mods

This commit is contained in:
Blue (Lukas Rieger) 2019-12-30 22:36:48 +01:00
parent 29feb3e4a9
commit f6be5dd30f
27 changed files with 522 additions and 652 deletions

View File

@ -26,6 +26,7 @@
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -51,9 +52,9 @@
import com.flowpowered.math.vector.Vector3i;
import com.google.common.base.Preconditions;
import de.bluecolored.bluemap.core.config.Configuration;
import de.bluecolored.bluemap.core.config.Configuration.MapConfig;
import de.bluecolored.bluemap.core.config.ConfigurationFile;
import de.bluecolored.bluemap.core.config.ConfigManager;
import de.bluecolored.bluemap.core.config.MainConfig;
import de.bluecolored.bluemap.core.config.MainConfig.MapConfig;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.mca.MCAWorld;
import de.bluecolored.bluemap.core.metrics.Metrics;
@ -68,15 +69,13 @@
public class BlueMapCLI {
private ConfigurationFile configFile;
private Configuration config;
private ConfigManager configManager;
private File configFolder;
private ResourcePack resourcePack;
private boolean forceRender;
public BlueMapCLI(ConfigurationFile configFile, File configFolder, boolean forceRender) {
this.configFile = configFile;
this.config = configFile.getConfig();
public BlueMapCLI(ConfigManager configManager, File configFolder, boolean forceRender) {
this.configManager = configManager;
this.configFolder = configFolder;
this.forceRender = forceRender;
this.resourcePack = null;
@ -85,6 +84,8 @@ public BlueMapCLI(ConfigurationFile configFile, File configFolder, boolean force
public void renderMaps() throws IOException {
Preconditions.checkNotNull(resourcePack);
MainConfig config = configManager.getMainConfig();
config.getWebDataPath().toFile().mkdirs();
Map<String, MapType> maps = new HashMap<>();
@ -96,7 +97,7 @@ public void renderMaps() throws IOException {
}
Logger.global.logInfo("Preparing renderer for map '" + mapConfig.getId() + "' ...");
World world = MCAWorld.load(mapPath.toPath(), UUID.randomUUID());
World world = MCAWorld.load(mapPath.toPath(), UUID.randomUUID(), configManager.getBlockIdConfig(), configManager.getBlockPropertiesConfig(), configManager.getBiomeConfig());
HiresModelManager hiresModelManager = new HiresModelManager(
config.getWebDataPath().resolve("hires").resolve(mapConfig.getId()),
@ -124,6 +125,7 @@ public void renderMaps() throws IOException {
webSettings.setFrom(map.getTileRenderer(), map.getId());
}
for (MapConfig map : config.getMapConfigs()) {
if (!maps.containsKey(map.getId())) continue; //don't add not loaded maps
webSettings.setHiresViewDistance(map.getHiresViewDistance(), map.getId());
webSettings.setLowresViewDistance(map.getLowresViewDistance(), map.getId());
}
@ -189,13 +191,15 @@ public void renderMaps() throws IOException {
public void startWebserver() throws IOException {
Logger.global.logInfo("Starting webserver...");
BlueMapWebServer webserver = new BlueMapWebServer(config);
BlueMapWebServer webserver = new BlueMapWebServer(configManager.getMainConfig());
webserver.updateWebfiles();
webserver.start();
}
private boolean loadResources() throws IOException, ParseResourceException {
Logger.global.logInfo("Loading resources...");
MainConfig config = configManager.getMainConfig();
File defaultResourceFile = config.getDataPath().resolve("minecraft-client-" + ResourcePack.MINECRAFT_CLIENT_VERSION + ".jar").toFile();
File resourceExtensionsFile = config.getDataPath().resolve("resourceExtensions.zip").toFile();
@ -214,7 +218,7 @@ private boolean loadResources() throws IOException, ParseResourceException {
}
//find more resource packs
File resourcePackFolder = configFile.getFile().toPath().resolveSibling("resourcepacks").toFile();
File resourcePackFolder = configFolder.toPath().resolve("resourcepacks").toFile();
resourcePackFolder.mkdirs();
File[] resourcePacks = resourcePackFolder.listFiles();
Arrays.sort(resourcePacks);
@ -234,7 +238,7 @@ private boolean loadResources() throws IOException, ParseResourceException {
}
private boolean handleMissingResources(File resourceFile) {
if (config.isDownloadAccepted()) {
if (configManager.getMainConfig().isDownloadAccepted()) {
try {
Logger.global.logInfo("Downloading " + ResourcePack.MINECRAFT_CLIENT_URL + " to " + resourceFile + " ...");
ResourcePack.downloadDefaultResource(resourceFile);
@ -246,7 +250,7 @@ private boolean handleMissingResources(File resourceFile) {
} else {
Logger.global.logWarning("BlueMap is missing important resources!");
Logger.global.logWarning("You need to accept the download of the required files in order of BlueMap to work!");
Logger.global.logWarning("Please check: " + configFile.getFile() + " and try again!");
Logger.global.logWarning("Please check " + configManager.getMainConfigFile() + " and try again!");
return false;
}
}
@ -270,30 +274,37 @@ public static void main(String[] args) throws IOException, ParseResourceExceptio
configFolder.mkdirs();
}
File configFile = new File(configFolder, "bluemap.conf");
URL cliConfigUrl = BlueMapCLI.class.getResource("/bluemap-cli.conf");
URL cliDefaultsUrl = BlueMapCLI.class.getResource("/bluemap-cli-defaults.conf");
boolean configCreated = !configFile.exists();
ConfigurationFile config = ConfigurationFile.loadOrCreate(configFile, BlueMapCLI.class.getResource("/bluemap-cli.conf"));
ConfigManager config = new ConfigManager(configFolder, cliConfigUrl, cliDefaultsUrl);
boolean configCreated = !config.getMainConfigFile().exists();
config.loadOrCreateConfigs();
if (configCreated) {
Logger.global.logInfo("No config file found! Created an example config here: " + configFile);
Logger.global.logInfo("No config file found! Created default configs here: " + configFolder);
return;
}
BlueMapCLI bluemap = new BlueMapCLI(config, configFolder, cmd.hasOption("f"));
if (config.getConfig().isWebserverEnabled()) {
if (config.getMainConfig().isWebserverEnabled()) {
//start webserver
bluemap.startWebserver();
//wait a second to let the webserver start, looks nicer in the log
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {}
}
if (!config.getConfig().getMapConfigs().isEmpty()) {
if (!config.getMainConfig().getMapConfigs().isEmpty()) {
//load resources
if (bluemap.loadResources()) {
//metrics
if (config.getConfig().isMetricsEnabled()) Metrics.sendReportAsync("CLI");
if (config.getMainConfig().isMetricsEnabled()) Metrics.sendReportAsync("CLI");
//render maps
bluemap.renderMaps();

View File

@ -0,0 +1,9 @@
accept-download: false
metrics: true
data: "."
web {
enabled: false
webroot: "web"
port: 8100
maxConnectionCount: 100
}

View File

@ -6,6 +6,7 @@ dependencies {
compile 'com.flowpowered:flow-math:1.0.3'
compile 'ninja.leaping.configurate:configurate-hocon:3.3'
compile 'ninja.leaping.configurate:configurate-gson:3.3'
compile 'ninja.leaping.configurate:configurate-yaml:3.3'
compile 'com.github.Querz:NBT:4.0'
}

View File

@ -22,45 +22,33 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.bluecolored.bluemap.core.mca.mapping;
package de.bluecolored.bluemap.core.config;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map.Entry;
import de.bluecolored.bluemap.core.mca.mapping.BiomeMapper;
import de.bluecolored.bluemap.core.world.Biome;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.gson.GsonConfigurationLoader;
public class BiomeIdMapper {
public class BiomeConfig implements BiomeMapper {
private HashMap<Integer, Biome> biomes;
public BiomeIdMapper() throws IOException {
public BiomeConfig(ConfigurationNode node) {
biomes = new HashMap<>();
GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
.setURL(getClass().getResource("/biomes.json"))
.build();
ConfigurationNode node = loader.load();
for (Entry<Object, ? extends ConfigurationNode> e : node.getChildrenMap().entrySet()){
String id = e.getKey().toString();
Biome biome = Biome.create(id, e.getValue());
biomes.put(biome.getOrdinal(), biome);
}
}
}
@Override
public Biome get(int id) {
Biome biome = biomes.get(id);
if (biome == null) return Biome.DEFAULT;
return biome;
}
public static BiomeIdMapper create() throws IOException {
return new BiomeIdMapper();
return biomes.getOrDefault(id, Biome.DEFAULT);
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.config;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.mca.mapping.BlockIdMapper;
import de.bluecolored.bluemap.core.world.BlockState;
import ninja.leaping.configurate.ConfigurationNode;
public class BlockIdConfig implements BlockIdMapper {
private Map<BlockIDMeta, BlockState> mappings;
public BlockIdConfig(ConfigurationNode node) {
mappings = new HashMap<>();
for (Entry<Object, ? extends ConfigurationNode> e : node.getChildrenMap().entrySet()){
String key = e.getKey().toString();
String value = e.getValue().getString();
try {
int splitIndex = key.indexOf(':');
int blockId, blockMeta;
if (splitIndex > 0 && splitIndex < key.length() - 1) {
blockId = Integer.parseInt(key.substring(0, splitIndex));
blockMeta = Integer.parseInt(key.substring(splitIndex + 1));
} else {
blockId = Integer.parseInt(key);
blockMeta = 0;
}
BlockIDMeta idmeta = new BlockIDMeta(blockId, blockMeta);
BlockState state = BlockState.fromString(value);
mappings.put(idmeta, state);
} catch (NumberFormatException ex) {
Logger.global.logWarning("Loading BlockIdConfig: Failed to parse blockid:meta from key '" + key + "'");
} catch (IllegalArgumentException ex) {
Logger.global.logWarning("Loading BlockIdConfig: Failed to parse BlockState from value '" + value + "'");
}
}
}
@Override
public BlockState get(int id, int meta) {
BlockState state = mappings.get(new BlockIDMeta(id, meta));
if (state == null) {
state = mappings.getOrDefault(new BlockIDMeta(id, 0), BlockState.AIR); //meta-fallback
}
return state;
}
class BlockIDMeta {
private final int id;
private final int meta;
public BlockIDMeta(int id, int meta) {
this.id = id;
this.meta = meta;
}
public int getId() {
return id;
}
public int getMeta() {
return meta;
}
@Override
public int hashCode() {
return id * 0xFFFF + meta;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BlockIDMeta) {
BlockIDMeta other = (BlockIDMeta) obj;
return other.id == id && other.meta == meta;
}
return false;
}
}
}

View File

@ -22,7 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.bluecolored.bluemap.core.mca.mapping;
package de.bluecolored.bluemap.core.config;
import java.io.IOException;
import java.util.Map.Entry;
@ -35,36 +35,34 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.mca.mapping.BlockPropertiesMapper;
import de.bluecolored.bluemap.core.world.BlockProperties;
import de.bluecolored.bluemap.core.world.BlockState;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.gson.GsonConfigurationLoader;
public class BlockPropertyMapper {
private static final BlockProperties DEFAULT_PROPERTIES = new BlockProperties(false, false, false);
public class BlockPropertiesConfig implements BlockPropertiesMapper {
private Multimap<String, BlockStateMapping<BlockProperties>> mappings;
private LoadingCache<BlockState, BlockProperties> mappingCache;
private BlockPropertyMapper() throws IOException {
public BlockPropertiesConfig(ConfigurationNode node) throws IOException {
mappings = HashMultimap.create();
GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
.setURL(getClass().getResource("/blockProperties.json"))
.build();
ConfigurationNode node = loader.load();
for (Entry<Object, ? extends ConfigurationNode> e : node.getChildrenMap().entrySet()){
String key = e.getKey().toString();
BlockState bsKey = BlockState.fromString(key);
BlockProperties bsValue = new BlockProperties(
e.getValue().getNode("culling").getBoolean(false),
e.getValue().getNode("occluding").getBoolean(false),
e.getValue().getNode("flammable").getBoolean(false)
);
BlockStateMapping<BlockProperties> mapping = new BlockStateMapping<>(bsKey, bsValue);
mappings.put(bsKey.getId(), mapping);
try {
BlockState bsKey = BlockState.fromString(key);
BlockProperties bsValue = new BlockProperties(
e.getValue().getNode("culling").getBoolean(false),
e.getValue().getNode("occluding").getBoolean(false),
e.getValue().getNode("flammable").getBoolean(false)
);
BlockStateMapping<BlockProperties> mapping = new BlockStateMapping<>(bsKey, bsValue);
mappings.put(bsKey.getFullId(), mapping);
} catch (IllegalArgumentException ex) {
Logger.global.logWarning("Loading BlockPropertiesConfig: Failed to parse BlockState from key '" + key + "'");
}
}
mappings = Multimaps.unmodifiableMultimap(mappings);
@ -77,27 +75,24 @@ private BlockPropertyMapper() throws IOException {
});
}
public BlockProperties map(BlockState from){
@Override
public BlockProperties get(BlockState from){
try {
return mappingCache.get(from);
} catch (ExecutionException e) {
} catch (ExecutionException neverHappens) {
//should never happen, since the CacheLoader does not throw any exceptions
throw new RuntimeException("Unexpected error while trying to map a BlockState's properties", e.getCause());
throw new RuntimeException("Unexpected error while trying to map a BlockState's properties", neverHappens.getCause());
}
}
private BlockProperties mapNoCache(BlockState bs){
for (BlockStateMapping<BlockProperties> bm : mappings.get(bs.getId())){
for (BlockStateMapping<BlockProperties> bm : mappings.get(bs.getFullId())){
if (bm.fitsTo(bs)){
return bm.getMapping();
}
}
return DEFAULT_PROPERTIES;
}
public static BlockPropertyMapper create() throws IOException {
return new BlockPropertyMapper();
return BlockProperties.DEFAULT;
}
}

View File

@ -22,7 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.bluecolored.bluemap.core.mca.mapping;
package de.bluecolored.bluemap.core.config;
import java.util.Map.Entry;

View File

@ -0,0 +1,170 @@
/*
* 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.config;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.resourcepack.ResourcePack;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.gson.GsonConfigurationLoader;
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
public class ConfigManager {
private static final Set<Placeholder> CONFIG_PLACEHOLDERS = new HashSet<>();
static {
CONFIG_PLACEHOLDERS.add(new Placeholder("version", BlueMap.VERSION));
CONFIG_PLACEHOLDERS.add(new Placeholder("datetime-iso", () -> LocalDateTime.now().withNano(0).toString()));
CONFIG_PLACEHOLDERS.add(new Placeholder("minecraft-client-url", ResourcePack.MINECRAFT_CLIENT_URL));
CONFIG_PLACEHOLDERS.add(new Placeholder("minecraft-client-version", ResourcePack.MINECRAFT_CLIENT_VERSION));
}
private File configFolder;
private URL defaultMainConfig;
private URL mainConfigDefaultValues;
private MainConfig mainConfig;
private BlockIdConfig blockIdConfig;
private BlockPropertiesConfig blockPropertiesConfig;
private BiomeConfig biomeConfig;
/**
* Manages all configurations BlueMap needs to render stuff.
*
* @param configFolder The folder containing all configuration-files
* @param defaultMainConfig The default main-configuration file, used if a new configuration is generated
* @param mainConfigDefaultValues The default values that are used for the main-configuration file (if they are undefined)
*/
public ConfigManager(File configFolder, URL defaultMainConfig, URL mainConfigDefaultValues) {
this.defaultMainConfig = defaultMainConfig;
this.configFolder = configFolder;
}
public MainConfig getMainConfig() {
return mainConfig;
}
public File getMainConfigFile() {
return new File(configFolder, "bluemap.conf");
}
public BlockIdConfig getBlockIdConfig() {
return blockIdConfig;
}
public File getBlockIdConfigFile() {
return new File(configFolder, "blockIds.json");
}
public BlockPropertiesConfig getBlockPropertiesConfig() {
return blockPropertiesConfig;
}
public File getBlockPropertiesConfigFile() {
return new File(configFolder, "blockProperties.json");
}
public BiomeConfig getBiomeConfig() {
return biomeConfig;
}
public File getBiomeConfigFile() {
return new File(configFolder, "biomes.json");
}
public void loadOrCreateConfigs() throws IOException {
mainConfig = new MainConfig(loadOrCreate(getMainConfigFile(), defaultMainConfig, mainConfigDefaultValues, true));
URL blockIdsConfigUrl = BlueMap.class.getResource("/blockIds.json");
blockIdConfig = new BlockIdConfig(loadOrCreate(getBlockIdConfigFile(), blockIdsConfigUrl, blockIdsConfigUrl, false));
URL blockPropertiesConfigUrl = BlueMap.class.getResource("/blockProperties.json");
blockPropertiesConfig = new BlockPropertiesConfig(loadOrCreate(getBlockPropertiesConfigFile(), blockPropertiesConfigUrl, blockPropertiesConfigUrl, false));
URL biomeConfigUrl = BlueMap.class.getResource("/biomes.json");
biomeConfig = new BiomeConfig(loadOrCreate(getBiomeConfigFile(), biomeConfigUrl, biomeConfigUrl, false));
}
private ConfigurationNode loadOrCreate(File configFile, URL defaultConfig, URL defaultValues, boolean usePlaceholders) throws IOException {
if (!configFile.exists()) {
configFile.getParentFile().mkdirs();
//load content of default config
String content;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(defaultConfig.openStream(), StandardCharsets.UTF_8))){
content = reader.lines().collect(Collectors.joining("\n"));
}
//replace placeholders if enabled
if (usePlaceholders) {
for (Placeholder placeholder : CONFIG_PLACEHOLDERS) {
content = placeholder.apply(content);
}
}
//create the config file
Files.write(configFile.toPath(), content.getBytes(StandardCharsets.UTF_8));
}
ConfigurationNode configNode = getLoader(configFile).load();
//populate missing values with default values
if (defaultValues != null) {
ConfigurationNode defaultValuesNode = getLoader(defaultValues).load();
configNode.mergeValuesFrom(defaultValuesNode);
}
return configNode;
}
private ConfigurationLoader<? extends ConfigurationNode> getLoader(URL url){
if (url.getFile().endsWith(".json")) return GsonConfigurationLoader.builder().setURL(url).build();
if (url.getFile().endsWith(".yaml") || url.getFile().endsWith(".yml")) return YAMLConfigurationLoader.builder().setURL(url).build();
else return HoconConfigurationLoader.builder().setURL(url).build();
}
private ConfigurationLoader<? extends ConfigurationNode> getLoader(File file){
if (file.getName().endsWith(".json")) return GsonConfigurationLoader.builder().setFile(file).build();
if (file.getName().endsWith(".yaml") || file.getName().endsWith(".yml")) return YAMLConfigurationLoader.builder().setFile(file).build();
else return HoconConfigurationLoader.builder().setFile(file).build();
}
}

View File

@ -1,123 +0,0 @@
/*
* 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.config;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.resourcepack.ResourcePack;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
import ninja.leaping.configurate.loader.ConfigurationLoader;
public class ConfigurationFile {
private static final Set<Placeholder> CONFIG_PLACEHOLDERS = new HashSet<>();
static {
CONFIG_PLACEHOLDERS.add(new Placeholder("version", BlueMap.VERSION));
CONFIG_PLACEHOLDERS.add(new Placeholder("datetime-iso", () -> LocalDateTime.now().withNano(0).toString()));
CONFIG_PLACEHOLDERS.add(new Placeholder("minecraft-client-url", ResourcePack.MINECRAFT_CLIENT_URL));
CONFIG_PLACEHOLDERS.add(new Placeholder("minecraft-client-version", ResourcePack.MINECRAFT_CLIENT_VERSION));
}
private File configFile;
private Configuration config;
private ConfigurationFile(File configFile, File defaultValuesFile) throws IOException {
this.configFile = configFile;
ConfigurationLoader<CommentedConfigurationNode> configLoader = HoconConfigurationLoader.builder()
.setFile(configFile)
.build();
CommentedConfigurationNode rootNode = configLoader.load();
// fill defaults
ConfigurationLoader<CommentedConfigurationNode> defaultConfigLoader = HoconConfigurationLoader.builder()
.setFile(defaultValuesFile)
.build();
CommentedConfigurationNode defaultRootNode = defaultConfigLoader.load();
fillDefaults(rootNode, defaultRootNode);
this.config = new Configuration(rootNode);
}
private void fillDefaults(ConfigurationNode rootNode, ConfigurationNode defaultRootNode) {
setDefault(rootNode.getNode("metrics"), defaultRootNode.getNode("metrics").getValue());
setDefault(rootNode.getNode("data"), defaultRootNode.getNode("data").getValue());
setDefault(rootNode.getNode("renderThreadCount"), defaultRootNode.getNode("renderThreadCount").getValue());
rootNode.getNode("web").mergeValuesFrom(defaultRootNode.getNode("web"));
}
private void setDefault(ConfigurationNode node, Object value) {
if (node.isVirtual()) node.setValue(value);
}
public File getFile() {
return configFile;
}
public Configuration getConfig() {
return config;
}
public static ConfigurationFile loadOrCreate(File configFile) throws IOException {
return loadOrCreate(configFile, ConfigurationFile.class.getResource("/bluemap.conf"));
}
public static ConfigurationFile loadOrCreate(File configFile, URL defaultConfig) throws IOException {
File tempDefaultFile = File.createTempFile("bluemap-defaults", ".conf");
FileUtils.copyURLToFile(defaultConfig, tempDefaultFile, 10000, 10000);
if (!configFile.exists()) {
configFile.getParentFile().mkdirs();
//replace placeholder
String content = new String(Files.readAllBytes(tempDefaultFile.toPath()), StandardCharsets.UTF_8);
for (Placeholder placeholder : CONFIG_PLACEHOLDERS) {
content = placeholder.apply(content);
}
Files.write(configFile.toPath(), content.getBytes(StandardCharsets.UTF_8));
}
return new ConfigurationFile(configFile, tempDefaultFile);
}
public static void registerPlaceholder(Placeholder placeholder) {
CONFIG_PLACEHOLDERS.add(placeholder);
}
}

View File

@ -38,9 +38,9 @@
import de.bluecolored.bluemap.core.web.WebServerConfig;
import ninja.leaping.configurate.ConfigurationNode;
public class Configuration implements WebServerConfig {
public class MainConfig implements WebServerConfig {
private String version;
private String version;
private boolean downloadAccepted = false;
private boolean metricsEnabled = false;
@ -59,8 +59,8 @@ public class Configuration implements WebServerConfig {
private Collection<MapConfig> mapConfigs = new ArrayList<>();
public Configuration(ConfigurationNode node) throws IOException {
version = node.getNode("version").getString("-");
public MainConfig(ConfigurationNode node) throws IOException {
version = node.getNode("version").getString();
downloadAccepted = node.getNode("accept-download").getBoolean(false);
metricsEnabled = node.getNode("metrics").getBoolean(false);

View File

@ -26,7 +26,7 @@
import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.core.mca.mapping.BiomeIdMapper;
import de.bluecolored.bluemap.core.mca.mapping.BiomeMapper;
import de.bluecolored.bluemap.core.mca.mapping.BlockIdMapper;
import de.bluecolored.bluemap.core.world.Biome;
import de.bluecolored.bluemap.core.world.BlockState;
@ -37,7 +37,7 @@
class ChunkAnvil112 extends Chunk {
private BlockIdMapper blockIdMapper;
private BiomeIdMapper biomeIdMapper;
private BiomeMapper biomeIdMapper;
private boolean isGenerated;
private Section[] sections;

View File

@ -31,7 +31,7 @@
import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.mca.mapping.BiomeIdMapper;
import de.bluecolored.bluemap.core.mca.mapping.BiomeMapper;
import de.bluecolored.bluemap.core.world.Biome;
import de.bluecolored.bluemap.core.world.BlockState;
import de.bluecolored.bluemap.core.world.LightData;
@ -44,7 +44,7 @@
import net.querz.nbt.mca.MCAUtil;
class ChunkAnvil113 extends Chunk {
private BiomeIdMapper biomeIdMapper;
private BiomeMapper biomeIdMapper;
private boolean isGenerated;
private Section[] sections;

View File

@ -26,9 +26,9 @@
import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.core.mca.mapping.BlockProperties;
import de.bluecolored.bluemap.core.world.Biome;
import de.bluecolored.bluemap.core.world.Block;
import de.bluecolored.bluemap.core.world.BlockProperties;
import de.bluecolored.bluemap.core.world.BlockState;
import de.bluecolored.bluemap.core.world.LightData;
@ -84,6 +84,11 @@ public boolean isCullingNeighborFaces() {
public boolean isOccludingNeighborFaces() {
return properties.isOccluding();
}
@Override
public boolean isFlammable() {
return properties.isFlammable();
}
@Override
public Biome getBiome() {

View File

@ -60,13 +60,13 @@
import de.bluecolored.bluemap.core.mca.extensions.TripwireConnectExtension;
import de.bluecolored.bluemap.core.mca.extensions.WallConnectExtension;
import de.bluecolored.bluemap.core.mca.extensions.WoodenFenceConnectExtension;
import de.bluecolored.bluemap.core.mca.mapping.BiomeIdMapper;
import de.bluecolored.bluemap.core.mca.mapping.BiomeMapper;
import de.bluecolored.bluemap.core.mca.mapping.BlockIdMapper;
import de.bluecolored.bluemap.core.mca.mapping.BlockProperties;
import de.bluecolored.bluemap.core.mca.mapping.BlockPropertyMapper;
import de.bluecolored.bluemap.core.mca.mapping.BlockPropertiesMapper;
import de.bluecolored.bluemap.core.util.AABB;
import de.bluecolored.bluemap.core.world.Biome;
import de.bluecolored.bluemap.core.world.Block;
import de.bluecolored.bluemap.core.world.BlockProperties;
import de.bluecolored.bluemap.core.world.BlockState;
import de.bluecolored.bluemap.core.world.ChunkNotGeneratedException;
import de.bluecolored.bluemap.core.world.LightData;
@ -83,19 +83,7 @@ public class MCAWorld implements World {
private static final Cache<WorldChunkHash, Chunk> CHUNK_CACHE = CacheBuilder.newBuilder().maximumSize(500).build();
private static final Multimap<String, BlockStateExtension> BLOCK_STATE_EXTENSIONS = MultimapBuilder.hashKeys().arrayListValues().build();
public static final BlockIdMapper DEFAULT_BLOCK_ID_MAPPER;
public static final BlockPropertyMapper DEFAULT_BLOCK_PROPERTY_MAPPER;
public static final BiomeIdMapper DEFAULT_BIOME_ID_MAPPER;
static {
try {
DEFAULT_BLOCK_ID_MAPPER = BlockIdMapper.create();
DEFAULT_BLOCK_PROPERTY_MAPPER = BlockPropertyMapper.create();
DEFAULT_BIOME_ID_MAPPER = BiomeIdMapper.create();
} catch (IOException e) {
throw new RuntimeException("Failed to load essential resources!", e);
}
registerBlockStateExtension(new SnowyExtension());
registerBlockStateExtension(new StairShapeExtension());
registerBlockStateExtension(new FireExtension());
@ -117,8 +105,8 @@ public class MCAWorld implements World {
private Vector3i spawnPoint;
private BlockIdMapper blockIdMapper;
private BlockPropertyMapper blockPropertyMapper;
private BiomeIdMapper biomeIdMapper;
private BlockPropertiesMapper blockPropertiesMapper;
private BiomeMapper biomeMapper;
private MCAWorld(
Path worldFolder,
@ -128,8 +116,8 @@ private MCAWorld(
int seaLevel,
Vector3i spawnPoint,
BlockIdMapper blockIdMapper,
BlockPropertyMapper blockPropertyMapper,
BiomeIdMapper biomeIdMapper
BlockPropertiesMapper blockPropertiesMapper,
BiomeMapper biomeMapper
) {
this.uuid = uuid;
this.worldFolder = worldFolder;
@ -139,8 +127,8 @@ private MCAWorld(
this.spawnPoint = spawnPoint;
this.blockIdMapper = blockIdMapper;
this.blockPropertyMapper = blockPropertyMapper;
this.biomeIdMapper = biomeIdMapper;
this.blockPropertiesMapper = blockPropertiesMapper;
this.biomeMapper = biomeMapper;
}
public BlockState getBlockState(Vector3i pos) {
@ -164,7 +152,7 @@ public Block getBlock(Vector3i pos) throws ChunkNotGeneratedException {
BlockState blockState = getExtendedBlockState(chunk, pos);
LightData lightData = chunk.getLightData(pos);
Biome biome = chunk.getBiome(pos);
BlockProperties properties = blockPropertyMapper.map(blockState);
BlockProperties properties = blockPropertiesMapper.get(blockState);
return new MCABlock(this, blockState, lightData, biome, properties, pos);
} catch (IOException ex) {
@ -335,24 +323,24 @@ public BlockIdMapper getBlockIdMapper() {
return blockIdMapper;
}
public BlockPropertyMapper getBlockPropertyMapper() {
return blockPropertyMapper;
public BlockPropertiesMapper getBlockPropertiesMapper() {
return blockPropertiesMapper;
}
public BiomeIdMapper getBiomeIdMapper() {
return biomeIdMapper;
public BiomeMapper getBiomeIdMapper() {
return biomeMapper;
}
public void setBlockIdMapper(BlockIdMapper blockIdMapper) {
this.blockIdMapper = blockIdMapper;
}
public void setBlockPropertyMapper(BlockPropertyMapper blockPropertyMapper) {
this.blockPropertyMapper = blockPropertyMapper;
public void setBlockPropertiesMapper(BlockPropertiesMapper blockPropertiesMapper) {
this.blockPropertiesMapper = blockPropertiesMapper;
}
public void setBiomeIdMapper(BiomeIdMapper biomeIdMapper) {
this.biomeIdMapper = biomeIdMapper;
public void setBiomeMapper(BiomeMapper biomeMapper) {
this.biomeMapper = biomeMapper;
}
public Path getWorldFolder() {
@ -367,7 +355,7 @@ private Path getMCAFilePath(Vector2i region) {
return getRegionFolder().resolve(MCAUtil.createNameFromRegionLocation(region.getX(), region.getY()));
}
public static MCAWorld load(Path worldFolder, UUID uuid) throws IOException {
public static MCAWorld load(Path worldFolder, UUID uuid, BlockIdMapper blockIdMapper, BlockPropertiesMapper blockPropertiesMapper, BiomeMapper biomeIdMapper) throws IOException {
try {
CompoundTag level = (CompoundTag) NBTUtil.readTag(worldFolder.resolve("level.dat").toFile());
CompoundTag levelData = level.getCompoundTag("Data");
@ -389,10 +377,10 @@ public static MCAWorld load(Path worldFolder, UUID uuid) throws IOException {
name,
worldHeight,
seaLevel,
spawnPoint,
DEFAULT_BLOCK_ID_MAPPER,
DEFAULT_BLOCK_PROPERTY_MAPPER,
DEFAULT_BIOME_ID_MAPPER
spawnPoint,
blockIdMapper,
blockPropertiesMapper,
biomeIdMapper
);
} catch (ClassCastException | NullPointerException ex) {
throw new IOException("Invaid level.dat format!", ex);

View File

@ -35,7 +35,7 @@ public abstract class ConnectSameOrFullBlockExtension extends ConnectExtension {
public boolean connectsTo(MCAWorld world, Vector3i pos, BlockState block) {
if (super.connectsTo(world, pos, block)) return true;
return world.getBlockPropertyMapper().map(block).isCulling();
return world.getBlockPropertiesMapper().get(block).isCulling();
}
}

View File

@ -43,13 +43,13 @@ public class FireExtension implements BlockStateExtension {
public BlockState extend(MCAWorld world, Vector3i pos, BlockState state) {
BlockState below = world.getBlockState(pos.add(0, -1, 0));
boolean isOnGround = world.getBlockPropertyMapper().map(below).isCulling();
boolean isOnGround = world.getBlockPropertiesMapper().get(below).isCulling();
for (Direction dir : Direction.values()) {
if (dir != Direction.DOWN) {
if (!isOnGround) {
BlockState neighbor = world.getBlockState(pos.add(dir.toVector()));
state = state.with(dir.name().toLowerCase(), String.valueOf(!world.getBlockPropertyMapper().map(neighbor).isCulling()));
state = state.with(dir.name().toLowerCase(), String.valueOf(!world.getBlockPropertiesMapper().get(neighbor).isCulling()));
} else {
state = state.with(dir.name().toLowerCase(), "false");
}

View File

@ -0,0 +1,34 @@
/*
* 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.mca.mapping;
import de.bluecolored.bluemap.core.world.Biome;
@FunctionalInterface
public interface BiomeMapper {
Biome get(int id);
}

View File

@ -24,96 +24,11 @@
*/
package de.bluecolored.bluemap.core.mca.mapping;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.world.BlockState;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.gson.GsonConfigurationLoader;
public class BlockIdMapper {
@FunctionalInterface
public interface BlockIdMapper {
private Map<BlockIDMeta, BlockState> mappings;
public BlockIdMapper() throws IOException {
mappings = new HashMap<>();
GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
.setURL(getClass().getResource("/blockIds.json"))
.build();
ConfigurationNode node = loader.load();
for (Entry<Object, ? extends ConfigurationNode> e : node.getChildrenMap().entrySet()){
String key = e.getKey().toString();
String value = e.getValue().getString();
int splitIndex = key.indexOf(':');
int blockId = Integer.parseInt(key.substring(0, splitIndex));
int blockMeta = Integer.parseInt(key.substring(splitIndex + 1));
BlockIDMeta idmeta = new BlockIDMeta(blockId, blockMeta);
BlockState state = BlockState.fromString(value);
mappings.put(idmeta, state);
}
}
public BlockState get(int id, int meta) {
if (id == 0) return BlockState.AIR;
BlockState state = mappings.get(new BlockIDMeta(id, meta));
if (state == null) {
state = mappings.get(new BlockIDMeta(id, 0)); //fallback
if (state == null) {
Logger.global.noFloodDebug(id + ":" + meta + "-blockidmapper-mappingerr", "Block ID can not be mapped: " + id + ":" + meta);
return BlockState.AIR;
}
}
return state;
}
class BlockIDMeta {
private final int id;
private final int meta;
public BlockIDMeta(int id, int meta) {
this.id = id;
this.meta = meta;
}
public int getId() {
return id;
}
public int getMeta() {
return meta;
}
@Override
public int hashCode() {
return id * 0xFFFF + meta;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BlockIDMeta) {
BlockIDMeta other = (BlockIDMeta) obj;
return other.id == id && other.meta == meta;
}
return false;
}
}
public static BlockIdMapper create() throws IOException {
return new BlockIdMapper();
}
BlockState get(int id, int meta);
}

View File

@ -0,0 +1,35 @@
/*
* 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.mca.mapping;
import de.bluecolored.bluemap.core.world.BlockProperties;
import de.bluecolored.bluemap.core.world.BlockState;
@FunctionalInterface
public interface BlockPropertiesMapper {
BlockProperties get(BlockState blockState);
}

View File

@ -95,6 +95,11 @@ public boolean isCullingNeighborFaces() {
return false;
}
@Override
public boolean isFlammable() {
return false;
}
@Override
public Biome getBiome() {
return Biome.DEFAULT;

View File

@ -51,6 +51,8 @@ public Block() {
public abstract double getBlockLightLevel();
public abstract boolean isCullingNeighborFaces();
public abstract boolean isFlammable();
public boolean isOccludingNeighborFaces(){
return isCullingNeighborFaces();

View File

@ -22,10 +22,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.bluecolored.bluemap.core.mca.mapping;
package de.bluecolored.bluemap.core.world;
public class BlockProperties {
public static final BlockProperties DEFAULT = new BlockProperties(false, false, false);
private final boolean culling, occluding, flammable;
public BlockProperties(boolean culling, boolean occluding, boolean flammable) {

View File

@ -180,23 +180,27 @@ public String toString() {
return getId() + "[" + sj.toString() + "]";
}
public static BlockState fromString(String serializedBlockState) {
Matcher m = BLOCKSTATE_SERIALIZATION_PATTERN.matcher(serializedBlockState);
m.find();
Map<String, String> pt = new HashMap<>();
String g2 = m.group(2);
if (g2 != null){
String[] propertyStrings = g2.trim().split(",");
for (String s : propertyStrings){
String[] kv = s.split("=", 2);
pt.put(kv[0], kv[1]);
public static BlockState fromString(String serializedBlockState) throws IllegalArgumentException {
try {
Matcher m = BLOCKSTATE_SERIALIZATION_PATTERN.matcher(serializedBlockState);
m.find();
Map<String, String> pt = new HashMap<>();
String g2 = m.group(2);
if (g2 != null){
String[] propertyStrings = g2.trim().split(",");
for (String s : propertyStrings){
String[] kv = s.split("=", 2);
pt.put(kv[0], kv[1]);
}
}
String blockId = m.group(1).trim();
return new BlockState(blockId, pt);
} catch (Exception ex) {
throw new IllegalArgumentException("'" + serializedBlockState + "' could not be parsed to a BlockState!");
}
String blockId = m.group(1).trim();
return new BlockState(blockId, pt);
}
}

View File

@ -1,130 +0,0 @@
/*
* 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.world;
import com.flowpowered.math.vector.Vector3i;
/**
* This class wraps another Block to cache all getters.<br>
* The implementation <b>can</b> use this to make sure all underlying getters are only called once and cached-data is used on the second call.
*/
public class CachedBlock extends Block {
private Block block;
private BlockState state;
private World world;
private Vector3i position;
private double sunLight, blockLight;
private Biome biome;
private boolean isCullingCached;
private boolean isCulling;
private boolean isOccludingCached;
private boolean isOccluding;
private CachedBlock(Block block) {
this.block = block;
this.state = null;
this.world = null;
this.position = null;
this.sunLight = -1;
this.blockLight = -1;
this.isCullingCached = false;
this.isCulling = false;
this.isOccludingCached = false;
this.isOccluding = false;
}
@Override
public BlockState getBlock() {
if (state == null) state = block.getBlock();
return state;
}
@Override
public World getWorld() {
if (world == null) world = block.getWorld();
return world;
}
@Override
public Vector3i getPosition() {
if (position == null) position = block.getPosition();
return position;
}
@Override
public double getSunLightLevel() {
if (sunLight == -1) sunLight = block.getSunLightLevel();
return sunLight;
}
@Override
public double getBlockLightLevel() {
if (blockLight == -1) blockLight = block.getBlockLightLevel();
return blockLight;
}
@Override
public boolean isCullingNeighborFaces() {
if (!isCullingCached){
isCulling = block.isCullingNeighborFaces();
isCullingCached = true;
}
return isCulling;
}
@Override
public boolean isOccludingNeighborFaces() {
if (!isOccludingCached){
isOccluding = block.isOccludingNeighborFaces();
isOccludingCached = true;
}
return isOccluding;
}
@Override
public Biome getBiome() {
if (biome == null){
biome = block.getBiome();
}
return biome;
}
public static CachedBlock of(Block block){
if (block instanceof CachedBlock) return (CachedBlock) block;
return new CachedBlock(block);
}
}

View File

@ -1,168 +0,0 @@
## ##
## BlueMap ##
## ##
## by Blue (Lukas Rieger) ##
## http://bluecolored.de/ ##
## ##
# !! Don't change this !!
# This is used to detect version-changes in the configuration
# and update configuration correctly.
version: "%version%"
# By changing the setting (accept-download) below to TRUE you are indicating that you have accepted mojang's EULA (https://account.mojang.com/documents/minecraft_eula),
# you confirm that you own a license to Minecraft (Java Edition)
# and you agree that BlueMap will download and use this file for you: %minecraft-client-url%
# (Alternatively you can download the file yourself and store it here: <data>/minecraft-client-%minecraft-client-version%.jar)
# This file contains resources that belong to mojang and you must not redistribute it or do anything else that is not compilant with mojang's EULA.
# BlueMap uses resources in this file to generate the 3D-Models used for the map and texture them. (BlueMap will not work without those resources.)
# %datetime-iso%
accept-download: false
# If this is true, BlueMap might send really basic metrics reports containg only the implementation-type and the version that is being used to https://metrics.bluecolored.de/bluemap/
# This allows me to track the basic usage of BlueMap and helps me stay motivated to further develop this tool! Please leave it on :)
# An example report looks like this: {"implementation":"CLI","version":"%version%"}
metrics: true
# The folder where bluemap saves data-files it needs during runtime or to save e.g. the render-progress to resume it later.
data: "data"
web {
# With this setting you can enable the integrated web-server.
enabled: false
# The webroot of the website that displays the map.
webroot: "web"
# The IP-Adress that the webserver binds to.
# If this setting is commented out, bluemap tries to find the default ip-adress of your system.
# If you only want to access it locally use "localhost".
#ip: "localhost"
#ip: "127.0.0.1"
# The port that the webserver listenes to.
# Default is 8100
port: 8100
# Max number of simultaneous connections that the webserver allows
# Default is 100
maxConnectionCount: 100
# Unncomment this to override the path where bluemap stores the data-files.
# Default is "<webroot>/data"
#web-data: "path/to/data/folder"
}
# This changes the amount of threads that BlueMap will use to render the maps.
# A higher value can improve render-speed but could impact performance on the host machine.
# This should be always below or equal to the number of available processor-cores.
# If this value is commented out BlueMap tries to find the optimal thread count to max out render-performance
#renderThreadCount: 2
# This is an array with multiple configured maps.
# You can define multiple maps, for different worlds with different render-settings here
maps: [
{
# The id of this map
# Should only contain word-charactes: [a-zA-Z0-9_]
id: "world"
# 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: "World"
# The path to the save-folder of the world to render
world: "world"
# If this is false, BlueMap tries to omit all blocks that 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.
# Default is false
renderCaves: false
# AmbientOcclusion adds soft shadows into corners, which gives the map a much better look.
# This has only a small impact on render-time and has no impact on the web-performance of the map.
# The value defines the strength of the shading, a value of 0 disables ambientOcclusion.
# Default is 0.25
ambientOcclusion: 0.25
# Lighting uses the light-data in minecraft to shade each block-face.
# If this is enabled, caves and inside buildings without torches will be darker.
# The value defines the strength of the shading and a value of 0 disables lighting (every block will be fully lit).
# Default is 0.8
lighting: 0.8
# Using this, BlueMap pretends that every Block above the defined value is AIR.
# Default is disabled
#sliceY: 90
# With the below values you can just not render blocks at certain heights.
# This can be used to ignore the nethers ceiling.
# Default is no min or max y value
#minY: 50
#maxY: 126
# HIRES is the high-resolution render of the map. Where you see every block.
hires {
# Defines the size of one map-tile in blocks.
# If you change this value, the lowres values might need adjustment as well!
# Default is 32
tileSize: 32
# The View-Distance for hires tiles on the web-map (the value is the radius in tiles)
# Default is 3.5
viewDistance: 3.5
}
# LOWRES is the low-resolution render of the map. THats the model that you see if you zoom far out to get an overview.
lowres {
# Defines resolution of the lowres model. E.g. If the hires.tileSize is 32, a value of 4 means that every 8*8 blocks will be summarized by one point on the lowres map.
# Calculation: 32 / 4 = 8
# You can only use values that result in an integer if you use the above calculation!
# Default is 4
pointsPerHiresTile: 4
# Defines the size of one lowres-map-tile in points.
# Default is 50
pointsPerLowresTile: 50
# The View-Distance for lowres tiles on the web-map (the value is the radius in tiles)
# Default is 4
viewDistance: 4
}
}
# Here another example for the End-Map
# Things we dont want to change from default we can just omit
{
id: "end"
name: "End"
world: "world/DIM1"
# In the end is no light, so we need to enable this or we don't see anything.
renderCaves: true
# Same here, we don't want a dark map. But not completely disabled, so we see the effect of e.g torches.
lighting: 0.4
}
# Here another example for the Nether-Map
{
id: "nether"
name: "Nether"
world: "world/DIM-1"
renderCaves: true
lighting: 0.6
# We slice the whole world at y:90 so evrery block above 90 will be air.
# This way we dont render the nethers ceiling.
sliceY: 90
# Instead of slicing we also could do this, that would look like an x-ray view through the ceiling.
#maxY: 126
}
]

View File

@ -30,6 +30,7 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
@ -60,9 +61,9 @@
import com.flowpowered.math.vector.Vector2i;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.config.Configuration;
import de.bluecolored.bluemap.core.config.Configuration.MapConfig;
import de.bluecolored.bluemap.core.config.ConfigurationFile;
import de.bluecolored.bluemap.core.config.ConfigManager;
import de.bluecolored.bluemap.core.config.MainConfig;
import de.bluecolored.bluemap.core.config.MainConfig.MapConfig;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.mca.MCAWorld;
import de.bluecolored.bluemap.core.metrics.Metrics;
@ -101,7 +102,7 @@ public class SpongePlugin {
@Inject
private MetricsLite2 metrics;
private Configuration config;
private MainConfig config;
private ResourcePack resourcePack;
private Map<UUID, World> worlds;
@ -131,8 +132,10 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
unload(); //ensure nothing is left running (from a failed load or something)
//load configs
File configFile = getConfigPath().resolve("bluemap.conf").toFile();
config = ConfigurationFile.loadOrCreate(configFile, SpongePlugin.class.getResource("/bluemap-sponge.conf")).getConfig();
URL defaultSpongeConfig = SpongePlugin.class.getResource("/bluemap-sponge.conf");
URL spongeConfigDefaults = SpongePlugin.class.getResource("/bluemap-sponge-defaults.conf");
ConfigManager configManager = new ConfigManager(getConfigPath().toFile(), defaultSpongeConfig, spongeConfigDefaults);
config = configManager.getMainConfig();
File blockColorsConfigFile = getConfigPath().resolve("blockColors.json").toFile();
if (!blockColorsConfigFile.exists()) {
@ -145,7 +148,7 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
File textureExportFile = config.getWebDataPath().resolve("textures.json").toFile();
if (!defaultResourceFile.exists()) {
handleMissingResources(defaultResourceFile, configFile);
handleMissingResources(defaultResourceFile, configManager.getMainConfigFile());
unload();
Sponge.getCommandManager().register(this, new Commands(this).createStandaloneReloadCommand(), "bluemap");
@ -198,7 +201,7 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
World world = worlds.get(worldUUID);
if (world == null) {
try {
world = MCAWorld.load(worldFolder.toPath(), worldUUID);
world = MCAWorld.load(worldFolder.toPath(), worldUUID, configManager.getBlockIdConfig(), configManager.getBlockPropertiesConfig(), configManager.getBiomeConfig());
worlds.put(worldUUID, world);
} catch (IOException e) {
Logger.global.logError("Failed to load map '" + id + "': Failed to read level.dat", e);
@ -258,6 +261,7 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
webSettings.setFrom(map.getTileRenderer(), map.getId());
}
for (MapConfig map : config.getMapConfigs()) {
if (!maps.containsKey(map.getId())) continue; //don't add not loaded maps
webSettings.setHiresViewDistance(map.getHiresViewDistance(), map.getId());
webSettings.setLowresViewDistance(map.getLowresViewDistance(), map.getId());
}
@ -378,7 +382,7 @@ public void onServerReload(GameReloadEvent evt) {
});
}
private void handleMissingResources(File resourceFile, File configFile) {
private void handleMissingResources(File resourceFile, File mainConfigFile) {
if (config.isDownloadAccepted()) {
//download file async
@ -405,7 +409,7 @@ private void handleMissingResources(File resourceFile, File configFile) {
} else {
Logger.global.logWarning("BlueMap is missing important resources!");
Logger.global.logWarning("You need to accept the download of the required files in order of BlueMap to work!");
Logger.global.logWarning("Please check: " + configFile);
Logger.global.logWarning("Please check: " + mainConfigFile);
Logger.global.logInfo("If you have changed the config you can simply reload the plugin using: /bluemap reload");
}
}

View File

@ -0,0 +1,9 @@
accept-download: false
metrics: false
data: "bluemap"
web {
enabled: true
webroot: "bluemap/web"
port: 8100
maxConnectionCount: 100
}