Add render configuration to the core

This commit is contained in:
Blue (Lukas Rieger) 2019-11-02 17:44:37 +01:00
parent 7c1221552c
commit 987cc5a01b
2 changed files with 441 additions and 0 deletions

View File

@ -0,0 +1,289 @@
/*
* 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.InetAddress;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.io.FileUtils;
import com.google.common.base.Preconditions;
import de.bluecolored.bluemap.core.render.RenderSettings;
import de.bluecolored.bluemap.core.web.WebServerConfig;
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 implements WebServerConfig {
private String configVersion;
private boolean webserverEnabled;
private int webserverPort;
private int webserverMaxConnections;
private InetAddress webserverBindAdress;
private Path webRoot;
private Path webDataPath;
private int renderThreadCount;
private Collection<MapConfig> mapConfigs;
private ConfigurationFile(File configFile) throws IOException {
ConfigurationLoader<CommentedConfigurationNode> configLoader = HoconConfigurationLoader.builder()
.setFile(configFile)
.build();
CommentedConfigurationNode rootNode = configLoader.load();
configVersion = rootNode.getNode("version").getString("-");
loadWebConfig(rootNode.getNode("web"));
int defaultCount = (int) Math.max(Math.min((double) Runtime.getRuntime().availableProcessors() * 0.75, 16), 1);
renderThreadCount = rootNode.getNode("renderThreadCount").getInt(defaultCount);
if (renderThreadCount <= 0) renderThreadCount = defaultCount;
loadMapConfigs(rootNode.getNode("maps"));
}
private void loadWebConfig(ConfigurationNode node) throws IOException {
webserverEnabled = node.getNode("enabled").getBoolean(false);
String webRootString = node.getNode("webroot").getString();
if (webserverEnabled && webRootString == null) throw new IOException("Invalid configuration: Node web.webroot is not defined");
webRoot = toFolder(webRootString);
if (webserverEnabled) {
webserverPort = node.getNode("port").getInt(8100);
webserverMaxConnections = node.getNode("maxConnectionCount").getInt(100);
String webserverBindAdressString = node.getNode("ip").getString("");
if (webserverBindAdressString.isEmpty()) {
webserverBindAdress = InetAddress.getLocalHost();
} else {
webserverBindAdress = InetAddress.getByName(webserverBindAdressString);
}
}
String webDataString = node.getNode("data").getString();
if (webDataString != null)
webDataPath = toFolder(webDataString);
else if (webRoot != null)
webDataPath = webRoot.resolve("data");
else
throw new IOException("Invalid configuration: Node web.data is not defined in config");
}
private void loadMapConfigs(ConfigurationNode node) throws IOException {
mapConfigs = new ArrayList<>();
for (ConfigurationNode mapConfigNode : node.getChildrenList()) {
mapConfigs.add(new MapConfig(mapConfigNode));
}
}
public boolean isWebserverEnabled() {
return webserverEnabled;
}
public Path getWebDataPath() {
return webDataPath;
}
@Override
public int getWebserverPort() {
return webserverPort;
}
@Override
public int getWebserverMaxConnections() {
return webserverMaxConnections;
}
@Override
public InetAddress getWebserverBindAdress() {
return webserverBindAdress;
}
@Override
public Path getWebRoot() {
return webRoot;
}
public String getConfigVersion() {
return configVersion;
}
public int getRenderThreadCount() {
return renderThreadCount;
}
public Collection<MapConfig> getMapConfigs(){
return mapConfigs;
}
private Path toFolder(String pathString) throws IOException {
Preconditions.checkNotNull(pathString);
File file = new File(pathString);
if (file.exists() && !file.isDirectory()) throw new IOException("Invalid configuration: Path '" + file.getAbsolutePath() + "' is a file (should be a directory)");
if (!file.exists() && !file.mkdirs()) throw new IOException("Invalid configuration: Folders to path '" + file.getAbsolutePath() + "' could not be created");
return file.toPath();
}
public static ConfigurationFile loadOrCreate(File configFile) throws IOException {
if (!configFile.exists()) {
configFile.getParentFile().mkdirs();
FileUtils.copyURLToFile(ConfigurationFile.class.getResource("/bluemap.conf"), configFile, 10000, 10000);
}
return new ConfigurationFile(configFile);
}
public class MapConfig implements RenderSettings {
private String id;
private String name;
private String world;
private boolean renderCaves;
private float ambientOcclusion;
private float lighting;
private int maxY, minY, sliceY;
private int hiresTileSize;
private float hiresViewDistance;
private int lowresPointsPerHiresTile;
private int lowresPointsPerLowresTile;
private float lowresViewDistance;
private MapConfig(ConfigurationNode node) throws IOException {
this.id = node.getNode("id").getString("");
if (id.isEmpty()) throw new IOException("Invalid configuration: Node maps[?].id is not defined");
this.name = node.getNode("name").getString(id);
this.world = node.getNode("world").getString("");
if (world.isEmpty()) throw new IOException("Invalid configuration: Node maps[?].world is not defined");
this.renderCaves = node.getNode("renderCaves").getBoolean(false);
this.ambientOcclusion = node.getNode("ambientOcclusion").getFloat(0.25f);
this.lighting = node.getNode("lighting").getFloat(0.8f);
this.maxY = node.getNode("maxY").getInt(RenderSettings.super.getMaxY());
this.minY = node.getNode("minY").getInt(RenderSettings.super.getMinY());
this.sliceY = node.getNode("sliceY").getInt(RenderSettings.super.getSliceY());
this.hiresTileSize = node.getNode("hires", "tileSize").getInt(32);
this.hiresViewDistance = node.getNode("hires", "viewDistance").getFloat(3.5f);
this.lowresPointsPerHiresTile = node.getNode("lowres", "pointsPerHiresTile").getInt(4);
this.lowresPointsPerLowresTile = node.getNode("lowres", "pointsPerLowresTile").getInt(50);
this.lowresViewDistance = node.getNode("lowres", "viewDistance").getFloat(4f);
//check valid configuration values
double blocksPerPoint = (double) this.hiresTileSize / (double) this.lowresPointsPerHiresTile;
if (blocksPerPoint != Math.floor(blocksPerPoint)) throw new IOException("Invalid configuration: Invalid map resolution settings of map " + id + ": hires.tileSize / lowres.pointsPerTile has to be an integer result");
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getWorldId() {
return world;
}
public boolean isRenderCaves() {
return renderCaves;
}
@Override
public float getAmbientOcclusionStrenght() {
return ambientOcclusion;
}
@Override
public float getLightShadeMultiplier() {
return lighting;
}
public int getHiresTileSize() {
return hiresTileSize;
}
public float getHiresViewDistance() {
return hiresViewDistance;
}
public int getLowresPointsPerHiresTile() {
return lowresPointsPerHiresTile;
}
public int getLowresPointsPerLowresTile() {
return lowresPointsPerLowresTile;
}
public float getLowresViewDistance() {
return lowresViewDistance;
}
@Override
public boolean isExcludeFacesWithoutSunlight() {
return !isRenderCaves();
}
@Override
public int getMaxY() {
return maxY;
}
@Override
public int getMinY() {
return minY;
}
@Override
public int getSliceY() {
return sliceY;
}
}
}

View File

@ -0,0 +1,152 @@
## ##
## 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: "1.0.0"
web {
# With this setting you can disable the web-server.
# This is usefull if you want to only render the map-data for later use, or if you setup your own webserver.
enabled: true
# The webroot of the website that displays the map.
webroot: "bluemap/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"
#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
}
]