mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-12-27 11:27:39 +01:00
Add some more resources-compatibility and tweak some values in configs and colors
This commit is contained in:
parent
22c2772c70
commit
c60a62a6cd
@ -64,6 +64,7 @@
|
||||
import de.bluecolored.bluemap.core.resourcepack.ParseResourceException;
|
||||
import de.bluecolored.bluemap.core.resourcepack.ResourcePack;
|
||||
import de.bluecolored.bluemap.core.web.BlueMapWebServer;
|
||||
import de.bluecolored.bluemap.core.web.WebFilesManager;
|
||||
import de.bluecolored.bluemap.core.web.WebSettings;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
@ -192,7 +193,6 @@ public void startWebserver() throws IOException {
|
||||
Logger.global.logInfo("Starting webserver...");
|
||||
|
||||
BlueMapWebServer webserver = new BlueMapWebServer(configManager.getMainConfig());
|
||||
webserver.updateWebfiles();
|
||||
webserver.start();
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ private boolean loadResources() throws IOException, ParseResourceException {
|
||||
private boolean handleMissingResources(File resourceFile) {
|
||||
if (configManager.getMainConfig().isDownloadAccepted()) {
|
||||
try {
|
||||
Logger.global.logInfo("Downloading " + ResourcePack.MINECRAFT_CLIENT_URL + " to " + resourceFile + " ...");
|
||||
Logger.global.logInfo("Downloading " + ResourcePack.MINECRAFT_CLIENT_URL + " to " + resourceFile.getCanonicalPath() + " ...");
|
||||
ResourcePack.downloadDefaultResource(resourceFile);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
@ -286,6 +286,12 @@ public static void main(String[] args) throws IOException, ParseResourceExceptio
|
||||
return;
|
||||
}
|
||||
|
||||
WebFilesManager webFilesManager = new WebFilesManager(config.getMainConfig().getWebRoot());
|
||||
if (webFilesManager.needsUpdate()) {
|
||||
Logger.global.logInfo("Updating webfiles in " + config.getMainConfig().getWebRoot().normalize() + "...");
|
||||
webFilesManager.updateFiles();
|
||||
}
|
||||
|
||||
BlueMapCLI bluemap = new BlueMapCLI(config, configFolder, cmd.hasOption("f"));
|
||||
|
||||
if (config.getMainConfig().isWebserverEnabled()) {
|
||||
@ -352,7 +358,7 @@ private static void printHelp() {
|
||||
|
||||
if (file.isFile()) {
|
||||
try {
|
||||
filename = "." + File.separator + new File("").getAbsoluteFile().toPath().relativize(file.toPath()).toString();
|
||||
filename = "." + File.separator + new File("").getCanonicalFile().toPath().relativize(file.toPath()).toString();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
filename = file.getAbsolutePath();
|
||||
}
|
||||
|
@ -7,3 +7,4 @@ web {
|
||||
port: 8100
|
||||
maxConnectionCount: 100
|
||||
}
|
||||
renderThreadCount: 0
|
||||
|
@ -56,8 +56,10 @@ web {
|
||||
# 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
|
||||
# Zero or a negative value means the amount of of available processor-cores subtracted by the value.
|
||||
# (So a value of -2 with 6 cores results in 4 render-processes)
|
||||
# Default is 0
|
||||
renderThreadCount: 0
|
||||
|
||||
# This is an array with multiple configured maps.
|
||||
# You can define multiple maps, for different worlds with different render-settings here
|
||||
@ -112,8 +114,8 @@ maps: [
|
||||
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
|
||||
# Default is 4.5
|
||||
viewDistance: 4.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.
|
||||
@ -129,8 +131,8 @@ maps: [
|
||||
pointsPerLowresTile: 50
|
||||
|
||||
# The View-Distance for lowres tiles on the web-map (the value is the radius in tiles)
|
||||
# Default is 4
|
||||
viewDistance: 4
|
||||
# Default is 7
|
||||
viewDistance: 7
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,9 +68,10 @@ public MainConfig(ConfigurationNode node) throws IOException {
|
||||
|
||||
loadWebConfig(node.getNode("web"));
|
||||
|
||||
int defaultCount = Runtime.getRuntime().availableProcessors();
|
||||
renderThreadCount = node.getNode("renderThreadCount").getInt(defaultCount);
|
||||
if (renderThreadCount <= 0) renderThreadCount = defaultCount;
|
||||
int processors = Runtime.getRuntime().availableProcessors();
|
||||
renderThreadCount = node.getNode("renderThreadCount").getInt(0);
|
||||
if (renderThreadCount <= 0) renderThreadCount = processors + renderThreadCount;
|
||||
if (renderThreadCount <= 0) renderThreadCount = 1;
|
||||
|
||||
loadMapConfigs(node.getNode("maps"));
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ public BlockStateModel build(BlockState blockState, BlockModelResource bmr) {
|
||||
|
||||
int level = getLiquidLevel(blockState);
|
||||
float[] heights = new float[]{16f, 16f, 16f, 16f};
|
||||
float coloralpha = 0.2f;
|
||||
|
||||
if (level < 8 && !(level == 0 && isLiquid(context.getRelativeBlock(0, 1, 0)))){
|
||||
heights = new float[]{
|
||||
@ -80,6 +81,8 @@ public BlockStateModel build(BlockState blockState, BlockModelResource bmr) {
|
||||
getLiquidCornerHeight(0, 0, -1),
|
||||
getLiquidCornerHeight(0, 0, 0)
|
||||
};
|
||||
|
||||
coloralpha = 0.8f;
|
||||
}
|
||||
|
||||
BlockStateModel model = new BlockStateModel();
|
||||
@ -114,7 +117,7 @@ public BlockStateModel build(BlockState blockState, BlockModelResource bmr) {
|
||||
|
||||
//calculate mapcolor
|
||||
Vector4f mapcolor = texture.getColor();
|
||||
mapcolor = mapcolor.mul(tintcolor.toVector4(0.5));
|
||||
mapcolor = mapcolor.mul(tintcolor.toVector4(coloralpha));
|
||||
model.setMapColor(mapcolor);
|
||||
|
||||
return model;
|
||||
|
@ -31,6 +31,7 @@
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -213,6 +214,8 @@ public static Builder builder(FileAccess sourcesAccess, ResourcePack resourcePac
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private static final String JSON_COMMENT = "__comment";
|
||||
|
||||
private FileAccess sourcesAccess;
|
||||
private ResourcePack resourcePack;
|
||||
@ -227,7 +230,12 @@ private Builder(FileAccess sourcesAccess, ResourcePack resourcePack) {
|
||||
}
|
||||
|
||||
public synchronized BlockModelResource build(String modelPath) throws IOException, ParseResourceException {
|
||||
textures.clear();
|
||||
return build(modelPath, Collections.emptyMap());
|
||||
}
|
||||
|
||||
public synchronized BlockModelResource build(String modelPath, Map<String, String> textures) throws IOException, ParseResourceException {
|
||||
this.textures.clear();
|
||||
this.textures.putAll(textures);
|
||||
return buildNoReset(modelPath, true, modelPath);
|
||||
}
|
||||
|
||||
@ -239,6 +247,8 @@ private BlockModelResource buildNoReset(String modelPath, boolean renderElements
|
||||
.load();
|
||||
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : config.getNode("textures").getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
|
||||
textures.putIfAbsent(entry.getKey().toString(), entry.getValue().getString(null));
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,9 @@
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -39,6 +41,7 @@
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.resourcepack.PropertyCondition.All;
|
||||
import de.bluecolored.bluemap.core.resourcepack.fileaccess.FileAccess;
|
||||
import de.bluecolored.bluemap.core.util.MathUtils;
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
@ -46,113 +49,138 @@
|
||||
import ninja.leaping.configurate.gson.GsonConfigurationLoader;
|
||||
|
||||
public class BlockStateResource {
|
||||
|
||||
|
||||
private List<Variant> variants = new ArrayList<>();
|
||||
private Collection<Variant> multipart = new ArrayList<>();
|
||||
|
||||
private BlockStateResource() {}
|
||||
|
||||
public Collection<TransformedBlockModelResource> getModels(BlockState blockState){
|
||||
|
||||
private BlockStateResource() {
|
||||
}
|
||||
|
||||
public Collection<TransformedBlockModelResource> getModels(BlockState blockState) {
|
||||
return getModels(blockState, Vector3i.ZERO);
|
||||
}
|
||||
|
||||
public Collection<TransformedBlockModelResource> getModels(BlockState blockState, Vector3i pos){
|
||||
|
||||
public Collection<TransformedBlockModelResource> getModels(BlockState blockState, Vector3i pos) {
|
||||
Collection<TransformedBlockModelResource> models = new ArrayList<>();
|
||||
|
||||
Variant allMatch = null;
|
||||
for (Variant variant : variants) {
|
||||
if (variant.condition.matches(blockState)) {
|
||||
if (variant.condition instanceof All) { //only use "all" conditioned if nothing else matched
|
||||
if (allMatch == null) allMatch = variant;
|
||||
continue;
|
||||
}
|
||||
|
||||
models.add(variant.getModel(pos));
|
||||
return models;
|
||||
}
|
||||
}
|
||||
|
||||
if (allMatch != null) {
|
||||
models.add(allMatch.getModel(pos));
|
||||
return models;
|
||||
}
|
||||
|
||||
for (Variant variant : multipart) {
|
||||
if (variant.condition.matches(blockState)) {
|
||||
models.add(variant.getModel(pos));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
|
||||
private class Variant {
|
||||
|
||||
|
||||
private PropertyCondition condition = PropertyCondition.all();
|
||||
private Collection<Weighted<TransformedBlockModelResource>> models = new ArrayList<>();
|
||||
|
||||
|
||||
private double totalWeight;
|
||||
|
||||
private Variant() {}
|
||||
|
||||
|
||||
private Variant() {
|
||||
}
|
||||
|
||||
public TransformedBlockModelResource getModel(Vector3i pos) {
|
||||
double selection = MathUtils.hashToFloat(pos, 827364) * totalWeight; //random based on position
|
||||
double selection = MathUtils.hashToFloat(pos, 827364) * totalWeight; // random based on position
|
||||
for (Weighted<TransformedBlockModelResource> w : models) {
|
||||
selection -= w.weight;
|
||||
if (selection < 0) return w.value;
|
||||
if (selection < 0)
|
||||
return w.value;
|
||||
}
|
||||
|
||||
|
||||
throw new RuntimeException("This line should never be reached!");
|
||||
}
|
||||
|
||||
|
||||
public void updateTotalWeight() {
|
||||
totalWeight = 0d;
|
||||
for (Weighted<?> w : models) {
|
||||
totalWeight += w.weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class Weighted<T> {
|
||||
|
||||
|
||||
private T value;
|
||||
private double weight;
|
||||
|
||||
|
||||
public Weighted(T value, double weight) {
|
||||
this.value = value;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static Builder builder(FileAccess sourcesAccess, ResourcePack resourcePack) {
|
||||
return new Builder(sourcesAccess, resourcePack);
|
||||
}
|
||||
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private static final String JSON_COMMENT = "__comment";
|
||||
|
||||
private final FileAccess sourcesAccess;
|
||||
private final ResourcePack resourcePack;
|
||||
|
||||
|
||||
private Builder(FileAccess sourcesAccess, ResourcePack resourcePack) {
|
||||
this.sourcesAccess = sourcesAccess;
|
||||
this.resourcePack = resourcePack;
|
||||
}
|
||||
|
||||
|
||||
public BlockStateResource build(String blockstateFile) throws IOException {
|
||||
BlockStateResource blockState = new BlockStateResource();
|
||||
ConfigurationNode config = GsonConfigurationLoader.builder()
|
||||
.setSource(() -> new BufferedReader(new InputStreamReader(sourcesAccess.readFile(blockstateFile), StandardCharsets.UTF_8)))
|
||||
.build()
|
||||
.load();
|
||||
|
||||
//create variants
|
||||
.setSource(() -> new BufferedReader(
|
||||
new InputStreamReader(sourcesAccess.readFile(blockstateFile), StandardCharsets.UTF_8)))
|
||||
.build().load();
|
||||
|
||||
if (!config.getNode("forge_marker").isVirtual()) {
|
||||
return buildForge(config, blockstateFile);
|
||||
}
|
||||
|
||||
BlockStateResource blockState = new BlockStateResource();
|
||||
|
||||
// create variants
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : config.getNode("variants").getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
|
||||
try {
|
||||
String conditionString = entry.getKey().toString();
|
||||
ConfigurationNode transformedModelNode = entry.getValue();
|
||||
|
||||
|
||||
Variant variant = blockState.new Variant();
|
||||
variant.condition = parseConditionString(conditionString);
|
||||
variant.models = loadModels(transformedModelNode, blockstateFile);
|
||||
|
||||
variant.models = loadModels(transformedModelNode, blockstateFile, null);
|
||||
|
||||
variant.updateTotalWeight();
|
||||
|
||||
|
||||
blockState.variants.add(variant);
|
||||
} catch (Exception ex) {
|
||||
Logger.global.logWarning("Failed to parse a variant of " + blockstateFile + ": " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
//create multipart
|
||||
|
||||
// create multipart
|
||||
for (ConfigurationNode partNode : config.getNode("multipart").getChildrenList()) {
|
||||
try {
|
||||
Variant variant = blockState.new Variant();
|
||||
@ -160,64 +188,64 @@ public BlockStateResource build(String blockstateFile) throws IOException {
|
||||
if (!whenNode.isVirtual()) {
|
||||
variant.condition = parseCondition(whenNode);
|
||||
}
|
||||
variant.models = loadModels(partNode.getNode("apply"), blockstateFile);
|
||||
|
||||
variant.models = loadModels(partNode.getNode("apply"), blockstateFile, null);
|
||||
|
||||
variant.updateTotalWeight();
|
||||
|
||||
|
||||
blockState.multipart.add(variant);
|
||||
} catch (Exception ex) {
|
||||
Logger.global.logWarning("Failed to parse a multipart-part of " + blockstateFile + ": " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return blockState;
|
||||
}
|
||||
|
||||
private Collection<Weighted<TransformedBlockModelResource>> loadModels(ConfigurationNode node, String blockstateFile) {
|
||||
|
||||
private Collection<Weighted<TransformedBlockModelResource>> loadModels(ConfigurationNode node, String blockstateFile, Map<String, String> overrideTextures) {
|
||||
Collection<Weighted<TransformedBlockModelResource>> models = new ArrayList<>();
|
||||
|
||||
|
||||
if (node.hasListChildren()) {
|
||||
for (ConfigurationNode modelNode : node.getChildrenList()) {
|
||||
try {
|
||||
models.add(loadModel(modelNode));
|
||||
models.add(loadModel(modelNode, overrideTextures));
|
||||
} catch (ParseResourceException ex) {
|
||||
Logger.global.logWarning("Failed to load a model trying to parse " + blockstateFile + ": " + ex);
|
||||
}
|
||||
}
|
||||
} else if (node.hasMapChildren()) {
|
||||
try {
|
||||
models.add(loadModel(node));
|
||||
models.add(loadModel(node, overrideTextures));
|
||||
} catch (ParseResourceException ex) {
|
||||
Logger.global.logWarning("Failed to load a model trying to parse " + blockstateFile + ": " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
private Weighted<TransformedBlockModelResource> loadModel(ConfigurationNode node) throws ParseResourceException {
|
||||
String modelPath = node.getNode("model").getString();
|
||||
if (modelPath == null) throw new ParseResourceException("No model defined!");
|
||||
|
||||
modelPath = ResourcePack.namespacedToAbsoluteResourcePath(modelPath, "models") + ".json";
|
||||
|
||||
|
||||
private Weighted<TransformedBlockModelResource> loadModel(ConfigurationNode node, Map<String, String> overrideTextures) throws ParseResourceException {
|
||||
String namespacedModelPath = node.getNode("model").getString();
|
||||
if (namespacedModelPath == null)
|
||||
throw new ParseResourceException("No model defined!");
|
||||
|
||||
String modelPath = ResourcePack.namespacedToAbsoluteResourcePath(namespacedModelPath, "models") + ".json";
|
||||
|
||||
BlockModelResource model = resourcePack.blockModelResources.get(modelPath);
|
||||
if (model == null) {
|
||||
BlockModelResource.Builder builder = BlockModelResource.builder(sourcesAccess, resourcePack);
|
||||
try {
|
||||
model = BlockModelResource.builder(sourcesAccess, resourcePack).build(modelPath);
|
||||
if (overrideTextures != null) model = builder.build(modelPath, overrideTextures);
|
||||
else model = builder.build(modelPath);
|
||||
} catch (IOException e) {
|
||||
throw new ParseResourceException("Failed to load model " + modelPath, e);
|
||||
}
|
||||
|
||||
|
||||
resourcePack.blockModelResources.put(modelPath, model);
|
||||
}
|
||||
|
||||
Vector2i rotation = new Vector2i(
|
||||
node.getNode("x").getInt(0),
|
||||
node.getNode("y").getInt(0)
|
||||
);
|
||||
|
||||
Vector2i rotation = new Vector2i(node.getNode("x").getInt(0), node.getNode("y").getInt(0));
|
||||
boolean uvLock = node.getNode("uvlock").getBoolean(false);
|
||||
|
||||
|
||||
TransformedBlockModelResource transformedModel = new TransformedBlockModelResource(rotation, uvLock, model);
|
||||
return new Weighted<TransformedBlockModelResource>(transformedModel, node.getNode("weight").getDouble(1d));
|
||||
}
|
||||
@ -226,32 +254,36 @@ private PropertyCondition parseCondition(ConfigurationNode conditionNode) {
|
||||
List<PropertyCondition> andConditions = new ArrayList<>();
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : conditionNode.getChildrenMap().entrySet()) {
|
||||
String key = entry.getKey().toString();
|
||||
if (key.equals(JSON_COMMENT)) continue;
|
||||
|
||||
if (key.equals("OR")) {
|
||||
List<PropertyCondition> orConditions = new ArrayList<>();
|
||||
for (ConfigurationNode orConditionNode : entry.getValue().getChildrenList()) {
|
||||
orConditions.add(parseCondition(orConditionNode));
|
||||
}
|
||||
andConditions.add(PropertyCondition.or(orConditions.toArray(new PropertyCondition[orConditions.size()])));
|
||||
andConditions.add(
|
||||
PropertyCondition.or(orConditions.toArray(new PropertyCondition[orConditions.size()])));
|
||||
} else {
|
||||
String[] values = StringUtils.split(entry.getValue().getString(""), '|');
|
||||
andConditions.add(PropertyCondition.property(key, values));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return PropertyCondition.and(andConditions.toArray(new PropertyCondition[andConditions.size()]));
|
||||
}
|
||||
|
||||
|
||||
private PropertyCondition parseConditionString(String conditionString) throws IllegalArgumentException {
|
||||
List<PropertyCondition> conditions = new ArrayList<>();
|
||||
if (!conditionString.isEmpty() && !conditionString.equals("default") && !conditionString.equals("normal")) {
|
||||
String[] conditionSplit = StringUtils.split(conditionString, ',');
|
||||
for (String element : conditionSplit) {
|
||||
String[] keyval = StringUtils.split(element, "=", 2);
|
||||
if (keyval.length < 2) throw new IllegalArgumentException("Condition-String '" + conditionString + "' is invalid!");
|
||||
if (keyval.length < 2)
|
||||
throw new IllegalArgumentException("Condition-String '" + conditionString + "' is invalid!");
|
||||
conditions.add(PropertyCondition.property(keyval[0], keyval[1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PropertyCondition condition;
|
||||
if (conditions.isEmpty()) {
|
||||
condition = PropertyCondition.all();
|
||||
@ -260,8 +292,129 @@ private PropertyCondition parseConditionString(String conditionString) throws Il
|
||||
} else {
|
||||
condition = PropertyCondition.and(conditions.toArray(new PropertyCondition[conditions.size()]));
|
||||
}
|
||||
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
private BlockStateResource buildForge(ConfigurationNode config, String blockstateFile) {
|
||||
ConfigurationNode modelDefaults = config.getNode("defaults");
|
||||
|
||||
List<ForgeVariant> variants = new ArrayList<>();
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : config.getNode("variants").getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
if (isForgeStraightVariant(entry.getValue())) continue;
|
||||
|
||||
// create variants for single property
|
||||
List<ForgeVariant> propertyVariants = new ArrayList<>();
|
||||
String key = entry.getKey().toString();
|
||||
for (Entry<Object, ? extends ConfigurationNode> value : entry.getValue().getChildrenMap().entrySet()) {
|
||||
if (value.getKey().equals(JSON_COMMENT)) continue;
|
||||
|
||||
ForgeVariant variant = new ForgeVariant();
|
||||
variant.properties.put(key, value.getKey().toString());
|
||||
variant.node = value.getValue();
|
||||
propertyVariants.add(variant);
|
||||
}
|
||||
|
||||
// join variants
|
||||
List<ForgeVariant> oldVariants = variants;
|
||||
variants = new ArrayList<>(oldVariants.size() * propertyVariants.size());
|
||||
for (ForgeVariant oldVariant : oldVariants) {
|
||||
for (ForgeVariant addVariant : propertyVariants) {
|
||||
variants.add(oldVariant.createMerge(addVariant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//create all possible property-variants
|
||||
BlockStateResource blockState = new BlockStateResource();
|
||||
for (ForgeVariant forgeVariant : variants) {
|
||||
Variant variant = blockState.new Variant();
|
||||
|
||||
ConfigurationNode modelNode = forgeVariant.node.mergeValuesFrom(modelDefaults);
|
||||
|
||||
Map<String, String> textures = new HashMap<>();
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : modelNode.getNode("textures").getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
|
||||
textures.putIfAbsent(entry.getKey().toString(), entry.getValue().getString(null));
|
||||
}
|
||||
|
||||
List<PropertyCondition> conditions = new ArrayList<>(forgeVariant.properties.size());
|
||||
for (Entry<String, String> property : forgeVariant.properties.entrySet()) {
|
||||
conditions.add(PropertyCondition.property(property.getKey(), property.getValue()));
|
||||
}
|
||||
variant.condition = PropertyCondition.and(conditions.toArray(new PropertyCondition[conditions.size()]));
|
||||
|
||||
variant.models.addAll(loadModels(modelNode, blockstateFile, textures));
|
||||
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : modelNode.getNode("submodel").getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
|
||||
variant.models.addAll(loadModels(entry.getValue(), blockstateFile, textures));
|
||||
}
|
||||
|
||||
variant.updateTotalWeight();
|
||||
blockState.variants.add(variant);
|
||||
}
|
||||
|
||||
//create default straight variant
|
||||
ConfigurationNode normalNode = config.getNode("variants", "normal");
|
||||
if (normalNode.isVirtual() || isForgeStraightVariant(normalNode)) {
|
||||
normalNode.mergeValuesFrom(modelDefaults);
|
||||
|
||||
Map<String, String> textures = new HashMap<>();
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : normalNode.getNode("textures").getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
|
||||
textures.putIfAbsent(entry.getKey().toString(), entry.getValue().getString(null));
|
||||
}
|
||||
|
||||
Variant variant = blockState.new Variant();
|
||||
variant.condition = PropertyCondition.all();
|
||||
variant.models.addAll(loadModels(normalNode, blockstateFile, textures));
|
||||
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : normalNode.getNode("submodel").getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
|
||||
variant.models.addAll(loadModels(entry.getValue(), blockstateFile, textures));
|
||||
}
|
||||
|
||||
variant.updateTotalWeight();
|
||||
blockState.variants.add(variant);
|
||||
}
|
||||
|
||||
return blockState;
|
||||
}
|
||||
|
||||
private boolean isForgeStraightVariant(ConfigurationNode node) {
|
||||
if (node.hasListChildren())
|
||||
return true;
|
||||
|
||||
for (Entry<Object, ? extends ConfigurationNode> entry : node.getChildrenMap().entrySet()) {
|
||||
if (entry.getKey().equals(JSON_COMMENT)) continue;
|
||||
if (!entry.getValue().hasMapChildren()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private class ForgeVariant {
|
||||
public Map<String, String> properties = new HashMap<>();
|
||||
public ConfigurationNode node = GsonConfigurationLoader.builder().build().createEmptyNode();
|
||||
|
||||
public ForgeVariant createMerge(ForgeVariant other) {
|
||||
ForgeVariant merge = new ForgeVariant();
|
||||
|
||||
merge.properties.putAll(this.properties);
|
||||
merge.properties.putAll(other.properties);
|
||||
|
||||
merge.node.mergeValuesFrom(this.node);
|
||||
merge.node.mergeValuesFrom(other.node);
|
||||
|
||||
return merge;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,8 @@
|
||||
@FunctionalInterface
|
||||
public interface PropertyCondition {
|
||||
|
||||
static final PropertyCondition MATCH_ALL = state -> true;
|
||||
static final PropertyCondition MATCH_NONE = state -> false;
|
||||
static final PropertyCondition MATCH_ALL = new All();
|
||||
static final PropertyCondition MATCH_NONE = new None();
|
||||
|
||||
boolean matches(BlockState state);
|
||||
|
||||
@ -95,6 +95,24 @@ public boolean matches(BlockState state) {
|
||||
|
||||
}
|
||||
|
||||
class All implements PropertyCondition {
|
||||
|
||||
@Override
|
||||
public boolean matches(BlockState state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class None implements PropertyCondition {
|
||||
|
||||
@Override
|
||||
public boolean matches(BlockState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static PropertyCondition all() {
|
||||
return MATCH_ALL;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@
|
||||
import de.bluecolored.bluemap.core.resourcepack.BlockStateResource.Builder;
|
||||
import de.bluecolored.bluemap.core.resourcepack.fileaccess.CombinedFileAccess;
|
||||
import de.bluecolored.bluemap.core.resourcepack.fileaccess.FileAccess;
|
||||
import de.bluecolored.bluemap.core.resourcepack.fileaccess.ResourcePackOldFormatFileAccess;
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
|
||||
/**
|
||||
@ -109,14 +110,15 @@ public void load(Collection<File> sources) throws IOException {
|
||||
* @param sources The list of {@link File} sources. Each can be a folder or any zip-compressed file. (E.g. .zip or .jar)
|
||||
*/
|
||||
public void load(File... sources) {
|
||||
try (CombinedFileAccess sourcesAccess = new CombinedFileAccess()){
|
||||
try (CombinedFileAccess combinedSourcesAccess = new CombinedFileAccess()){
|
||||
for (File file : sources) {
|
||||
try {
|
||||
sourcesAccess.addFileAccess(FileAccess.of(file));
|
||||
combinedSourcesAccess.addFileAccess(FileAccess.of(file));
|
||||
} catch (IOException e) {
|
||||
Logger.global.logError("Failed to read ResourcePack: " + file, e);
|
||||
}
|
||||
}
|
||||
FileAccess sourcesAccess = ResourcePackOldFormatFileAccess.from(combinedSourcesAccess);
|
||||
|
||||
textures.reloadAllTextures(sourcesAccess);
|
||||
|
||||
@ -183,6 +185,8 @@ public static void downloadDefaultResource(File file) throws IOException {
|
||||
protected static String namespacedToAbsoluteResourcePath(String namespacedPath, String resourceTypeFolder) {
|
||||
String path = namespacedPath;
|
||||
|
||||
resourceTypeFolder = FileAccess.normalize(resourceTypeFolder);
|
||||
|
||||
int namespaceIndex = path.indexOf(':');
|
||||
String namespace = "minecraft";
|
||||
if (namespaceIndex != -1) {
|
||||
@ -190,7 +194,11 @@ protected static String namespacedToAbsoluteResourcePath(String namespacedPath,
|
||||
path = path.substring(namespaceIndex + 1);
|
||||
}
|
||||
|
||||
path = "assets/" + namespace + "/" + resourceTypeFolder + "/" + FileAccess.normalize(path);
|
||||
if (resourceTypeFolder.isEmpty()) {
|
||||
path = "assets/" + namespace + "/" + FileAccess.normalize(path);
|
||||
} else {
|
||||
path = "assets/" + namespace + "/" + resourceTypeFolder + "/" + FileAccess.normalize(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
@ -57,7 +57,9 @@ static String getFileName(String path) {
|
||||
}
|
||||
|
||||
static String normalize(String path) {
|
||||
if (path.isEmpty()) return path;
|
||||
if (path.charAt(path.length() - 1) == '/') path = path.substring(0, path.length() - 1);
|
||||
if (path.isEmpty()) return path;
|
||||
if (path.charAt(0) == '/') path = path.substring(1);
|
||||
return path;
|
||||
}
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.resourcepack.fileaccess;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* This {@link FileAccess} tries to make 1.12/1.13/1.14 ResourcePacks compatible with each other
|
||||
*/
|
||||
public class ResourcePackOldFormatFileAccess implements FileAccess {
|
||||
|
||||
private FileAccess parent;
|
||||
|
||||
protected ResourcePackOldFormatFileAccess(FileAccess parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
parent.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream readFile(String path) throws FileNotFoundException, IOException {
|
||||
try {
|
||||
return parent.readFile(path);
|
||||
} catch (FileNotFoundException ex) {
|
||||
for (String altPath : otherPathsToTry(path)) {
|
||||
try {
|
||||
return parent.readFile(altPath);
|
||||
} catch (FileNotFoundException ex2) {
|
||||
ex.addSuppressed(ex2);
|
||||
} catch (IOException ex2) {
|
||||
ex.addSuppressed(ex2);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> listFiles(String path, boolean recursive) {
|
||||
return parent.listFiles(path, recursive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> listFolders(String path) {
|
||||
return parent.listFolders(path);
|
||||
}
|
||||
|
||||
private Collection<String> otherPathsToTry(String path){
|
||||
path = FileAccess.normalize(path);
|
||||
List<String> paths = new ArrayList<>();
|
||||
String[] parts = path.split(Pattern.quote("/"));
|
||||
|
||||
//handle block/blocks folder-differences
|
||||
if (parts.length >= 4 && parts[0].equals("assets") && parts[2].equals("models")) {
|
||||
if (parts[3].equals("block")) {
|
||||
parts[3] = "blocks";
|
||||
paths.add(String.join("/", parts));
|
||||
} else if (parts[3].equals("blocks")) {
|
||||
parts[3] = "block";
|
||||
paths.add(String.join("/", parts));
|
||||
} else {
|
||||
String[] newParts = new String[parts.length + 1];
|
||||
System.arraycopy(parts, 0, newParts, 0, 3);
|
||||
System.arraycopy(parts, 3, newParts, 4, parts.length - 3);
|
||||
|
||||
newParts[3] = "blocks";
|
||||
paths.add(String.join("/", newParts));
|
||||
|
||||
newParts[3] = "block";
|
||||
paths.add(String.join("/", newParts));
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
public static ResourcePackOldFormatFileAccess from(FileAccess source) {
|
||||
if (source instanceof ResourcePackOldFormatFileAccess) return (ResourcePackOldFormatFileAccess) source;
|
||||
return new ResourcePackOldFormatFileAccess(source);
|
||||
}
|
||||
|
||||
}
|
@ -131,6 +131,9 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
|
||||
if (loaded) return;
|
||||
unload(); //ensure nothing is left running (from a failed load or something)
|
||||
|
||||
//register reload command in case bluemap crashes during loading
|
||||
Sponge.getCommandManager().register(this, new Commands(this).createStandaloneReloadCommand(), "bluemap");
|
||||
|
||||
//load configs
|
||||
URL defaultSpongeConfig = SpongePlugin.class.getResource("/bluemap-sponge.conf");
|
||||
URL spongeConfigDefaults = SpongePlugin.class.getResource("/bluemap-sponge-defaults.conf");
|
||||
@ -151,7 +154,7 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
|
||||
if (!defaultResourceFile.exists()) {
|
||||
handleMissingResources(defaultResourceFile, configManager.getMainConfigFile());
|
||||
unload();
|
||||
|
||||
|
||||
Sponge.getCommandManager().register(this, new Commands(this).createStandaloneReloadCommand(), "bluemap");
|
||||
return;
|
||||
}
|
||||
@ -183,7 +186,7 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
|
||||
|
||||
File worldFolder = new File(mapConfig.getWorldPath());
|
||||
if (!worldFolder.exists() || !worldFolder.isDirectory()) {
|
||||
Logger.global.logError("Failed to load map '" + id + "': '" + worldFolder + "' does not exist or is no directory!", new IOException());
|
||||
Logger.global.logError("Failed to load map '" + id + "': '" + worldFolder.getCanonicalPath() + "' does not exist or is no directory!", new IOException());
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -276,6 +279,7 @@ public synchronized void load() throws ExecutionException, IOException, Interrup
|
||||
}
|
||||
|
||||
//init commands
|
||||
Sponge.getCommandManager().getOwnedBy(this).forEach(Sponge.getCommandManager()::removeMapping);
|
||||
Sponge.getCommandManager().register(this, new Commands(this).createRootCommand(), "bluemap");
|
||||
|
||||
//metrics
|
||||
@ -410,7 +414,7 @@ private void handleMissingResources(File resourceFile, File mainConfigFile) {
|
||||
} 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: " + mainConfigFile);
|
||||
try { Logger.global.logWarning("Please check: " + mainConfigFile.getCanonicalPath()); } catch (IOException ignored) {}
|
||||
Logger.global.logInfo("If you have changed the config you can simply reload the plugin using: /bluemap reload");
|
||||
}
|
||||
}
|
||||
|
@ -7,3 +7,4 @@ web {
|
||||
port: 8100
|
||||
maxConnectionCount: 100
|
||||
}
|
||||
renderThreadCount: -2
|
||||
|
@ -52,8 +52,10 @@ web {
|
||||
# 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
|
||||
# Zero or a negative value means the amount of of available processor-cores subtracted by the value.
|
||||
# (So a value of -2 with 6 cores results in 4 render-processes)
|
||||
# Default is -2
|
||||
renderThreadCount: -2
|
||||
|
||||
# This is an array with multiple configured maps.
|
||||
# You can define multiple maps, for different worlds with different render-settings here
|
||||
@ -108,8 +110,8 @@ maps: [
|
||||
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
|
||||
# Default is 4.5
|
||||
viewDistance: 4.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.
|
||||
@ -125,8 +127,8 @@ maps: [
|
||||
pointsPerLowresTile: 50
|
||||
|
||||
# The View-Distance for lowres tiles on the web-map (the value is the radius in tiles)
|
||||
# Default is 4
|
||||
viewDistance: 4
|
||||
# Default is 7
|
||||
viewDistance: 7
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user