Improve resource-loading and texture-file generation and add implementation specific configurations

This commit is contained in:
Blue (Lukas Rieger) 2019-11-23 14:22:39 +01:00
parent 2b3ef38672
commit fd155d6ce6
11 changed files with 103 additions and 50 deletions

View File

@ -92,6 +92,10 @@ private Path toFolder(String pathString) throws IOException {
if (!file.exists() && !file.mkdirs()) throw new IOException("Invalid configuration: Folders to path '" + file.getAbsolutePath() + "' could not be created");
return file.toPath();
}
public Path getDataPath() {
return dataPath;
}
public boolean isWebserverEnabled() {
return webserverEnabled;

View File

@ -49,6 +49,7 @@ public class ConfigurationFile {
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 Configuration config;

View File

@ -380,6 +380,8 @@ public static MCAWorld load(Path worldFolder, UUID uuid) throws IOException {
levelData.getInt("SpawnZ")
);
CHUNK_CACHE.invalidateAll();
return new MCAWorld(
worldFolder,
uuid,

View File

@ -47,10 +47,12 @@
import com.google.common.cache.CacheBuilder;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.util.FileUtil;
import de.bluecolored.bluemap.core.world.BlockState;
public class ResourcePack {
public static final String MINECRAFT_CLIENT_VERSION = "1.14.4";
public static final String MINECRAFT_CLIENT_URL = "https://launcher.mojang.com/v1/objects/8c325a0c5bd674dd747d6ebaa4c791fd363ad8a9/client.jar";
private Map<Path, Resource> resources;
@ -62,37 +64,31 @@ public class ResourcePack {
public ResourcePack(List<File> dataSources, File textureExportFile) throws IOException, NoSuchResourceException {
this.resources = new HashMap<>();
load(dataSources);
//load resources in order
for (File resource : dataSources) overrideResourcesWith(resource);
blockStateResourceCache = CacheBuilder.newBuilder()
.maximumSize(10000)
.build();
textureProvider = new TextureProvider();
if (textureExportFile.exists()){
textureProvider.load(textureExportFile);
} else {
textureProvider.generate(this);
textureProvider.save(textureExportFile);
}
textureProvider.generate(this); //if loaded add missing textures
textureProvider.save(textureExportFile);
blockColorProvider = new BlockColorProvider(this);
}
private void load(List<File> dataSources) throws IOException {
resources.clear();
//load resourcepacks in order
for (File resourcePath : dataSources) overrideResourcesWith(resourcePath);
}
private void overrideResourcesWith(File resourcePath){
if (resourcePath.isFile() && resourcePath.getName().endsWith(".zip") || resourcePath.getName().endsWith(".jar")){
overrideResourcesWithZipFile(resourcePath);
return;
private void overrideResourcesWith(File resource){
if (resource.isFile() && resource.getName().endsWith(".zip") || resource.getName().endsWith(".jar")){
overrideResourcesWithZipFile(resource);
} else {
overrideResourcesWith(resource, Paths.get(""));
}
overrideResourcesWith(resourcePath, Paths.get(""));
}
private void overrideResourcesWith(File resource, Path resourcePath){
@ -103,7 +99,7 @@ private void overrideResourcesWith(File resource, Path resourcePath){
return;
}
if (resource.isFile()){
if (resource.isFile() && isActualResourcePath(resourcePath)){
try {
byte[] bytes = Files.readAllBytes(resource.toPath());
resources.put(resourcePath, new Resource(bytes));
@ -124,15 +120,9 @@ private void overrideResourcesWithZipFile(File resourceFile){
if (file.isDirectory()) continue;
Path resourcePath = Paths.get("", file.getName().split("/"));
if (
!resourcePath.startsWith(Paths.get("assets", "minecraft", "blockstates")) &&
!resourcePath.startsWith(Paths.get("assets", "minecraft", "models", "block")) &&
!resourcePath.startsWith(Paths.get("assets", "minecraft", "textures", "block")) &&
!resourcePath.startsWith(Paths.get("assets", "minecraft", "textures", "colormap"))
) continue;
if (!isActualResourcePath(resourcePath)) continue;
InputStream fileInputStream = zipFile.getInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(Math.max(8, (int) file.getSize()));
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1){
@ -146,6 +136,17 @@ private void overrideResourcesWithZipFile(File resourceFile){
}
}
private boolean isActualResourcePath(Path path) {
String[] blockstatesPattern = {"assets", ".*", "blockstates", "*"};
String[] modelsPattern = {"assets", ".*", "models", "blocks?", "*"};
String[] texturesPattern = {"assets", ".*", "textures", "block|colormap", "*"};
return
FileUtil.matchPath(path, blockstatesPattern) ||
FileUtil.matchPath(path, modelsPattern) ||
FileUtil.matchPath(path, texturesPattern);
}
public BlockStateResource getBlockStateResource(BlockState block) throws NoSuchResourceException, InvalidResourceDeclarationException {
BlockStateResource bsr = blockStateResourceCache.getIfPresent(block);

View File

@ -30,7 +30,6 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.Map;
@ -44,6 +43,7 @@
import de.bluecolored.bluemap.core.resourcepack.ResourcePack.Resource;
import de.bluecolored.bluemap.core.util.ConfigUtil;
import de.bluecolored.bluemap.core.util.FileUtil;
import de.bluecolored.bluemap.core.util.MathUtil;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.gson.GsonConfigurationLoader;
@ -77,29 +77,34 @@ public Texture getTexture(int index){
}
public void generate(ResourcePack resources) throws IOException {
indexMap.clear();
textures.clear();
Path textureRoot = Paths.get("assets", "minecraft", "textures");
String[] texturesPathPattern = {"assets", ".*", "textures", "block", "*"};
for (Entry<Path, Resource> entry : resources.getAllResources().entrySet()){
if (entry.getKey().startsWith(textureRoot) && entry.getKey().toString().endsWith(".png")){
BufferedImage image = ImageIO.read(entry.getValue().getStream());
if (image == null) throw new IOException("Failed to read Image: " + entry.getKey());
String path = textureRoot.relativize(entry.getKey()).normalize().toString();
Path key = entry.getKey();
if (FileUtil.matchPath(key, texturesPathPattern) && key.toString().endsWith(".png")){
String path = key.subpath(3, key.getNameCount()).normalize().toString();
String id = path
.substring(0, path.length() - ".png".length())
.replace(File.separatorChar, '/');
BufferedImage image = ImageIO.read(entry.getValue().getStream());
if (image == null) throw new IOException("Failed to read Image: " + key);
Texture texture = new Texture(id, image);
textures.add(texture);
indexMap.put(id, textures.size() - 1);
//update if existing else add new
if (indexMap.containsKey(id)) {
int index = indexMap.get(id);
textures.set(index, texture);
} else {
textures.add(texture);
indexMap.put(id, textures.size() - 1);
}
}
}
}
public void load(File file) throws IOException {
indexMap.clear();
textures.clear();

View File

@ -29,6 +29,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import com.flowpowered.math.vector.Vector2i;
@ -73,4 +74,30 @@ public static void waitForFile(File file, long time, TimeUnit unit) throws Inter
}
}
/**
* The path-elements are being matched to the pattern-elements,
* each pattern-element can be a regex pattern to match against one path-element or "*" to represent any number of arbitrary elements (lazy: until the next pattern matches).
*/
public static boolean matchPath(Path path, String... pattern) {
int p = 0;
for (int i = 0; i < path.getNameCount(); i++) {
while (pattern[p].equals("*")) {
p++;
if (pattern.length >= p) return true;
}
if (Pattern.matches(pattern[p], path.getName(i).toString())) {
p++;
continue;
}
if (p > 0 && pattern[p-1].equals("*")) continue;
return false;
}
return true;
}
}

View File

@ -96,6 +96,7 @@ public String toString() {
.add("biome", getBiome())
.add("blocklight", getBlockLightLevel())
.add("sunlight", getSunLightLevel())
.add("state", getBlock())
.toString();
}

View File

@ -13,7 +13,7 @@ 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.jar)
# (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%
@ -28,9 +28,8 @@ metrics: true
data: "data"
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
# With this setting you can enable the integrated web-server.
enabled: false
# The webroot of the website that displays the map.
webroot: "web"

View File

@ -97,6 +97,7 @@ public CommandSpec createReloadCommand() {
.permission("bluemap.reload")
.executor((source, args) -> {
try {
source.sendMessage(Text.of(TextColors.GOLD, "Reloading BlueMap..."));
plugin.reload();
if (plugin.isLoaded()) {

View File

@ -31,8 +31,11 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@ -52,12 +55,11 @@
import org.spongepowered.api.scheduler.SpongeExecutorService;
import com.flowpowered.math.vector.Vector2i;
import com.google.common.collect.Lists;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.config.ConfigurationFile;
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.logger.Logger;
import de.bluecolored.bluemap.core.mca.MCAWorld;
import de.bluecolored.bluemap.core.metrics.Metrics;
@ -130,10 +132,10 @@ public synchronized void load() throws IOException, NoSuchResourceException {
//load configs
File configFile = getConfigPath().resolve("bluemap.conf").toFile();
config = ConfigurationFile.loadOrCreate(configFile).getConfig();
config = ConfigurationFile.loadOrCreate(configFile, SpongePlugin.class.getResource("/bluemap-sponge.conf")).getConfig();
//load resources
File defaultResourceFile = getConfigPath().resolve("resourcepacks").resolve("minecraft-client.jar").toFile();
File defaultResourceFile = config.getDataPath().resolve("minecraft-client-" + ResourcePack.MINECRAFT_CLIENT_VERSION + ".jar").toFile();
File textureExportFile = config.getWebDataPath().resolve("textures.json").toFile();
if (!defaultResourceFile.exists()) {
@ -146,7 +148,17 @@ public synchronized void load() throws IOException, NoSuchResourceException {
return;
}
resourcePack = new ResourcePack(Lists.newArrayList(defaultResourceFile), textureExportFile);
//find more resource packs
File resourcePackFolder = getConfigPath().resolve("resourcepacks").toFile();
resourcePackFolder.mkdirs();
File[] resourcePacks = resourcePackFolder.listFiles();
Arrays.sort(resourcePacks);
List<File> resources = new ArrayList<>(resourcePacks.length + 1);
resources.add(defaultResourceFile);
for (File file : resourcePacks) resources.add(file);
resourcePack = new ResourcePack(resources, textureExportFile);
//load maps
for (MapConfig mapConfig : config.getMapConfigs()) {

View File

@ -13,7 +13,7 @@ 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.jar)
# (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%
@ -23,7 +23,7 @@ accept-download: false
data: "bluemap"
web {
# With this setting you can disable the web-server.
# With this setting you can disable the integrated 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